c92deeb690468050bd2765cd186be9b329f56338
[reactos.git] / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 PDEVICE_NODE IopRootDeviceNode;
19 KSPIN_LOCK IopDeviceTreeLock;
20 ERESOURCE PpRegistryDeviceResource;
21 KGUARDED_MUTEX PpDeviceReferenceTableLock;
22 RTL_AVL_TABLE PpDeviceReferenceTable;
23
24 extern ULONG ExpInitializationPhase;
25 extern BOOLEAN ExpInTextModeSetup;
26 extern BOOLEAN PnpSystemInit;
27
28 /* DATA **********************************************************************/
29
30 PDRIVER_OBJECT IopRootDriverObject;
31 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
32
33 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
34 {
35 PDEVICE_OBJECT DeviceObject;
36 DEVICE_RELATION_TYPE Type;
37 PIO_WORKITEM WorkItem;
38 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
39
40 /* FUNCTIONS *****************************************************************/
41 NTSTATUS
42 NTAPI
43 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
44 IN ULONG CreateOptions,
45 OUT PHANDLE Handle);
46
47 VOID
48 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject);
49
50 NTSTATUS
51 IopPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject, BOOLEAN Force);
52
53 PDEVICE_NODE
54 FASTCALL
55 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
56 {
57 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
58 }
59
60 VOID
61 IopFixupDeviceId(PWCHAR String)
62 {
63 ULONG Length = wcslen(String), i;
64
65 for (i = 0; i < Length; i++)
66 {
67 if (String[i] == L'\\')
68 String[i] = L'#';
69 }
70 }
71
72 VOID
73 NTAPI
74 IopInstallCriticalDevice(PDEVICE_NODE DeviceNode)
75 {
76 NTSTATUS Status;
77 HANDLE CriticalDeviceKey, InstanceKey;
78 OBJECT_ATTRIBUTES ObjectAttributes;
79 UNICODE_STRING CriticalDeviceKeyU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CriticalDeviceDatabase");
80 UNICODE_STRING CompatibleIdU = RTL_CONSTANT_STRING(L"CompatibleIDs");
81 UNICODE_STRING HardwareIdU = RTL_CONSTANT_STRING(L"HardwareID");
82 UNICODE_STRING ServiceU = RTL_CONSTANT_STRING(L"Service");
83 UNICODE_STRING ClassGuidU = RTL_CONSTANT_STRING(L"ClassGUID");
84 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
85 ULONG HidLength = 0, CidLength = 0, BufferLength;
86 PWCHAR IdBuffer, OriginalIdBuffer;
87
88 /* Open the device instance key */
89 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
90 if (Status != STATUS_SUCCESS)
91 return;
92
93 Status = ZwQueryValueKey(InstanceKey,
94 &HardwareIdU,
95 KeyValuePartialInformation,
96 NULL,
97 0,
98 &HidLength);
99 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
100 {
101 ZwClose(InstanceKey);
102 return;
103 }
104
105 Status = ZwQueryValueKey(InstanceKey,
106 &CompatibleIdU,
107 KeyValuePartialInformation,
108 NULL,
109 0,
110 &CidLength);
111 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
112 {
113 CidLength = 0;
114 }
115
116 BufferLength = HidLength + CidLength;
117 BufferLength -= (((CidLength != 0) ? 2 : 1) * FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
118
119 /* Allocate a buffer to hold data from both */
120 OriginalIdBuffer = IdBuffer = ExAllocatePool(PagedPool, BufferLength);
121 if (!IdBuffer)
122 {
123 ZwClose(InstanceKey);
124 return;
125 }
126
127 /* Compute the buffer size */
128 if (HidLength > CidLength)
129 BufferLength = HidLength;
130 else
131 BufferLength = CidLength;
132
133 PartialInfo = ExAllocatePool(PagedPool, BufferLength);
134 if (!PartialInfo)
135 {
136 ZwClose(InstanceKey);
137 ExFreePool(OriginalIdBuffer);
138 return;
139 }
140
141 Status = ZwQueryValueKey(InstanceKey,
142 &HardwareIdU,
143 KeyValuePartialInformation,
144 PartialInfo,
145 HidLength,
146 &HidLength);
147 if (Status != STATUS_SUCCESS)
148 {
149 ExFreePool(PartialInfo);
150 ExFreePool(OriginalIdBuffer);
151 ZwClose(InstanceKey);
152 return;
153 }
154
155 /* Copy in HID info first (without 2nd terminating NULL if CID is present) */
156 HidLength = PartialInfo->DataLength - ((CidLength != 0) ? sizeof(WCHAR) : 0);
157 RtlCopyMemory(IdBuffer, PartialInfo->Data, HidLength);
158
159 if (CidLength != 0)
160 {
161 Status = ZwQueryValueKey(InstanceKey,
162 &CompatibleIdU,
163 KeyValuePartialInformation,
164 PartialInfo,
165 CidLength,
166 &CidLength);
167 if (Status != STATUS_SUCCESS)
168 {
169 ExFreePool(PartialInfo);
170 ExFreePool(OriginalIdBuffer);
171 ZwClose(InstanceKey);
172 return;
173 }
174
175 /* Copy CID next */
176 CidLength = PartialInfo->DataLength;
177 RtlCopyMemory(((PUCHAR)IdBuffer) + HidLength, PartialInfo->Data, CidLength);
178 }
179
180 /* Free our temp buffer */
181 ExFreePool(PartialInfo);
182
183 InitializeObjectAttributes(&ObjectAttributes,
184 &CriticalDeviceKeyU,
185 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
186 NULL,
187 NULL);
188 Status = ZwOpenKey(&CriticalDeviceKey,
189 KEY_ENUMERATE_SUB_KEYS,
190 &ObjectAttributes);
191 if (!NT_SUCCESS(Status))
192 {
193 /* The critical device database doesn't exist because
194 * we're probably in 1st stage setup, but it's ok */
195 ExFreePool(OriginalIdBuffer);
196 ZwClose(InstanceKey);
197 return;
198 }
199
200 while (*IdBuffer)
201 {
202 ULONG StringLength = (ULONG)wcslen(IdBuffer) + 1, Index;
203
204 IopFixupDeviceId(IdBuffer);
205
206 /* Look through all subkeys for a match */
207 for (Index = 0; TRUE; Index++)
208 {
209 ULONG NeededLength;
210 PKEY_BASIC_INFORMATION BasicInfo;
211
212 Status = ZwEnumerateKey(CriticalDeviceKey,
213 Index,
214 KeyBasicInformation,
215 NULL,
216 0,
217 &NeededLength);
218 if (Status == STATUS_NO_MORE_ENTRIES)
219 break;
220 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
221 {
222 UNICODE_STRING ChildIdNameU, RegKeyNameU;
223
224 BasicInfo = ExAllocatePool(PagedPool, NeededLength);
225 if (!BasicInfo)
226 {
227 /* No memory */
228 ExFreePool(OriginalIdBuffer);
229 ZwClose(CriticalDeviceKey);
230 ZwClose(InstanceKey);
231 return;
232 }
233
234 Status = ZwEnumerateKey(CriticalDeviceKey,
235 Index,
236 KeyBasicInformation,
237 BasicInfo,
238 NeededLength,
239 &NeededLength);
240 if (Status != STATUS_SUCCESS)
241 {
242 /* This shouldn't happen */
243 ExFreePool(BasicInfo);
244 continue;
245 }
246
247 ChildIdNameU.Buffer = IdBuffer;
248 ChildIdNameU.MaximumLength = ChildIdNameU.Length = (StringLength - 1) * sizeof(WCHAR);
249 RegKeyNameU.Buffer = BasicInfo->Name;
250 RegKeyNameU.MaximumLength = RegKeyNameU.Length = BasicInfo->NameLength;
251
252 if (RtlEqualUnicodeString(&ChildIdNameU, &RegKeyNameU, TRUE))
253 {
254 HANDLE ChildKeyHandle;
255
256 InitializeObjectAttributes(&ObjectAttributes,
257 &ChildIdNameU,
258 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
259 CriticalDeviceKey,
260 NULL);
261
262 Status = ZwOpenKey(&ChildKeyHandle,
263 KEY_QUERY_VALUE,
264 &ObjectAttributes);
265 if (Status != STATUS_SUCCESS)
266 {
267 ExFreePool(BasicInfo);
268 continue;
269 }
270
271 /* Check if there's already a driver installed */
272 Status = ZwQueryValueKey(InstanceKey,
273 &ClassGuidU,
274 KeyValuePartialInformation,
275 NULL,
276 0,
277 &NeededLength);
278 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
279 {
280 ExFreePool(BasicInfo);
281 continue;
282 }
283
284 Status = ZwQueryValueKey(ChildKeyHandle,
285 &ClassGuidU,
286 KeyValuePartialInformation,
287 NULL,
288 0,
289 &NeededLength);
290 if (Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL)
291 {
292 ExFreePool(BasicInfo);
293 continue;
294 }
295
296 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
297 if (!PartialInfo)
298 {
299 ExFreePool(OriginalIdBuffer);
300 ExFreePool(BasicInfo);
301 ZwClose(InstanceKey);
302 ZwClose(ChildKeyHandle);
303 ZwClose(CriticalDeviceKey);
304 return;
305 }
306
307 /* Read ClassGUID entry in the CDDB */
308 Status = ZwQueryValueKey(ChildKeyHandle,
309 &ClassGuidU,
310 KeyValuePartialInformation,
311 PartialInfo,
312 NeededLength,
313 &NeededLength);
314 if (Status != STATUS_SUCCESS)
315 {
316 ExFreePool(BasicInfo);
317 continue;
318 }
319
320 /* Write it to the ENUM key */
321 Status = ZwSetValueKey(InstanceKey,
322 &ClassGuidU,
323 0,
324 REG_SZ,
325 PartialInfo->Data,
326 PartialInfo->DataLength);
327 if (Status != STATUS_SUCCESS)
328 {
329 ExFreePool(BasicInfo);
330 ExFreePool(PartialInfo);
331 ZwClose(ChildKeyHandle);
332 continue;
333 }
334
335 Status = ZwQueryValueKey(ChildKeyHandle,
336 &ServiceU,
337 KeyValuePartialInformation,
338 NULL,
339 0,
340 &NeededLength);
341 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
342 {
343 ExFreePool(PartialInfo);
344 PartialInfo = ExAllocatePool(PagedPool, NeededLength);
345 if (!PartialInfo)
346 {
347 ExFreePool(OriginalIdBuffer);
348 ExFreePool(BasicInfo);
349 ZwClose(InstanceKey);
350 ZwClose(ChildKeyHandle);
351 ZwClose(CriticalDeviceKey);
352 return;
353 }
354
355 /* Read the service entry from the CDDB */
356 Status = ZwQueryValueKey(ChildKeyHandle,
357 &ServiceU,
358 KeyValuePartialInformation,
359 PartialInfo,
360 NeededLength,
361 &NeededLength);
362 if (Status != STATUS_SUCCESS)
363 {
364 ExFreePool(BasicInfo);
365 ExFreePool(PartialInfo);
366 ZwClose(ChildKeyHandle);
367 continue;
368 }
369
370 /* Write it to the ENUM key */
371 Status = ZwSetValueKey(InstanceKey,
372 &ServiceU,
373 0,
374 REG_SZ,
375 PartialInfo->Data,
376 PartialInfo->DataLength);
377 if (Status != STATUS_SUCCESS)
378 {
379 ExFreePool(BasicInfo);
380 ExFreePool(PartialInfo);
381 ZwClose(ChildKeyHandle);
382 continue;
383 }
384
385 DPRINT1("Installed service '%S' for critical device '%wZ'\n", PartialInfo->Data, &ChildIdNameU);
386 }
387 else
388 {
389 DPRINT1("Installed NULL service for critical device '%wZ'\n", &ChildIdNameU);
390 }
391
392 /* We need to enumerate children */
393 DeviceNode->Flags |= DNF_NEED_TO_ENUM;
394
395 ExFreePool(OriginalIdBuffer);
396 ExFreePool(PartialInfo);
397 ExFreePool(BasicInfo);
398 ZwClose(InstanceKey);
399 ZwClose(ChildKeyHandle);
400 ZwClose(CriticalDeviceKey);
401
402 /* That's it */
403 return;
404 }
405
406 ExFreePool(BasicInfo);
407 }
408 else
409 {
410 /* Umm, not sure what happened here */
411 continue;
412 }
413 }
414
415 /* Advance to the next ID */
416 IdBuffer += StringLength;
417 }
418
419 ExFreePool(OriginalIdBuffer);
420 ZwClose(InstanceKey);
421 ZwClose(CriticalDeviceKey);
422 }
423
424 NTSTATUS
425 FASTCALL
426 IopInitializeDevice(PDEVICE_NODE DeviceNode,
427 PDRIVER_OBJECT DriverObject)
428 {
429 PDEVICE_OBJECT Fdo;
430 NTSTATUS Status;
431
432 if (!DriverObject)
433 {
434 /* Special case for bus driven devices */
435 DeviceNode->Flags |= DNF_ADDED;
436 return STATUS_SUCCESS;
437 }
438
439 if (!DriverObject->DriverExtension->AddDevice)
440 {
441 DeviceNode->Flags |= DNF_LEGACY_DRIVER;
442 }
443
444 if (DeviceNode->Flags & DNF_LEGACY_DRIVER)
445 {
446 DeviceNode->Flags |= DNF_ADDED + DNF_STARTED;
447 return STATUS_SUCCESS;
448 }
449
450 /* This is a Plug and Play driver */
451 DPRINT("Plug and Play driver found\n");
452 ASSERT(DeviceNode->PhysicalDeviceObject);
453
454 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
455 &DriverObject->DriverName,
456 &DeviceNode->InstancePath);
457 Status = DriverObject->DriverExtension->AddDevice(
458 DriverObject, DeviceNode->PhysicalDeviceObject);
459 if (!NT_SUCCESS(Status))
460 {
461 DPRINT1("%wZ->AddDevice(%wZ) failed with status 0x%x\n",
462 &DriverObject->DriverName,
463 &DeviceNode->InstancePath,
464 Status);
465 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
466 return Status;
467 }
468
469 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
470
471 /* Check if we have a ACPI device (needed for power management) */
472 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
473 {
474 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
475
476 /* There can be only one system power device */
477 if (!SystemPowerDeviceNodeCreated)
478 {
479 PopSystemPowerDeviceNode = DeviceNode;
480 ObReferenceObject(PopSystemPowerDeviceNode->PhysicalDeviceObject);
481 SystemPowerDeviceNodeCreated = TRUE;
482 }
483 }
484
485 ObDereferenceObject(Fdo);
486
487 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
488
489 return STATUS_SUCCESS;
490 }
491
492 static
493 NTSTATUS
494 NTAPI
495 IopSendEject(IN PDEVICE_OBJECT DeviceObject)
496 {
497 IO_STACK_LOCATION Stack;
498 PVOID Dummy;
499
500 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
501 Stack.MajorFunction = IRP_MJ_PNP;
502 Stack.MinorFunction = IRP_MN_EJECT;
503
504 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
505 }
506
507 static
508 VOID
509 NTAPI
510 IopSendSurpriseRemoval(IN PDEVICE_OBJECT DeviceObject)
511 {
512 IO_STACK_LOCATION Stack;
513 PVOID Dummy;
514
515 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
516 Stack.MajorFunction = IRP_MJ_PNP;
517 Stack.MinorFunction = IRP_MN_SURPRISE_REMOVAL;
518
519 /* Drivers should never fail a IRP_MN_SURPRISE_REMOVAL request */
520 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
521 }
522
523 static
524 NTSTATUS
525 NTAPI
526 IopQueryRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
527 {
528 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
529 IO_STACK_LOCATION Stack;
530 PVOID Dummy;
531 NTSTATUS Status;
532
533 ASSERT(DeviceNode);
534
535 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVE_PENDING,
536 &DeviceNode->InstancePath);
537
538 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
539 Stack.MajorFunction = IRP_MJ_PNP;
540 Stack.MinorFunction = IRP_MN_QUERY_REMOVE_DEVICE;
541
542 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
543
544 IopNotifyPlugPlayNotification(DeviceObject,
545 EventCategoryTargetDeviceChange,
546 &GUID_TARGET_DEVICE_QUERY_REMOVE,
547 NULL,
548 NULL);
549
550 if (!NT_SUCCESS(Status))
551 {
552 DPRINT1("Removal vetoed by %wZ\n", &DeviceNode->InstancePath);
553 IopQueueTargetDeviceEvent(&GUID_DEVICE_REMOVAL_VETOED,
554 &DeviceNode->InstancePath);
555 }
556
557 return Status;
558 }
559
560 static
561 NTSTATUS
562 NTAPI
563 IopQueryStopDevice(IN PDEVICE_OBJECT DeviceObject)
564 {
565 IO_STACK_LOCATION Stack;
566 PVOID Dummy;
567
568 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
569 Stack.MajorFunction = IRP_MJ_PNP;
570 Stack.MinorFunction = IRP_MN_QUERY_STOP_DEVICE;
571
572 return IopSynchronousCall(DeviceObject, &Stack, &Dummy);
573 }
574
575 static
576 VOID
577 NTAPI
578 IopSendRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
579 {
580 IO_STACK_LOCATION Stack;
581 PVOID Dummy;
582
583 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
584 Stack.MajorFunction = IRP_MJ_PNP;
585 Stack.MinorFunction = IRP_MN_REMOVE_DEVICE;
586
587 /* Drivers should never fail a IRP_MN_REMOVE_DEVICE request */
588 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
589
590 IopNotifyPlugPlayNotification(DeviceObject,
591 EventCategoryTargetDeviceChange,
592 &GUID_TARGET_DEVICE_REMOVE_COMPLETE,
593 NULL,
594 NULL);
595 }
596
597 static
598 VOID
599 NTAPI
600 IopCancelRemoveDevice(IN PDEVICE_OBJECT DeviceObject)
601 {
602 IO_STACK_LOCATION Stack;
603 PVOID Dummy;
604
605 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
606 Stack.MajorFunction = IRP_MJ_PNP;
607 Stack.MinorFunction = IRP_MN_CANCEL_REMOVE_DEVICE;
608
609 /* Drivers should never fail a IRP_MN_CANCEL_REMOVE_DEVICE request */
610 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
611
612 IopNotifyPlugPlayNotification(DeviceObject,
613 EventCategoryTargetDeviceChange,
614 &GUID_TARGET_DEVICE_REMOVE_CANCELLED,
615 NULL,
616 NULL);
617 }
618
619 static
620 VOID
621 NTAPI
622 IopSendStopDevice(IN PDEVICE_OBJECT DeviceObject)
623 {
624 IO_STACK_LOCATION Stack;
625 PVOID Dummy;
626
627 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
628 Stack.MajorFunction = IRP_MJ_PNP;
629 Stack.MinorFunction = IRP_MN_STOP_DEVICE;
630
631 /* Drivers should never fail a IRP_MN_STOP_DEVICE request */
632 IopSynchronousCall(DeviceObject, &Stack, &Dummy);
633 }
634
635 VOID
636 NTAPI
637 IopStartDevice2(IN PDEVICE_OBJECT DeviceObject)
638 {
639 IO_STACK_LOCATION Stack;
640 PDEVICE_NODE DeviceNode;
641 NTSTATUS Status;
642 PVOID Dummy;
643 DEVICE_CAPABILITIES DeviceCapabilities;
644
645 /* Get the device node */
646 DeviceNode = IopGetDeviceNode(DeviceObject);
647
648 ASSERT(!(DeviceNode->Flags & DNF_DISABLED));
649
650 /* Build the I/O stack locaiton */
651 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
652 Stack.MajorFunction = IRP_MJ_PNP;
653 Stack.MinorFunction = IRP_MN_START_DEVICE;
654
655 Stack.Parameters.StartDevice.AllocatedResources =
656 DeviceNode->ResourceList;
657 Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
658 DeviceNode->ResourceListTranslated;
659
660 /* Do the call */
661 Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
662 if (!NT_SUCCESS(Status))
663 {
664 /* Send an IRP_MN_REMOVE_DEVICE request */
665 IopRemoveDevice(DeviceNode);
666
667 /* Set the appropriate flag */
668 DeviceNode->Flags |= DNF_START_FAILED;
669
670 DPRINT1("Warning: PnP Start failed (%wZ) [Status: 0x%x]\n", &DeviceNode->InstancePath, Status);
671 return;
672 }
673
674 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after start)\n");
675
676 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
677 if (!NT_SUCCESS(Status))
678 {
679 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
680 }
681
682 /* Invalidate device state so IRP_MN_QUERY_PNP_DEVICE_STATE is sent */
683 IoInvalidateDeviceState(DeviceObject);
684
685 /* Otherwise, mark us as started */
686 DeviceNode->Flags |= DNF_STARTED;
687 DeviceNode->Flags &= ~DNF_STOPPED;
688
689 /* We now need enumeration */
690 DeviceNode->Flags |= DNF_NEED_ENUMERATION_ONLY;
691 }
692
693 NTSTATUS
694 NTAPI
695 IopStartAndEnumerateDevice(IN PDEVICE_NODE DeviceNode)
696 {
697 PDEVICE_OBJECT DeviceObject;
698 NTSTATUS Status;
699 PAGED_CODE();
700
701 /* Sanity check */
702 ASSERT((DeviceNode->Flags & DNF_ADDED));
703 ASSERT((DeviceNode->Flags & (DNF_RESOURCE_ASSIGNED |
704 DNF_RESOURCE_REPORTED |
705 DNF_NO_RESOURCE_REQUIRED)));
706
707 /* Get the device object */
708 DeviceObject = DeviceNode->PhysicalDeviceObject;
709
710 /* Check if we're not started yet */
711 if (!(DeviceNode->Flags & DNF_STARTED))
712 {
713 /* Start us */
714 IopStartDevice2(DeviceObject);
715 }
716
717 /* Do we need to query IDs? This happens in the case of manual reporting */
718 #if 0
719 if (DeviceNode->Flags & DNF_NEED_QUERY_IDS)
720 {
721 DPRINT1("Warning: Device node has DNF_NEED_QUERY_IDS\n");
722 /* And that case shouldn't happen yet */
723 ASSERT(FALSE);
724 }
725 #endif
726
727 /* Make sure we're started, and check if we need enumeration */
728 if ((DeviceNode->Flags & DNF_STARTED) &&
729 (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY))
730 {
731 /* Enumerate us */
732 IoSynchronousInvalidateDeviceRelations(DeviceObject, BusRelations);
733 Status = STATUS_SUCCESS;
734 }
735 else
736 {
737 /* Nothing to do */
738 Status = STATUS_SUCCESS;
739 }
740
741 /* Return */
742 return Status;
743 }
744
745 NTSTATUS
746 IopStopDevice(
747 PDEVICE_NODE DeviceNode)
748 {
749 NTSTATUS Status;
750
751 DPRINT("Stopping device: %wZ\n", &DeviceNode->InstancePath);
752
753 Status = IopQueryStopDevice(DeviceNode->PhysicalDeviceObject);
754 if (NT_SUCCESS(Status))
755 {
756 IopSendStopDevice(DeviceNode->PhysicalDeviceObject);
757
758 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
759 DeviceNode->Flags |= DNF_STOPPED;
760
761 return STATUS_SUCCESS;
762 }
763
764 return Status;
765 }
766
767 NTSTATUS
768 IopStartDevice(
769 PDEVICE_NODE DeviceNode)
770 {
771 NTSTATUS Status;
772 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE;
773 UNICODE_STRING KeyName;
774 OBJECT_ATTRIBUTES ObjectAttributes;
775
776 if (DeviceNode->Flags & DNF_DISABLED)
777 return STATUS_SUCCESS;
778
779 Status = IopAssignDeviceResources(DeviceNode);
780 if (!NT_SUCCESS(Status))
781 goto ByeBye;
782
783 /* New PnP ABI */
784 IopStartAndEnumerateDevice(DeviceNode);
785
786 /* FIX: Should be done in new device instance code */
787 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle);
788 if (!NT_SUCCESS(Status))
789 goto ByeBye;
790
791 /* FIX: Should be done in IoXxxPrepareDriverLoading */
792 // {
793 RtlInitUnicodeString(&KeyName, L"Control");
794 InitializeObjectAttributes(&ObjectAttributes,
795 &KeyName,
796 OBJ_CASE_INSENSITIVE,
797 InstanceHandle,
798 NULL);
799 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
800 if (!NT_SUCCESS(Status))
801 goto ByeBye;
802
803 RtlInitUnicodeString(&KeyName, L"ActiveService");
804 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
805 // }
806
807 ByeBye:
808 if (ControlHandle != INVALID_HANDLE_VALUE)
809 ZwClose(ControlHandle);
810
811 if (InstanceHandle != INVALID_HANDLE_VALUE)
812 ZwClose(InstanceHandle);
813
814 return Status;
815 }
816
817 NTSTATUS
818 NTAPI
819 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
820 PDEVICE_CAPABILITIES DeviceCaps)
821 {
822 IO_STATUS_BLOCK StatusBlock;
823 IO_STACK_LOCATION Stack;
824 NTSTATUS Status;
825 HANDLE InstanceKey;
826 UNICODE_STRING ValueName;
827
828 /* Set up the Header */
829 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
830 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
831 DeviceCaps->Version = 1;
832 DeviceCaps->Address = -1;
833 DeviceCaps->UINumber = -1;
834
835 /* Set up the Stack */
836 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
837 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
838
839 /* Send the IRP */
840 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
841 &StatusBlock,
842 IRP_MN_QUERY_CAPABILITIES,
843 &Stack);
844 if (!NT_SUCCESS(Status))
845 {
846 DPRINT1("IRP_MN_QUERY_CAPABILITIES failed with status 0x%x\n", Status);
847 return Status;
848 }
849
850 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCaps->Version + sizeof(DeviceCaps->Version));
851
852 if (DeviceCaps->NoDisplayInUI)
853 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
854 else
855 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
856
857 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
858 if (NT_SUCCESS(Status))
859 {
860 /* Set 'Capabilities' value */
861 RtlInitUnicodeString(&ValueName, L"Capabilities");
862 Status = ZwSetValueKey(InstanceKey,
863 &ValueName,
864 0,
865 REG_DWORD,
866 (PVOID)&DeviceNode->CapabilityFlags,
867 sizeof(ULONG));
868
869 /* Set 'UINumber' value */
870 if (DeviceCaps->UINumber != MAXULONG)
871 {
872 RtlInitUnicodeString(&ValueName, L"UINumber");
873 Status = ZwSetValueKey(InstanceKey,
874 &ValueName,
875 0,
876 REG_DWORD,
877 &DeviceCaps->UINumber,
878 sizeof(ULONG));
879 }
880 }
881
882 return Status;
883 }
884
885 static VOID NTAPI
886 IopAsynchronousInvalidateDeviceRelations(
887 IN PDEVICE_OBJECT DeviceObject,
888 IN PVOID InvalidateContext)
889 {
890 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
891
892 IoSynchronousInvalidateDeviceRelations(
893 Data->DeviceObject,
894 Data->Type);
895
896 ObDereferenceObject(Data->DeviceObject);
897 IoFreeWorkItem(Data->WorkItem);
898 ExFreePool(Data);
899 }
900
901 NTSTATUS
902 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
903 {
904 KIRQL OldIrql;
905
906 if (PopSystemPowerDeviceNode)
907 {
908 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
909 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
910 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
911
912 return STATUS_SUCCESS;
913 }
914
915 return STATUS_UNSUCCESSFUL;
916 }
917
918 USHORT
919 NTAPI
920 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
921 {
922 USHORT i = 0, FoundIndex = 0xFFFF;
923 ULONG NewSize;
924 PVOID NewList;
925
926 /* Acquire the lock */
927 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
928
929 /* Loop all entries */
930 while (i < PnpBusTypeGuidList->GuidCount)
931 {
932 /* Try to find a match */
933 if (RtlCompareMemory(BusTypeGuid,
934 &PnpBusTypeGuidList->Guids[i],
935 sizeof(GUID)) == sizeof(GUID))
936 {
937 /* Found it */
938 FoundIndex = i;
939 goto Quickie;
940 }
941 i++;
942 }
943
944 /* Check if we have to grow the list */
945 if (PnpBusTypeGuidList->GuidCount)
946 {
947 /* Calculate the new size */
948 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
949 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
950
951 /* Allocate the new copy */
952 NewList = ExAllocatePool(PagedPool, NewSize);
953
954 if (!NewList) {
955 /* Fail */
956 ExFreePool(PnpBusTypeGuidList);
957 goto Quickie;
958 }
959
960 /* Now copy them, decrease the size too */
961 NewSize -= sizeof(GUID);
962 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
963
964 /* Free the old list */
965 ExFreePool(PnpBusTypeGuidList);
966
967 /* Use the new buffer */
968 PnpBusTypeGuidList = NewList;
969 }
970
971 /* Copy the new GUID */
972 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
973 BusTypeGuid,
974 sizeof(GUID));
975
976 /* The new entry is the index */
977 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
978 PnpBusTypeGuidList->GuidCount++;
979
980 Quickie:
981 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
982 return FoundIndex;
983 }
984
985 /*
986 * DESCRIPTION
987 * Creates a device node
988 *
989 * ARGUMENTS
990 * ParentNode = Pointer to parent device node
991 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
992 * to have the root device node create one
993 * (eg. for legacy drivers)
994 * DeviceNode = Pointer to storage for created device node
995 *
996 * RETURN VALUE
997 * Status
998 */
999 NTSTATUS
1000 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
1001 PDEVICE_OBJECT PhysicalDeviceObject,
1002 PUNICODE_STRING ServiceName,
1003 PDEVICE_NODE *DeviceNode)
1004 {
1005 PDEVICE_NODE Node;
1006 NTSTATUS Status;
1007 KIRQL OldIrql;
1008 UNICODE_STRING FullServiceName;
1009 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
1010 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
1011 UNICODE_STRING KeyName, ClassName;
1012 PUNICODE_STRING ServiceName1;
1013 ULONG LegacyValue;
1014 #if 0
1015 UNICODE_STRING ClassGUID;
1016 #endif
1017 HANDLE InstanceHandle;
1018
1019 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
1020 ParentNode, PhysicalDeviceObject, ServiceName);
1021
1022 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
1023 if (!Node)
1024 {
1025 return STATUS_INSUFFICIENT_RESOURCES;
1026 }
1027
1028 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
1029
1030 if (!ServiceName)
1031 ServiceName1 = &UnknownDeviceName;
1032 else
1033 ServiceName1 = ServiceName;
1034
1035 if (!PhysicalDeviceObject)
1036 {
1037 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
1038 FullServiceName.Length = 0;
1039 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
1040 if (!FullServiceName.Buffer)
1041 {
1042 ExFreePool(Node);
1043 return STATUS_INSUFFICIENT_RESOURCES;
1044 }
1045
1046 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
1047 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
1048
1049 Status = PnpRootCreateDevice(&FullServiceName, NULL, &PhysicalDeviceObject, &Node->InstancePath);
1050 if (!NT_SUCCESS(Status))
1051 {
1052 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
1053 ExFreePool(Node);
1054 return Status;
1055 }
1056
1057 /* Create the device key for legacy drivers */
1058 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
1059 if (!NT_SUCCESS(Status))
1060 {
1061 ZwClose(InstanceHandle);
1062 ExFreePool(Node);
1063 ExFreePool(FullServiceName.Buffer);
1064 return Status;
1065 }
1066
1067 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
1068 if (!Node->ServiceName.Buffer)
1069 {
1070 ZwClose(InstanceHandle);
1071 ExFreePool(Node);
1072 ExFreePool(FullServiceName.Buffer);
1073 return Status;
1074 }
1075
1076 Node->ServiceName.MaximumLength = ServiceName1->Length;
1077 Node->ServiceName.Length = 0;
1078
1079 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
1080
1081 if (ServiceName)
1082 {
1083 RtlInitUnicodeString(&KeyName, L"Service");
1084 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
1085 }
1086
1087 if (NT_SUCCESS(Status))
1088 {
1089 RtlInitUnicodeString(&KeyName, L"Legacy");
1090
1091 LegacyValue = 1;
1092 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
1093 if (NT_SUCCESS(Status))
1094 {
1095 RtlInitUnicodeString(&KeyName, L"Class");
1096
1097 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
1098 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
1099 #if 0
1100 if (NT_SUCCESS(Status))
1101 {
1102 RtlInitUnicodeString(&KeyName, L"ClassGUID");
1103
1104 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
1105 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
1106 }
1107 #endif
1108 }
1109 }
1110
1111 ZwClose(InstanceHandle);
1112 ExFreePool(FullServiceName.Buffer);
1113
1114 if (!NT_SUCCESS(Status))
1115 {
1116 ExFreePool(Node);
1117 return Status;
1118 }
1119
1120 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
1121 IopDeviceNodeSetFlag(Node, DNF_PROCESSED);
1122 IopDeviceNodeSetFlag(Node, DNF_ADDED);
1123 IopDeviceNodeSetFlag(Node, DNF_STARTED);
1124 }
1125
1126 Node->PhysicalDeviceObject = PhysicalDeviceObject;
1127
1128 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
1129
1130 if (ParentNode)
1131 {
1132 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1133 Node->Parent = ParentNode;
1134 Node->Sibling = ParentNode->Child;
1135 ParentNode->Child = Node;
1136 if (ParentNode->LastChild == NULL)
1137 ParentNode->LastChild = Node;
1138 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1139 Node->Level = ParentNode->Level + 1;
1140 }
1141
1142 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1143
1144 *DeviceNode = Node;
1145
1146 return STATUS_SUCCESS;
1147 }
1148
1149 NTSTATUS
1150 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
1151 {
1152 KIRQL OldIrql;
1153 PDEVICE_NODE PrevSibling = NULL;
1154
1155 /* All children must be deleted before a parent is deleted */
1156 ASSERT(!DeviceNode->Child);
1157
1158 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
1159
1160 ASSERT(DeviceNode->PhysicalDeviceObject);
1161
1162 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
1163
1164 /* Get previous sibling */
1165 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
1166 {
1167 PrevSibling = DeviceNode->Parent->Child;
1168 while (PrevSibling->Sibling != DeviceNode)
1169 PrevSibling = PrevSibling->Sibling;
1170 }
1171
1172 /* Unlink from parent if it exists */
1173 if (DeviceNode->Parent)
1174 {
1175 if (DeviceNode->Parent->LastChild == DeviceNode)
1176 {
1177 DeviceNode->Parent->LastChild = PrevSibling;
1178 if (PrevSibling)
1179 PrevSibling->Sibling = NULL;
1180 }
1181 if (DeviceNode->Parent->Child == DeviceNode)
1182 DeviceNode->Parent->Child = DeviceNode->Sibling;
1183 }
1184
1185 /* Unlink from sibling list */
1186 if (PrevSibling)
1187 PrevSibling->Sibling = DeviceNode->Sibling;
1188
1189 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
1190
1191 RtlFreeUnicodeString(&DeviceNode->InstancePath);
1192
1193 RtlFreeUnicodeString(&DeviceNode->ServiceName);
1194
1195 if (DeviceNode->ResourceList)
1196 {
1197 ExFreePool(DeviceNode->ResourceList);
1198 }
1199
1200 if (DeviceNode->ResourceListTranslated)
1201 {
1202 ExFreePool(DeviceNode->ResourceListTranslated);
1203 }
1204
1205 if (DeviceNode->ResourceRequirements)
1206 {
1207 ExFreePool(DeviceNode->ResourceRequirements);
1208 }
1209
1210 if (DeviceNode->BootResources)
1211 {
1212 ExFreePool(DeviceNode->BootResources);
1213 }
1214
1215 ExFreePool(DeviceNode);
1216
1217 return STATUS_SUCCESS;
1218 }
1219
1220 NTSTATUS
1221 NTAPI
1222 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
1223 IN PIO_STACK_LOCATION IoStackLocation,
1224 OUT PVOID *Information)
1225 {
1226 PIRP Irp;
1227 PIO_STACK_LOCATION IrpStack;
1228 IO_STATUS_BLOCK IoStatusBlock;
1229 KEVENT Event;
1230 NTSTATUS Status;
1231 PDEVICE_OBJECT TopDeviceObject;
1232 PAGED_CODE();
1233
1234 /* Call the top of the device stack */
1235 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
1236
1237 /* Allocate an IRP */
1238 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
1239 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
1240
1241 /* Initialize to failure */
1242 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
1243 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
1244
1245 /* Special case for IRP_MN_FILTER_RESOURCE_REQUIREMENTS */
1246 if (IoStackLocation->MinorFunction == IRP_MN_FILTER_RESOURCE_REQUIREMENTS)
1247 {
1248 /* Copy the resource requirements list into the IOSB */
1249 Irp->IoStatus.Information =
1250 IoStatusBlock.Information = (ULONG_PTR)IoStackLocation->Parameters.FilterResourceRequirements.IoResourceRequirementList;
1251 }
1252
1253 /* Initialize the event */
1254 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1255
1256 /* Set them up */
1257 Irp->UserIosb = &IoStatusBlock;
1258 Irp->UserEvent = &Event;
1259
1260 /* Queue the IRP */
1261 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1262 IoQueueThreadIrp(Irp);
1263
1264 /* Copy-in the stack */
1265 IrpStack = IoGetNextIrpStackLocation(Irp);
1266 *IrpStack = *IoStackLocation;
1267
1268 /* Call the driver */
1269 Status = IoCallDriver(TopDeviceObject, Irp);
1270 if (Status == STATUS_PENDING)
1271 {
1272 /* Wait for it */
1273 KeWaitForSingleObject(&Event,
1274 Executive,
1275 KernelMode,
1276 FALSE,
1277 NULL);
1278 Status = IoStatusBlock.Status;
1279 }
1280
1281 /* Return the information */
1282 *Information = (PVOID)IoStatusBlock.Information;
1283 return Status;
1284 }
1285
1286 NTSTATUS
1287 NTAPI
1288 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
1289 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
1290 IN UCHAR MinorFunction,
1291 IN PIO_STACK_LOCATION Stack OPTIONAL)
1292 {
1293 IO_STACK_LOCATION IoStackLocation;
1294
1295 /* Fill out the stack information */
1296 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
1297 IoStackLocation.MajorFunction = IRP_MJ_PNP;
1298 IoStackLocation.MinorFunction = MinorFunction;
1299 if (Stack)
1300 {
1301 /* Copy the rest */
1302 RtlCopyMemory(&IoStackLocation.Parameters,
1303 &Stack->Parameters,
1304 sizeof(Stack->Parameters));
1305 }
1306
1307 /* Do the PnP call */
1308 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
1309 &IoStackLocation,
1310 (PVOID)&IoStatusBlock->Information);
1311 return IoStatusBlock->Status;
1312 }
1313
1314 NTSTATUS
1315 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
1316 {
1317 PDEVICE_NODE ParentDeviceNode;
1318 PDEVICE_NODE ChildDeviceNode;
1319 NTSTATUS Status;
1320
1321 /* Copy context data so we don't overwrite it in subsequent calls to this function */
1322 ParentDeviceNode = Context->DeviceNode;
1323
1324 /* Call the action routine */
1325 Status = (Context->Action)(ParentDeviceNode, Context->Context);
1326 if (!NT_SUCCESS(Status))
1327 {
1328 return Status;
1329 }
1330
1331 /* Traversal of all children nodes */
1332 for (ChildDeviceNode = ParentDeviceNode->Child;
1333 ChildDeviceNode != NULL;
1334 ChildDeviceNode = ChildDeviceNode->Sibling)
1335 {
1336 /* Pass the current device node to the action routine */
1337 Context->DeviceNode = ChildDeviceNode;
1338
1339 Status = IopTraverseDeviceTreeNode(Context);
1340 if (!NT_SUCCESS(Status))
1341 {
1342 return Status;
1343 }
1344 }
1345
1346 return Status;
1347 }
1348
1349
1350 NTSTATUS
1351 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1352 {
1353 NTSTATUS Status;
1354
1355 DPRINT("Context 0x%p\n", Context);
1356
1357 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1358 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1359
1360 /* Start from the specified device node */
1361 Context->DeviceNode = Context->FirstDeviceNode;
1362
1363 /* Recursively traverse the device tree */
1364 Status = IopTraverseDeviceTreeNode(Context);
1365 if (Status == STATUS_UNSUCCESSFUL)
1366 {
1367 /* The action routine just wanted to terminate the traversal with status
1368 code STATUS_SUCCESS */
1369 Status = STATUS_SUCCESS;
1370 }
1371
1372 return Status;
1373 }
1374
1375
1376 /*
1377 * IopCreateDeviceKeyPath
1378 *
1379 * Creates a registry key
1380 *
1381 * Parameters
1382 * RegistryPath
1383 * Name of the key to be created.
1384 * Handle
1385 * Handle to the newly created key
1386 *
1387 * Remarks
1388 * This method can create nested trees, so parent of RegistryPath can
1389 * be not existant, and will be created if needed.
1390 */
1391 NTSTATUS
1392 NTAPI
1393 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
1394 IN ULONG CreateOptions,
1395 OUT PHANDLE Handle)
1396 {
1397 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
1398 HANDLE hParent = NULL, hKey;
1399 OBJECT_ATTRIBUTES ObjectAttributes;
1400 UNICODE_STRING KeyName;
1401 LPCWSTR Current, Last;
1402 USHORT Length;
1403 NTSTATUS Status;
1404
1405 /* Assume failure */
1406 *Handle = NULL;
1407
1408 /* Create a volatile device tree in 1st stage so we have a clean slate
1409 * for enumeration using the correct HAL (chosen in 1st stage setup) */
1410 if (ExpInTextModeSetup) CreateOptions |= REG_OPTION_VOLATILE;
1411
1412 /* Open root key for device instances */
1413 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
1414 if (!NT_SUCCESS(Status))
1415 {
1416 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
1417 return Status;
1418 }
1419
1420 Current = KeyName.Buffer = RegistryPath->Buffer;
1421 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
1422
1423 /* Go up to the end of the string */
1424 while (Current <= Last)
1425 {
1426 if (Current != Last && *Current != '\\')
1427 {
1428 /* Not the end of the string and not a separator */
1429 Current++;
1430 continue;
1431 }
1432
1433 /* Prepare relative key name */
1434 Length = (USHORT)((ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer);
1435 KeyName.MaximumLength = KeyName.Length = Length;
1436 DPRINT("Create '%wZ'\n", &KeyName);
1437
1438 /* Open key */
1439 InitializeObjectAttributes(&ObjectAttributes,
1440 &KeyName,
1441 OBJ_CASE_INSENSITIVE,
1442 hParent,
1443 NULL);
1444 Status = ZwCreateKey(&hKey,
1445 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
1446 &ObjectAttributes,
1447 0,
1448 NULL,
1449 CreateOptions,
1450 NULL);
1451
1452 /* Close parent key handle, we don't need it anymore */
1453 if (hParent)
1454 ZwClose(hParent);
1455
1456 /* Key opening/creating failed? */
1457 if (!NT_SUCCESS(Status))
1458 {
1459 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
1460 return Status;
1461 }
1462
1463 /* Check if it is the end of the string */
1464 if (Current == Last)
1465 {
1466 /* Yes, return success */
1467 *Handle = hKey;
1468 return STATUS_SUCCESS;
1469 }
1470
1471 /* Start with this new parent key */
1472 hParent = hKey;
1473 Current++;
1474 KeyName.Buffer = (LPWSTR)Current;
1475 }
1476
1477 return STATUS_UNSUCCESSFUL;
1478 }
1479
1480 NTSTATUS
1481 IopSetDeviceInstanceData(HANDLE InstanceKey,
1482 PDEVICE_NODE DeviceNode)
1483 {
1484 OBJECT_ATTRIBUTES ObjectAttributes;
1485 UNICODE_STRING KeyName;
1486 HANDLE LogConfKey;
1487 ULONG ResCount;
1488 ULONG ResultLength;
1489 NTSTATUS Status;
1490 HANDLE ControlHandle;
1491
1492 DPRINT("IopSetDeviceInstanceData() called\n");
1493
1494 /* Create the 'LogConf' key */
1495 RtlInitUnicodeString(&KeyName, L"LogConf");
1496 InitializeObjectAttributes(&ObjectAttributes,
1497 &KeyName,
1498 OBJ_CASE_INSENSITIVE,
1499 InstanceKey,
1500 NULL);
1501 Status = ZwCreateKey(&LogConfKey,
1502 KEY_ALL_ACCESS,
1503 &ObjectAttributes,
1504 0,
1505 NULL,
1506 REG_OPTION_VOLATILE,
1507 NULL);
1508 if (NT_SUCCESS(Status))
1509 {
1510 /* Set 'BootConfig' value */
1511 if (DeviceNode->BootResources != NULL)
1512 {
1513 ResCount = DeviceNode->BootResources->Count;
1514 if (ResCount != 0)
1515 {
1516 RtlInitUnicodeString(&KeyName, L"BootConfig");
1517 Status = ZwSetValueKey(LogConfKey,
1518 &KeyName,
1519 0,
1520 REG_RESOURCE_LIST,
1521 DeviceNode->BootResources,
1522 PnpDetermineResourceListSize(DeviceNode->BootResources));
1523 }
1524 }
1525
1526 /* Set 'BasicConfigVector' value */
1527 if (DeviceNode->ResourceRequirements != NULL &&
1528 DeviceNode->ResourceRequirements->ListSize != 0)
1529 {
1530 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1531 Status = ZwSetValueKey(LogConfKey,
1532 &KeyName,
1533 0,
1534 REG_RESOURCE_REQUIREMENTS_LIST,
1535 DeviceNode->ResourceRequirements,
1536 DeviceNode->ResourceRequirements->ListSize);
1537 }
1538
1539 ZwClose(LogConfKey);
1540 }
1541
1542 /* Set the 'ConfigFlags' value */
1543 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1544 Status = ZwQueryValueKey(InstanceKey,
1545 &KeyName,
1546 KeyValueBasicInformation,
1547 NULL,
1548 0,
1549 &ResultLength);
1550 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1551 {
1552 /* Write the default value */
1553 ULONG DefaultConfigFlags = 0;
1554 Status = ZwSetValueKey(InstanceKey,
1555 &KeyName,
1556 0,
1557 REG_DWORD,
1558 &DefaultConfigFlags,
1559 sizeof(DefaultConfigFlags));
1560 }
1561
1562 /* Create the 'Control' key */
1563 RtlInitUnicodeString(&KeyName, L"Control");
1564 InitializeObjectAttributes(&ObjectAttributes,
1565 &KeyName,
1566 OBJ_CASE_INSENSITIVE,
1567 InstanceKey,
1568 NULL);
1569 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1570
1571 if (NT_SUCCESS(Status))
1572 ZwClose(ControlHandle);
1573
1574 DPRINT("IopSetDeviceInstanceData() done\n");
1575
1576 return Status;
1577 }
1578
1579 /*
1580 * IopGetParentIdPrefix
1581 *
1582 * Retrieve (or create) a string which identifies a device.
1583 *
1584 * Parameters
1585 * DeviceNode
1586 * Pointer to device node.
1587 * ParentIdPrefix
1588 * Pointer to the string where is returned the parent node identifier
1589 *
1590 * Remarks
1591 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1592 * valid and its Buffer field is NULL-terminated. The caller needs to
1593 * to free the string with RtlFreeUnicodeString when it is no longer
1594 * needed.
1595 */
1596
1597 NTSTATUS
1598 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1599 PUNICODE_STRING ParentIdPrefix)
1600 {
1601 ULONG KeyNameBufferLength;
1602 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1603 UNICODE_STRING KeyName = {0, 0, NULL};
1604 UNICODE_STRING KeyValue;
1605 UNICODE_STRING ValueName;
1606 HANDLE hKey = NULL;
1607 ULONG crc32;
1608 NTSTATUS Status;
1609
1610 /* HACK: As long as some devices have a NULL device
1611 * instance path, the following test is required :(
1612 */
1613 if (DeviceNode->Parent->InstancePath.Length == 0)
1614 {
1615 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
1616 &DeviceNode->InstancePath);
1617 return STATUS_UNSUCCESSFUL;
1618 }
1619
1620 /* 1. Try to retrieve ParentIdPrefix from registry */
1621 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1622 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1623 if (!ParentIdPrefixInformation)
1624 {
1625 return STATUS_INSUFFICIENT_RESOURCES;
1626 }
1627
1628 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1629 if (!KeyName.Buffer)
1630 {
1631 Status = STATUS_INSUFFICIENT_RESOURCES;
1632 goto cleanup;
1633 }
1634 KeyName.Length = 0;
1635 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
1636
1637 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1638 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
1639
1640 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
1641 if (!NT_SUCCESS(Status))
1642 goto cleanup;
1643 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1644 Status = ZwQueryValueKey(
1645 hKey, &ValueName,
1646 KeyValuePartialInformation, ParentIdPrefixInformation,
1647 KeyNameBufferLength, &KeyNameBufferLength);
1648 if (NT_SUCCESS(Status))
1649 {
1650 if (ParentIdPrefixInformation->Type != REG_SZ)
1651 Status = STATUS_UNSUCCESSFUL;
1652 else
1653 {
1654 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1655 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1656 }
1657 goto cleanup;
1658 }
1659 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1660 {
1661 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1662 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1663 goto cleanup;
1664 }
1665
1666 /* 2. Create the ParentIdPrefix value */
1667 crc32 = RtlComputeCrc32(0,
1668 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1669 DeviceNode->Parent->InstancePath.Length);
1670
1671 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1672 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1673
1674 /* 3. Try to write the ParentIdPrefix to registry */
1675 Status = ZwSetValueKey(hKey,
1676 &ValueName,
1677 0,
1678 REG_SZ,
1679 (PVOID)KeyValue.Buffer,
1680 ((ULONG)wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1681
1682 cleanup:
1683 if (NT_SUCCESS(Status))
1684 {
1685 /* Duplicate the string to return it */
1686 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1687 }
1688 ExFreePool(ParentIdPrefixInformation);
1689 RtlFreeUnicodeString(&KeyName);
1690 if (hKey != NULL)
1691 ZwClose(hKey);
1692 return Status;
1693 }
1694
1695 NTSTATUS
1696 IopQueryHardwareIds(PDEVICE_NODE DeviceNode,
1697 HANDLE InstanceKey)
1698 {
1699 IO_STACK_LOCATION Stack;
1700 IO_STATUS_BLOCK IoStatusBlock;
1701 PWSTR Ptr;
1702 UNICODE_STRING ValueName;
1703 NTSTATUS Status;
1704 ULONG Length, TotalLength;
1705
1706 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1707
1708 RtlZeroMemory(&Stack, sizeof(Stack));
1709 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1710 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1711 &IoStatusBlock,
1712 IRP_MN_QUERY_ID,
1713 &Stack);
1714 if (NT_SUCCESS(Status))
1715 {
1716 /*
1717 * FIXME: Check for valid characters, if there is invalid characters
1718 * then bugcheck.
1719 */
1720 TotalLength = 0;
1721 Ptr = (PWSTR)IoStatusBlock.Information;
1722 DPRINT("Hardware IDs:\n");
1723 while (*Ptr)
1724 {
1725 DPRINT(" %S\n", Ptr);
1726 Length = (ULONG)wcslen(Ptr) + 1;
1727
1728 Ptr += Length;
1729 TotalLength += Length;
1730 }
1731 DPRINT("TotalLength: %hu\n", TotalLength);
1732 DPRINT("\n");
1733
1734 RtlInitUnicodeString(&ValueName, L"HardwareID");
1735 Status = ZwSetValueKey(InstanceKey,
1736 &ValueName,
1737 0,
1738 REG_MULTI_SZ,
1739 (PVOID)IoStatusBlock.Information,
1740 (TotalLength + 1) * sizeof(WCHAR));
1741 if (!NT_SUCCESS(Status))
1742 {
1743 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1744 }
1745 }
1746 else
1747 {
1748 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1749 }
1750
1751 return Status;
1752 }
1753
1754 NTSTATUS
1755 IopQueryCompatibleIds(PDEVICE_NODE DeviceNode,
1756 HANDLE InstanceKey)
1757 {
1758 IO_STACK_LOCATION Stack;
1759 IO_STATUS_BLOCK IoStatusBlock;
1760 PWSTR Ptr;
1761 UNICODE_STRING ValueName;
1762 NTSTATUS Status;
1763 ULONG Length, TotalLength;
1764
1765 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1766
1767 RtlZeroMemory(&Stack, sizeof(Stack));
1768 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1769 Status = IopInitiatePnpIrp(
1770 DeviceNode->PhysicalDeviceObject,
1771 &IoStatusBlock,
1772 IRP_MN_QUERY_ID,
1773 &Stack);
1774 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1775 {
1776 /*
1777 * FIXME: Check for valid characters, if there is invalid characters
1778 * then bugcheck.
1779 */
1780 TotalLength = 0;
1781 Ptr = (PWSTR)IoStatusBlock.Information;
1782 DPRINT("Compatible IDs:\n");
1783 while (*Ptr)
1784 {
1785 DPRINT(" %S\n", Ptr);
1786 Length = (ULONG)wcslen(Ptr) + 1;
1787
1788 Ptr += Length;
1789 TotalLength += Length;
1790 }
1791 DPRINT("TotalLength: %hu\n", TotalLength);
1792 DPRINT("\n");
1793
1794 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1795 Status = ZwSetValueKey(InstanceKey,
1796 &ValueName,
1797 0,
1798 REG_MULTI_SZ,
1799 (PVOID)IoStatusBlock.Information,
1800 (TotalLength + 1) * sizeof(WCHAR));
1801 if (!NT_SUCCESS(Status))
1802 {
1803 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1804 }
1805 }
1806 else
1807 {
1808 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1809 }
1810
1811 return Status;
1812 }
1813
1814
1815 /*
1816 * IopActionInterrogateDeviceStack
1817 *
1818 * Retrieve information for all (direct) child nodes of a parent node.
1819 *
1820 * Parameters
1821 * DeviceNode
1822 * Pointer to device node.
1823 * Context
1824 * Pointer to parent node to retrieve child node information for.
1825 *
1826 * Remarks
1827 * Any errors that occur are logged instead so that all child services have a chance
1828 * of being interrogated.
1829 */
1830
1831 NTSTATUS
1832 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1833 PVOID Context)
1834 {
1835 IO_STATUS_BLOCK IoStatusBlock;
1836 PDEVICE_NODE ParentDeviceNode;
1837 WCHAR InstancePath[MAX_PATH];
1838 IO_STACK_LOCATION Stack;
1839 NTSTATUS Status;
1840 ULONG RequiredLength;
1841 LCID LocaleId;
1842 HANDLE InstanceKey = NULL;
1843 UNICODE_STRING ValueName;
1844 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
1845 DEVICE_CAPABILITIES DeviceCapabilities;
1846
1847 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1848 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1849
1850 ParentDeviceNode = (PDEVICE_NODE)Context;
1851
1852 /*
1853 * We are called for the parent too, but we don't need to do special
1854 * handling for this node
1855 */
1856
1857 if (DeviceNode == ParentDeviceNode)
1858 {
1859 DPRINT("Success\n");
1860 return STATUS_SUCCESS;
1861 }
1862
1863 /*
1864 * Make sure this device node is a direct child of the parent device node
1865 * that is given as an argument
1866 */
1867
1868 if (DeviceNode->Parent != ParentDeviceNode)
1869 {
1870 DPRINT("Skipping 2+ level child\n");
1871 return STATUS_SUCCESS;
1872 }
1873
1874 /* Skip processing if it was already completed before */
1875 if (DeviceNode->Flags & DNF_PROCESSED)
1876 {
1877 /* Nothing to do */
1878 return STATUS_SUCCESS;
1879 }
1880
1881 /* Get Locale ID */
1882 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1883 if (!NT_SUCCESS(Status))
1884 {
1885 DPRINT1("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1886 return Status;
1887 }
1888
1889 /*
1890 * FIXME: For critical errors, cleanup and disable device, but always
1891 * return STATUS_SUCCESS.
1892 */
1893
1894 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1895
1896 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1897 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1898 &IoStatusBlock,
1899 IRP_MN_QUERY_ID,
1900 &Stack);
1901 if (NT_SUCCESS(Status))
1902 {
1903 /* Copy the device id string */
1904 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1905
1906 /*
1907 * FIXME: Check for valid characters, if there is invalid characters
1908 * then bugcheck.
1909 */
1910 }
1911 else
1912 {
1913 DPRINT1("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1914
1915 /* We have to return success otherwise we abort the traverse operation */
1916 return STATUS_SUCCESS;
1917 }
1918
1919 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack (after enumeration)\n");
1920
1921 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1922 if (!NT_SUCCESS(Status))
1923 {
1924 DPRINT1("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1925
1926 /* We have to return success otherwise we abort the traverse operation */
1927 return STATUS_SUCCESS;
1928 }
1929
1930 /* This bit is only check after enumeration */
1931 if (DeviceCapabilities.HardwareDisabled)
1932 {
1933 /* FIXME: Cleanup device */
1934 DeviceNode->Flags |= DNF_DISABLED;
1935 return STATUS_SUCCESS;
1936 }
1937 else
1938 DeviceNode->Flags &= ~DNF_DISABLED;
1939
1940 if (!DeviceCapabilities.UniqueID)
1941 {
1942 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1943 DPRINT("Instance ID is not unique\n");
1944 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1945 if (!NT_SUCCESS(Status))
1946 {
1947 DPRINT1("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1948
1949 /* We have to return success otherwise we abort the traverse operation */
1950 return STATUS_SUCCESS;
1951 }
1952 }
1953
1954 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1955
1956 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1957 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1958 &IoStatusBlock,
1959 IRP_MN_QUERY_ID,
1960 &Stack);
1961 if (NT_SUCCESS(Status))
1962 {
1963 /* Append the instance id string */
1964 wcscat(InstancePath, L"\\");
1965 if (ParentIdPrefix.Length > 0)
1966 {
1967 /* Add information from parent bus device to InstancePath */
1968 wcscat(InstancePath, ParentIdPrefix.Buffer);
1969 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1970 wcscat(InstancePath, L"&");
1971 }
1972 if (IoStatusBlock.Information)
1973 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1974
1975 /*
1976 * FIXME: Check for valid characters, if there is invalid characters
1977 * then bugcheck
1978 */
1979 }
1980 else
1981 {
1982 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1983 }
1984 RtlFreeUnicodeString(&ParentIdPrefix);
1985
1986 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1987 {
1988 DPRINT("No resources\n");
1989 /* FIXME: Cleanup and disable device */
1990 }
1991
1992 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1993
1994 /*
1995 * Create registry key for the instance id, if it doesn't exist yet
1996 */
1997 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
1998 if (!NT_SUCCESS(Status))
1999 {
2000 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2001
2002 /* We have to return success otherwise we abort the traverse operation */
2003 return STATUS_SUCCESS;
2004 }
2005
2006 IopQueryHardwareIds(DeviceNode, InstanceKey);
2007
2008 IopQueryCompatibleIds(DeviceNode, InstanceKey);
2009
2010 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2011
2012 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2013 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2014 Status = IopInitiatePnpIrp(
2015 DeviceNode->PhysicalDeviceObject,
2016 &IoStatusBlock,
2017 IRP_MN_QUERY_DEVICE_TEXT,
2018 &Stack);
2019 /* This key is mandatory, so even if the Irp fails, we still write it */
2020 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2021 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2022 {
2023 if (NT_SUCCESS(Status) &&
2024 IoStatusBlock.Information &&
2025 (*(PWSTR)IoStatusBlock.Information != 0))
2026 {
2027 /* This key is overriden when a driver is installed. Don't write the
2028 * new description if another one already exists */
2029 Status = ZwSetValueKey(InstanceKey,
2030 &ValueName,
2031 0,
2032 REG_SZ,
2033 (PVOID)IoStatusBlock.Information,
2034 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2035 }
2036 else
2037 {
2038 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2039 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2040
2041 Status = ZwSetValueKey(InstanceKey,
2042 &ValueName,
2043 0,
2044 REG_SZ,
2045 DeviceDesc.Buffer,
2046 DeviceDesc.MaximumLength);
2047
2048 if (!NT_SUCCESS(Status))
2049 {
2050 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2051 }
2052
2053 }
2054 }
2055
2056 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2057
2058 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2059 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2060 Status = IopInitiatePnpIrp(
2061 DeviceNode->PhysicalDeviceObject,
2062 &IoStatusBlock,
2063 IRP_MN_QUERY_DEVICE_TEXT,
2064 &Stack);
2065 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2066 {
2067 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2068 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2069 Status = ZwSetValueKey(InstanceKey,
2070 &ValueName,
2071 0,
2072 REG_SZ,
2073 (PVOID)IoStatusBlock.Information,
2074 ((ULONG)wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2075 if (!NT_SUCCESS(Status))
2076 {
2077 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2078 }
2079 }
2080 else
2081 {
2082 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2083 }
2084
2085 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2086
2087 Status = IopInitiatePnpIrp(
2088 DeviceNode->PhysicalDeviceObject,
2089 &IoStatusBlock,
2090 IRP_MN_QUERY_BUS_INFORMATION,
2091 NULL);
2092 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2093 {
2094 PPNP_BUS_INFORMATION BusInformation =
2095 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2096
2097 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2098 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2099 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2100 ExFreePool(BusInformation);
2101 }
2102 else
2103 {
2104 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2105
2106 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2107 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2108 DeviceNode->ChildBusTypeIndex = -1;
2109 }
2110
2111 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2112
2113 Status = IopInitiatePnpIrp(
2114 DeviceNode->PhysicalDeviceObject,
2115 &IoStatusBlock,
2116 IRP_MN_QUERY_RESOURCES,
2117 NULL);
2118 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2119 {
2120 DeviceNode->BootResources =
2121 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2122 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2123 }
2124 else
2125 {
2126 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2127 DeviceNode->BootResources = NULL;
2128 }
2129
2130 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2131
2132 Status = IopInitiatePnpIrp(
2133 DeviceNode->PhysicalDeviceObject,
2134 &IoStatusBlock,
2135 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2136 NULL);
2137 if (NT_SUCCESS(Status))
2138 {
2139 DeviceNode->ResourceRequirements =
2140 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2141 }
2142 else
2143 {
2144 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2145 DeviceNode->ResourceRequirements = NULL;
2146 }
2147
2148 if (InstanceKey != NULL)
2149 {
2150 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2151 }
2152
2153 ZwClose(InstanceKey);
2154
2155 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2156
2157 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2158 {
2159 /* Report the device to the user-mode pnp manager */
2160 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2161 &DeviceNode->InstancePath);
2162 }
2163
2164 return STATUS_SUCCESS;
2165 }
2166
2167 static
2168 VOID
2169 IopHandleDeviceRemoval(
2170 IN PDEVICE_NODE DeviceNode,
2171 IN PDEVICE_RELATIONS DeviceRelations)
2172 {
2173 PDEVICE_NODE Child = DeviceNode->Child, NextChild;
2174 ULONG i;
2175 BOOLEAN Found;
2176
2177 while (Child != NULL)
2178 {
2179 NextChild = Child->Sibling;
2180 Found = FALSE;
2181
2182 for (i = 0; DeviceRelations && i < DeviceRelations->Count; i++)
2183 {
2184 if (IopGetDeviceNode(DeviceRelations->Objects[i]) == Child)
2185 {
2186 Found = TRUE;
2187 break;
2188 }
2189 }
2190
2191 if (!Found && !(Child->Flags & DNF_WILL_BE_REMOVED))
2192 {
2193 /* Send removal IRPs to all of its children */
2194 IopPrepareDeviceForRemoval(Child->PhysicalDeviceObject, TRUE);
2195
2196 /* Send the surprise removal IRP */
2197 IopSendSurpriseRemoval(Child->PhysicalDeviceObject);
2198
2199 /* Tell the user-mode PnP manager that a device was removed */
2200 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
2201 &Child->InstancePath);
2202
2203 /* Send the remove device IRP */
2204 IopSendRemoveDevice(Child->PhysicalDeviceObject);
2205 }
2206
2207 Child = NextChild;
2208 }
2209 }
2210
2211 NTSTATUS
2212 IopEnumerateDevice(
2213 IN PDEVICE_OBJECT DeviceObject)
2214 {
2215 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2216 DEVICETREE_TRAVERSE_CONTEXT Context;
2217 PDEVICE_RELATIONS DeviceRelations;
2218 PDEVICE_OBJECT ChildDeviceObject;
2219 IO_STATUS_BLOCK IoStatusBlock;
2220 PDEVICE_NODE ChildDeviceNode;
2221 IO_STACK_LOCATION Stack;
2222 NTSTATUS Status;
2223 ULONG i;
2224
2225 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2226
2227 if (DeviceNode->Flags & DNF_NEED_ENUMERATION_ONLY)
2228 {
2229 DeviceNode->Flags &= ~DNF_NEED_ENUMERATION_ONLY;
2230
2231 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2232 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2233 &DeviceNode->InstancePath);
2234 }
2235
2236 DeviceNode->Flags &= ~DNF_NEED_TO_ENUM;
2237
2238 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2239
2240 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2241
2242 Status = IopInitiatePnpIrp(
2243 DeviceObject,
2244 &IoStatusBlock,
2245 IRP_MN_QUERY_DEVICE_RELATIONS,
2246 &Stack);
2247 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2248 {
2249 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2250 return Status;
2251 }
2252
2253 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2254
2255 /*
2256 * Send removal IRPs for devices that have disappeared
2257 * NOTE: This code handles the case where no relations are specified
2258 */
2259 IopHandleDeviceRemoval(DeviceNode, DeviceRelations);
2260
2261 /* Now we bail if nothing was returned */
2262 if (!DeviceRelations)
2263 {
2264 /* We're all done */
2265 DPRINT("No PDOs\n");
2266 return STATUS_SUCCESS;
2267 }
2268
2269 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2270
2271 /*
2272 * Create device nodes for all discovered devices
2273 */
2274 for (i = 0; i < DeviceRelations->Count; i++)
2275 {
2276 ChildDeviceObject = DeviceRelations->Objects[i];
2277 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2278
2279 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2280 if (!ChildDeviceNode)
2281 {
2282 /* One doesn't exist, create it */
2283 Status = IopCreateDeviceNode(
2284 DeviceNode,
2285 ChildDeviceObject,
2286 NULL,
2287 &ChildDeviceNode);
2288 if (NT_SUCCESS(Status))
2289 {
2290 /* Mark the node as enumerated */
2291 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2292
2293 /* Mark the DO as bus enumerated */
2294 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2295 }
2296 else
2297 {
2298 /* Ignore this DO */
2299 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2300 ObDereferenceObject(ChildDeviceObject);
2301 }
2302 }
2303 else
2304 {
2305 /* Mark it as enumerated */
2306 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2307 ObDereferenceObject(ChildDeviceObject);
2308 }
2309 }
2310 ExFreePool(DeviceRelations);
2311
2312 /*
2313 * Retrieve information about all discovered children from the bus driver
2314 */
2315 IopInitDeviceTreeTraverseContext(
2316 &Context,
2317 DeviceNode,
2318 IopActionInterrogateDeviceStack,
2319 DeviceNode);
2320
2321 Status = IopTraverseDeviceTree(&Context);
2322 if (!NT_SUCCESS(Status))
2323 {
2324 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2325 return Status;
2326 }
2327
2328 /*
2329 * Retrieve configuration from the registry for discovered children
2330 */
2331 IopInitDeviceTreeTraverseContext(
2332 &Context,
2333 DeviceNode,
2334 IopActionConfigureChildServices,
2335 DeviceNode);
2336
2337 Status = IopTraverseDeviceTree(&Context);
2338 if (!NT_SUCCESS(Status))
2339 {
2340 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2341 return Status;
2342 }
2343
2344 /*
2345 * Initialize services for discovered children.
2346 */
2347 Status = IopInitializePnpServices(DeviceNode);
2348 if (!NT_SUCCESS(Status))
2349 {
2350 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2351 return Status;
2352 }
2353
2354 DPRINT("IopEnumerateDevice() finished\n");
2355 return STATUS_SUCCESS;
2356 }
2357
2358
2359 /*
2360 * IopActionConfigureChildServices
2361 *
2362 * Retrieve configuration for all (direct) child nodes of a parent node.
2363 *
2364 * Parameters
2365 * DeviceNode
2366 * Pointer to device node.
2367 * Context
2368 * Pointer to parent node to retrieve child node configuration for.
2369 *
2370 * Remarks
2371 * Any errors that occur are logged instead so that all child services have a chance of beeing
2372 * configured.
2373 */
2374
2375 NTSTATUS
2376 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2377 PVOID Context)
2378 {
2379 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2380 PDEVICE_NODE ParentDeviceNode;
2381 PUNICODE_STRING Service;
2382 UNICODE_STRING ClassGUID;
2383 NTSTATUS Status;
2384 DEVICE_CAPABILITIES DeviceCaps;
2385
2386 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2387
2388 ParentDeviceNode = (PDEVICE_NODE)Context;
2389
2390 /*
2391 * We are called for the parent too, but we don't need to do special
2392 * handling for this node
2393 */
2394 if (DeviceNode == ParentDeviceNode)
2395 {
2396 DPRINT("Success\n");
2397 return STATUS_SUCCESS;
2398 }
2399
2400 /*
2401 * Make sure this device node is a direct child of the parent device node
2402 * that is given as an argument
2403 */
2404
2405 if (DeviceNode->Parent != ParentDeviceNode)
2406 {
2407 DPRINT("Skipping 2+ level child\n");
2408 return STATUS_SUCCESS;
2409 }
2410
2411 if (!(DeviceNode->Flags & DNF_PROCESSED))
2412 {
2413 DPRINT1("Child not ready to be configured\n");
2414 return STATUS_SUCCESS;
2415 }
2416
2417 if (!(DeviceNode->Flags & (DNF_DISABLED | DNF_STARTED | DNF_ADDED)))
2418 {
2419 WCHAR RegKeyBuffer[MAX_PATH];
2420 UNICODE_STRING RegKey;
2421
2422 /* Install the service for this if it's in the CDDB */
2423 //IopInstallCriticalDevice(DeviceNode);
2424
2425 RegKey.Length = 0;
2426 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2427 RegKey.Buffer = RegKeyBuffer;
2428
2429 /*
2430 * Retrieve configuration from Enum key
2431 */
2432
2433 Service = &DeviceNode->ServiceName;
2434
2435 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2436 RtlInitUnicodeString(Service, NULL);
2437 RtlInitUnicodeString(&ClassGUID, NULL);
2438
2439 QueryTable[0].Name = L"Service";
2440 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2441 QueryTable[0].EntryContext = Service;
2442
2443 QueryTable[1].Name = L"ClassGUID";
2444 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2445 QueryTable[1].EntryContext = &ClassGUID;
2446 QueryTable[1].DefaultType = REG_SZ;
2447 QueryTable[1].DefaultData = L"";
2448 QueryTable[1].DefaultLength = 0;
2449
2450 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2451 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2452
2453 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2454 RegKey.Buffer, QueryTable, NULL, NULL);
2455
2456 if (!NT_SUCCESS(Status))
2457 {
2458 /* FIXME: Log the error */
2459 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2460 &DeviceNode->InstancePath, Status);
2461 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2462 return STATUS_SUCCESS;
2463 }
2464
2465 if (Service->Buffer == NULL)
2466 {
2467 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2468 DeviceCaps.RawDeviceOK)
2469 {
2470 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2471
2472 DeviceNode->ServiceName.Length = 0;
2473 DeviceNode->ServiceName.MaximumLength = 0;
2474 DeviceNode->ServiceName.Buffer = NULL;
2475 }
2476 else if (ClassGUID.Length != 0)
2477 {
2478 /* Device has a ClassGUID value, but no Service value.
2479 * Suppose it is using the NULL driver, so state the
2480 * device is started */
2481 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2482 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2483 }
2484 else
2485 {
2486 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2487 }
2488 return STATUS_SUCCESS;
2489 }
2490
2491 DPRINT("Got Service %S\n", Service->Buffer);
2492 }
2493
2494 return STATUS_SUCCESS;
2495 }
2496
2497 /*
2498 * IopActionInitChildServices
2499 *
2500 * Initialize the service for all (direct) child nodes of a parent node
2501 *
2502 * Parameters
2503 * DeviceNode
2504 * Pointer to device node.
2505 * Context
2506 * Pointer to parent node to initialize child node services for.
2507 *
2508 * Remarks
2509 * If the driver image for a service is not loaded and initialized
2510 * it is done here too. Any errors that occur are logged instead so
2511 * that all child services have a chance of being initialized.
2512 */
2513
2514 NTSTATUS
2515 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2516 PVOID Context)
2517 {
2518 PDEVICE_NODE ParentDeviceNode;
2519 NTSTATUS Status;
2520 BOOLEAN BootDrivers = !PnpSystemInit;
2521
2522 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2523
2524 ParentDeviceNode = (PDEVICE_NODE)Context;
2525
2526 /*
2527 * We are called for the parent too, but we don't need to do special
2528 * handling for this node
2529 */
2530 if (DeviceNode == ParentDeviceNode)
2531 {
2532 DPRINT("Success\n");
2533 return STATUS_SUCCESS;
2534 }
2535
2536 /*
2537 * Make sure this device node is a direct child of the parent device node
2538 * that is given as an argument
2539 */
2540
2541 if (DeviceNode->Parent != ParentDeviceNode)
2542 {
2543 DPRINT("Skipping 2+ level child\n");
2544 return STATUS_SUCCESS;
2545 }
2546
2547 if (!(DeviceNode->Flags & DNF_PROCESSED))
2548 {
2549 DPRINT1("Child not ready to be added\n");
2550 return STATUS_SUCCESS;
2551 }
2552
2553 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2554 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2555 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2556 {
2557 if (DeviceNode->Flags & DNF_NEED_TO_ENUM)
2558 {
2559 Status = IopInitializeDevice(DeviceNode, NULL);
2560 if (NT_SUCCESS(Status))
2561 {
2562 /* HACK */
2563 DeviceNode->Flags &= ~DNF_STARTED;
2564 Status = IopStartDevice(DeviceNode);
2565 if (!NT_SUCCESS(Status))
2566 {
2567 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2568 &DeviceNode->InstancePath, Status);
2569 }
2570 }
2571 DeviceNode->Flags &= ~DNF_NEED_TO_ENUM;
2572 }
2573 return STATUS_SUCCESS;
2574 }
2575
2576 if (DeviceNode->ServiceName.Buffer == NULL)
2577 {
2578 /* We don't need to worry about loading the driver because we're
2579 * being driven in raw mode so our parent must be loaded to get here */
2580 Status = IopInitializeDevice(DeviceNode, NULL);
2581 if (NT_SUCCESS(Status))
2582 {
2583 Status = IopStartDevice(DeviceNode);
2584 if (!NT_SUCCESS(Status))
2585 {
2586 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2587 &DeviceNode->InstancePath, Status);
2588 }
2589 }
2590 }
2591 else
2592 {
2593 PLDR_DATA_TABLE_ENTRY ModuleObject;
2594 PDRIVER_OBJECT DriverObject;
2595
2596 /* Get existing DriverObject pointer (in case the driver has
2597 already been loaded and initialized) */
2598 Status = IopGetDriverObject(
2599 &DriverObject,
2600 &DeviceNode->ServiceName,
2601 FALSE);
2602
2603 if (!NT_SUCCESS(Status))
2604 {
2605 /* Driver is not initialized, try to load it */
2606 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2607
2608 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2609 {
2610 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2611 was loaded by the bootloader */
2612 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2613 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2614 {
2615 /* Initialize the driver */
2616 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2617 &DeviceNode->ServiceName, FALSE, &DriverObject);
2618 }
2619 else
2620 {
2621 Status = STATUS_SUCCESS;
2622 }
2623 }
2624 else
2625 {
2626 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2627 &DeviceNode->ServiceName, Status);
2628 }
2629 }
2630
2631 /* Driver is loaded and initialized at this point */
2632 if (NT_SUCCESS(Status))
2633 {
2634 /* Initialize the device, including all filters */
2635 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2636 }
2637 else
2638 {
2639 /*
2640 * Don't disable when trying to load only boot drivers
2641 */
2642 if (!BootDrivers)
2643 {
2644 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2645 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2646 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2647 DPRINT1("Initialization of service %S failed (Status %x)\n",
2648 DeviceNode->ServiceName.Buffer, Status);
2649 }
2650 }
2651 }
2652
2653 return STATUS_SUCCESS;
2654 }
2655
2656 /*
2657 * IopInitializePnpServices
2658 *
2659 * Initialize services for discovered children
2660 *
2661 * Parameters
2662 * DeviceNode
2663 * Top device node to start initializing services.
2664 *
2665 * Return Value
2666 * Status
2667 */
2668 NTSTATUS
2669 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2670 {
2671 DEVICETREE_TRAVERSE_CONTEXT Context;
2672
2673 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2674
2675 IopInitDeviceTreeTraverseContext(
2676 &Context,
2677 DeviceNode,
2678 IopActionInitChildServices,
2679 DeviceNode);
2680
2681 return IopTraverseDeviceTree(&Context);
2682 }
2683
2684 static NTSTATUS INIT_FUNCTION
2685 IopEnumerateDetectedDevices(
2686 IN HANDLE hBaseKey,
2687 IN PUNICODE_STRING RelativePath OPTIONAL,
2688 IN HANDLE hRootKey,
2689 IN BOOLEAN EnumerateSubKeys,
2690 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2691 IN ULONG ParentBootResourcesLength)
2692 {
2693 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2694 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2695 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2696 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2697 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2698 OBJECT_ATTRIBUTES ObjectAttributes;
2699 HANDLE hDevicesKey = NULL;
2700 HANDLE hDeviceKey = NULL;
2701 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2702 UNICODE_STRING Level2NameU;
2703 WCHAR Level2Name[5];
2704 ULONG IndexDevice = 0;
2705 ULONG IndexSubKey;
2706 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2707 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2708 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2709 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2710 UNICODE_STRING DeviceName, ValueName;
2711 ULONG RequiredSize;
2712 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2713 ULONG BootResourcesLength;
2714 NTSTATUS Status;
2715
2716 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
2717 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2718 static ULONG DeviceIndexPci = 0;
2719 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2720 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2721 static ULONG DeviceIndexSerial = 0;
2722 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2723 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2724 static ULONG DeviceIndexKeyboard = 0;
2725 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2726 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2727 static ULONG DeviceIndexMouse = 0;
2728 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
2729 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
2730 static ULONG DeviceIndexParallel = 0;
2731 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
2732 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
2733 static ULONG DeviceIndexFloppy = 0;
2734 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
2735 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
2736 static ULONG DeviceIndexIsa = 0;
2737 UNICODE_STRING HardwareIdKey;
2738 PUNICODE_STRING pHardwareId;
2739 ULONG DeviceIndex = 0;
2740 PUCHAR CmResourceList;
2741 ULONG ListCount;
2742
2743 if (RelativePath)
2744 {
2745 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
2746 if (!NT_SUCCESS(Status))
2747 {
2748 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2749 goto cleanup;
2750 }
2751 }
2752 else
2753 hDevicesKey = hBaseKey;
2754
2755 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2756 if (!pDeviceInformation)
2757 {
2758 DPRINT("ExAllocatePool() failed\n");
2759 Status = STATUS_NO_MEMORY;
2760 goto cleanup;
2761 }
2762
2763 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2764 if (!pValueInformation)
2765 {
2766 DPRINT("ExAllocatePool() failed\n");
2767 Status = STATUS_NO_MEMORY;
2768 goto cleanup;
2769 }
2770
2771 while (TRUE)
2772 {
2773 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2774 if (Status == STATUS_NO_MORE_ENTRIES)
2775 break;
2776 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2777 {
2778 ExFreePool(pDeviceInformation);
2779 DeviceInfoLength = RequiredSize;
2780 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2781 if (!pDeviceInformation)
2782 {
2783 DPRINT("ExAllocatePool() failed\n");
2784 Status = STATUS_NO_MEMORY;
2785 goto cleanup;
2786 }
2787 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2788 }
2789 if (!NT_SUCCESS(Status))
2790 {
2791 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2792 goto cleanup;
2793 }
2794 IndexDevice++;
2795
2796 /* Open device key */
2797 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2798 DeviceName.Buffer = pDeviceInformation->Name;
2799
2800 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
2801 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
2802 if (!NT_SUCCESS(Status))
2803 {
2804 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2805 goto cleanup;
2806 }
2807
2808 /* Read boot resources, and add then to parent ones */
2809 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2810 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2811 {
2812 ExFreePool(pValueInformation);
2813 ValueInfoLength = RequiredSize;
2814 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2815 if (!pValueInformation)
2816 {
2817 DPRINT("ExAllocatePool() failed\n");
2818 ZwDeleteKey(hLevel2Key);
2819 Status = STATUS_NO_MEMORY;
2820 goto cleanup;
2821 }
2822 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2823 }
2824 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2825 {
2826 BootResources = ParentBootResources;
2827 BootResourcesLength = ParentBootResourcesLength;
2828 }
2829 else if (!NT_SUCCESS(Status))
2830 {
2831 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2832 goto nextdevice;
2833 }
2834 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2835 {
2836 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2837 goto nextdevice;
2838 }
2839 else
2840 {
2841 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2842
2843 /* Concatenate current resources and parent ones */
2844 if (ParentBootResourcesLength == 0)
2845 BootResourcesLength = pValueInformation->DataLength;
2846 else
2847 BootResourcesLength = ParentBootResourcesLength
2848 + pValueInformation->DataLength
2849 - Header;
2850 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2851 if (!BootResources)
2852 {
2853 DPRINT("ExAllocatePool() failed\n");
2854 goto nextdevice;
2855 }
2856 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
2857 {
2858 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2859 }
2860 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2861 {
2862 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2863 RtlCopyMemory(
2864 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2865 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2866 ParentBootResourcesLength - Header);
2867 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2868 }
2869 else
2870 {
2871 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2872 RtlCopyMemory(
2873 (PVOID)((ULONG_PTR)BootResources + Header),
2874 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2875 ParentBootResourcesLength - Header);
2876 RtlCopyMemory(
2877 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2878 pValueInformation->Data + Header,
2879 pValueInformation->DataLength - Header);
2880 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2881 }
2882 }
2883
2884 if (EnumerateSubKeys)
2885 {
2886 IndexSubKey = 0;
2887 while (TRUE)
2888 {
2889 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2890 if (Status == STATUS_NO_MORE_ENTRIES)
2891 break;
2892 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2893 {
2894 ExFreePool(pDeviceInformation);
2895 DeviceInfoLength = RequiredSize;
2896 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2897 if (!pDeviceInformation)
2898 {
2899 DPRINT("ExAllocatePool() failed\n");
2900 Status = STATUS_NO_MEMORY;
2901 goto cleanup;
2902 }
2903 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2904 }
2905 if (!NT_SUCCESS(Status))
2906 {
2907 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2908 goto cleanup;
2909 }
2910 IndexSubKey++;
2911 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2912 DeviceName.Buffer = pDeviceInformation->Name;
2913
2914 Status = IopEnumerateDetectedDevices(
2915 hDeviceKey,
2916 &DeviceName,
2917 hRootKey,
2918 TRUE,
2919 BootResources,
2920 BootResourcesLength);
2921 if (!NT_SUCCESS(Status))
2922 goto cleanup;
2923 }
2924 }
2925
2926 /* Read identifier */
2927 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2928 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
2929 {
2930 ExFreePool(pValueInformation);
2931 ValueInfoLength = RequiredSize;
2932 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2933 if (!pValueInformation)
2934 {
2935 DPRINT("ExAllocatePool() failed\n");
2936 Status = STATUS_NO_MEMORY;
2937 goto cleanup;
2938 }
2939 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2940 }
2941 if (!NT_SUCCESS(Status))
2942 {
2943 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2944 {
2945 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2946 goto nextdevice;
2947 }
2948 ValueName.Length = ValueName.MaximumLength = 0;
2949 }
2950 else if (pValueInformation->Type != REG_SZ)
2951 {
2952 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2953 goto nextdevice;
2954 }
2955 else
2956 {
2957 /* Assign hardware id to this device */
2958 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2959 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2960 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2961 ValueName.Length -= sizeof(WCHAR);
2962 }
2963
2964 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2965 {
2966 pHardwareId = &HardwareIdSerial;
2967 DeviceIndex = DeviceIndexSerial++;
2968 }
2969 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2970 {
2971 pHardwareId = &HardwareIdKeyboard;
2972 DeviceIndex = DeviceIndexKeyboard++;
2973 }
2974 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2975 {
2976 pHardwareId = &HardwareIdMouse;
2977 DeviceIndex = DeviceIndexMouse++;
2978 }
2979 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
2980 {
2981 pHardwareId = &HardwareIdParallel;
2982 DeviceIndex = DeviceIndexParallel++;
2983 }
2984 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
2985 {
2986 pHardwareId = &HardwareIdFloppy;
2987 DeviceIndex = DeviceIndexFloppy++;
2988 }
2989 else if (NT_SUCCESS(Status))
2990 {
2991 /* Try to also match the device identifier */
2992 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2993 {
2994 pHardwareId = &HardwareIdPci;
2995 DeviceIndex = DeviceIndexPci++;
2996 }
2997 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
2998 {
2999 pHardwareId = &HardwareIdIsa;
3000 DeviceIndex = DeviceIndexIsa++;
3001 }
3002 else
3003 {
3004 DPRINT("Unknown device '%wZ'\n", &ValueName);
3005 goto nextdevice;
3006 }
3007 }
3008 else
3009 {
3010 /* Unknown key path */
3011 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3012 goto nextdevice;
3013 }
3014
3015 /* Prepare hardware id key (hardware id value without final \0) */
3016 HardwareIdKey = *pHardwareId;
3017 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3018
3019 /* Add the detected device to Root key */
3020 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3021 Status = ZwCreateKey(
3022 &hLevel1Key,
3023 KEY_CREATE_SUB_KEY,
3024 &ObjectAttributes,
3025 0,
3026 NULL,
3027 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3028 NULL);
3029 if (!NT_SUCCESS(Status))
3030 {
3031 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3032 goto nextdevice;
3033 }
3034 swprintf(Level2Name, L"%04lu", DeviceIndex);
3035 RtlInitUnicodeString(&Level2NameU, Level2Name);
3036 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3037 Status = ZwCreateKey(
3038 &hLevel2Key,
3039 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3040 &ObjectAttributes,
3041 0,
3042 NULL,
3043 ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0,
3044 NULL);
3045 ZwClose(hLevel1Key);
3046 if (!NT_SUCCESS(Status))
3047 {
3048 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3049 goto nextdevice;
3050 }
3051 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3052 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3053 if (!NT_SUCCESS(Status))
3054 {
3055 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3056 ZwDeleteKey(hLevel2Key);
3057 goto nextdevice;
3058 }
3059 /* Create 'LogConf' subkey */
3060 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3061 Status = ZwCreateKey(
3062 &hLogConf,
3063 KEY_SET_VALUE,
3064 &ObjectAttributes,
3065 0,
3066 NULL,
3067 REG_OPTION_VOLATILE,
3068 NULL);
3069 if (!NT_SUCCESS(Status))
3070 {
3071 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3072 ZwDeleteKey(hLevel2Key);
3073 goto nextdevice;
3074 }
3075 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3076 {
3077 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3078 if (!CmResourceList)
3079 {
3080 ZwClose(hLogConf);
3081 ZwDeleteKey(hLevel2Key);
3082 goto nextdevice;
3083 }
3084
3085 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3086 ListCount = 1;
3087 RtlCopyMemory(CmResourceList,
3088 &ListCount,
3089 sizeof(ULONG));
3090
3091 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3092 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3093 BootResources,
3094 BootResourcesLength);
3095
3096 /* Save boot resources to 'LogConf\BootConfig' */
3097 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3098 if (!NT_SUCCESS(Status))
3099 {
3100 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3101 ZwClose(hLogConf);
3102 ZwDeleteKey(hLevel2Key);
3103 goto nextdevice;
3104 }
3105 }
3106 ZwClose(hLogConf);
3107
3108 nextdevice:
3109 if (BootResources && BootResources != ParentBootResources)
3110 {
3111 ExFreePool(BootResources);
3112 BootResources = NULL;
3113 }
3114 if (hLevel2Key)
3115 {
3116 ZwClose(hLevel2Key);
3117 hLevel2Key = NULL;
3118 }
3119 if (hDeviceKey)
3120 {
3121 ZwClose(hDeviceKey);
3122 hDeviceKey = NULL;
3123 }
3124 }
3125
3126 Status = STATUS_SUCCESS;
3127
3128 cleanup:
3129 if (hDevicesKey && hDevicesKey != hBaseKey)
3130 ZwClose(hDevicesKey);
3131 if (hDeviceKey)
3132 ZwClose(hDeviceKey);
3133 if (pDeviceInformation)
3134 ExFreePool(pDeviceInformation);
3135 if (pValueInformation)
3136 ExFreePool(pValueInformation);
3137 return Status;
3138 }
3139
3140 static BOOLEAN INIT_FUNCTION
3141 IopIsFirmwareMapperDisabled(VOID)
3142 {
3143 UNICODE_STRING KeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CURRENTCONTROLSET\\Control\\Pnp");
3144 UNICODE_STRING KeyNameU = RTL_CONSTANT_STRING(L"DisableFirmwareMapper");
3145 OBJECT_ATTRIBUTES ObjectAttributes;
3146 HANDLE hPnpKey;
3147 PKEY_VALUE_PARTIAL_INFORMATION KeyInformation;
3148 ULONG DesiredLength, Length;
3149 ULONG KeyValue = 0;
3150 NTSTATUS Status;
3151
3152 InitializeObjectAttributes(&ObjectAttributes, &KeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3153 Status = ZwOpenKey(&hPnpKey, KEY_QUERY_VALUE, &ObjectAttributes);
3154 if (NT_SUCCESS(Status))
3155 {
3156 Status = ZwQueryValueKey(hPnpKey,
3157 &KeyNameU,
3158 KeyValuePartialInformation,
3159 NULL,
3160 0,
3161 &DesiredLength);
3162 if ((Status == STATUS_BUFFER_TOO_SMALL) ||
3163 (Status == STATUS_BUFFER_OVERFLOW))
3164 {
3165 Length = DesiredLength;
3166 KeyInformation = ExAllocatePool(PagedPool, Length);
3167 if (KeyInformation)
3168 {
3169 Status = ZwQueryValueKey(hPnpKey,
3170 &KeyNameU,
3171 KeyValuePartialInformation,
3172 KeyInformation,
3173 Length,
3174 &DesiredLength);
3175 if (NT_SUCCESS(Status) && KeyInformation->DataLength == sizeof(ULONG))
3176 {
3177 KeyValue = (ULONG)(*KeyInformation->Data);
3178 }
3179 else
3180 {
3181 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed\n", &KeyPathU, &KeyNameU);
3182 }
3183
3184 ExFreePool(KeyInformation);
3185 }
3186 else
3187 {
3188 DPRINT1("Failed to allocate memory for registry query\n");
3189 }
3190 }
3191 else
3192 {
3193 DPRINT1("ZwQueryValueKey(%wZ%wZ) failed with status 0x%08lx\n", &KeyPathU, &KeyNameU, Status);
3194 }
3195
3196 ZwClose(hPnpKey);
3197 }
3198 else
3199 {
3200 DPRINT1("ZwOpenKey(%wZ) failed with status 0x%08lx\n", &KeyPathU, Status);
3201 }
3202
3203 DPRINT1("Firmware mapper is %s\n", KeyValue != 0 ? "disabled" : "enabled");
3204
3205 return (KeyValue != 0) ? TRUE : FALSE;
3206 }
3207
3208 NTSTATUS
3209 NTAPI
3210 INIT_FUNCTION
3211 IopUpdateRootKey(VOID)
3212 {
3213 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3214 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3215 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3216 OBJECT_ATTRIBUTES ObjectAttributes;
3217 HANDLE hEnum, hRoot;
3218 NTSTATUS Status;
3219
3220 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3221 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3222 if (!NT_SUCCESS(Status))
3223 {
3224 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3225 return Status;
3226 }
3227
3228 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3229 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3230 ZwClose(hEnum);
3231 if (!NT_SUCCESS(Status))
3232 {
3233 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3234 return Status;
3235 }
3236
3237 if (!IopIsFirmwareMapperDisabled())
3238 {
3239 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3240 if (!NT_SUCCESS(Status))
3241 {
3242 /* Nothing to do, don't return with an error status */
3243 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3244 ZwClose(hRoot);
3245 return STATUS_SUCCESS;
3246 }
3247 Status = IopEnumerateDetectedDevices(
3248 hEnum,
3249 NULL,
3250 hRoot,
3251 TRUE,
3252 NULL,
3253 0);
3254 ZwClose(hEnum);
3255 }
3256 else
3257 {
3258 /* Enumeration is disabled */
3259 Status = STATUS_SUCCESS;
3260 }
3261
3262 ZwClose(hRoot);
3263
3264 return Status;
3265 }
3266
3267 NTSTATUS
3268 NTAPI
3269 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3270 HANDLE ParentKey,
3271 PUNICODE_STRING Name,
3272 ACCESS_MASK DesiredAccess)
3273 {
3274 OBJECT_ATTRIBUTES ObjectAttributes;
3275 NTSTATUS Status;
3276
3277 PAGED_CODE();
3278
3279 *KeyHandle = NULL;
3280
3281 InitializeObjectAttributes(&ObjectAttributes,
3282 Name,
3283 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3284 ParentKey,
3285 NULL);
3286
3287 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3288
3289 return Status;
3290 }
3291
3292 NTSTATUS
3293 NTAPI
3294 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3295 IN HANDLE RootHandle OPTIONAL,
3296 IN PUNICODE_STRING KeyName,
3297 IN ACCESS_MASK DesiredAccess,
3298 IN ULONG CreateOptions,
3299 OUT PULONG Disposition OPTIONAL)
3300 {
3301 OBJECT_ATTRIBUTES ObjectAttributes;
3302 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0;
3303 USHORT Length;
3304 HANDLE HandleArray[2];
3305 BOOLEAN Recursing = TRUE;
3306 PWCHAR pp, p, p1;
3307 UNICODE_STRING KeyString;
3308 NTSTATUS Status = STATUS_SUCCESS;
3309 PAGED_CODE();
3310
3311 /* P1 is start, pp is end */
3312 p1 = KeyName->Buffer;
3313 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3314
3315 /* Create the target key */
3316 InitializeObjectAttributes(&ObjectAttributes,
3317 KeyName,
3318 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3319 RootHandle,
3320 NULL);
3321 Status = ZwCreateKey(&HandleArray[i],
3322 DesiredAccess,
3323 &ObjectAttributes,
3324 0,
3325 NULL,
3326 CreateOptions,
3327 &KeyDisposition);
3328
3329 /* Now we check if this failed */
3330 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3331 {
3332 /* Target key failed, so we'll need to create its parent. Setup array */
3333 HandleArray[0] = NULL;
3334 HandleArray[1] = RootHandle;
3335
3336 /* Keep recursing for each missing parent */
3337 while (Recursing)
3338 {
3339 /* And if we're deep enough, close the last handle */
3340 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3341
3342 /* We're setup to ping-pong between the two handle array entries */
3343 RootHandleIndex = i;
3344 i = (i + 1) & 1;
3345
3346 /* Clear the one we're attempting to open now */
3347 HandleArray[i] = NULL;
3348
3349 /* Process the parent key name */
3350 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3351 Length = (USHORT)(p - p1) * sizeof(WCHAR);
3352
3353 /* Is there a parent name? */
3354 if (Length)
3355 {
3356 /* Build the unicode string for it */
3357 KeyString.Buffer = p1;
3358 KeyString.Length = KeyString.MaximumLength = Length;
3359
3360 /* Now try opening the parent */
3361 InitializeObjectAttributes(&ObjectAttributes,
3362 &KeyString,
3363 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3364 HandleArray[RootHandleIndex],
3365 NULL);
3366 Status = ZwCreateKey(&HandleArray[i],
3367 DesiredAccess,
3368 &ObjectAttributes,
3369 0,
3370 NULL,
3371 CreateOptions,
3372 &KeyDisposition);
3373 if (NT_SUCCESS(Status))
3374 {
3375 /* It worked, we have one more handle */
3376 NestedCloseLevel++;
3377 }
3378 else
3379 {
3380 /* Parent key creation failed, abandon loop */
3381 Recursing = FALSE;
3382 continue;
3383 }
3384 }
3385 else
3386 {
3387 /* We don't have a parent name, probably corrupted key name */
3388 Status = STATUS_INVALID_PARAMETER;
3389 Recursing = FALSE;
3390 continue;
3391 }
3392
3393 /* Now see if there's more parents to create */
3394 p1 = p + 1;
3395 if ((p == pp) || (p1 == pp))
3396 {
3397 /* We're done, hopefully successfully, so stop */
3398 Recursing = FALSE;
3399 }
3400 }
3401
3402 /* Outer loop check for handle nesting that requires closing the top handle */
3403 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3404 }
3405
3406 /* Check if we broke out of the loop due to success */
3407 if (NT_SUCCESS(Status))
3408 {
3409 /* Return the target handle (we closed all the parent ones) and disposition */
3410 *Handle = HandleArray[i];
3411 if (Disposition) *Disposition = KeyDisposition;
3412 }
3413
3414 /* Return the success state */
3415 return Status;
3416 }
3417
3418 NTSTATUS
3419 NTAPI
3420 IopGetRegistryValue(IN HANDLE Handle,
3421 IN PWSTR ValueName,
3422 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3423 {
3424 UNICODE_STRING ValueString;
3425 NTSTATUS Status;
3426 PKEY_VALUE_FULL_INFORMATION FullInformation;
3427 ULONG Size;
3428 PAGED_CODE();
3429
3430 RtlInitUnicodeString(&ValueString, ValueName);
3431
3432 Status = ZwQueryValueKey(Handle,
3433 &ValueString,
3434 KeyValueFullInformation,
3435 NULL,
3436 0,
3437 &Size);
3438 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3439 (Status != STATUS_BUFFER_TOO_SMALL))
3440 {
3441 return Status;
3442 }
3443
3444 FullInformation = ExAllocatePool(NonPagedPool, Size);
3445 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3446
3447 Status = ZwQueryValueKey(Handle,
3448 &ValueString,
3449 KeyValueFullInformation,
3450 FullInformation,
3451 Size,
3452 &Size);
3453 if (!NT_SUCCESS(Status))
3454 {
3455 ExFreePool(FullInformation);
3456 return Status;
3457 }
3458
3459 *Information = FullInformation;
3460 return STATUS_SUCCESS;
3461 }
3462
3463 RTL_GENERIC_COMPARE_RESULTS
3464 NTAPI
3465 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3466 IN PVOID FirstStruct,
3467 IN PVOID SecondStruct)
3468 {
3469 /* FIXME: TODO */
3470 ASSERT(FALSE);
3471 return 0;
3472 }
3473
3474 //
3475 // The allocation function is called by the generic table package whenever
3476 // it needs to allocate memory for the table.
3477 //
3478
3479 PVOID
3480 NTAPI
3481 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3482 IN CLONG ByteSize)
3483 {
3484 /* FIXME: TODO */
3485 ASSERT(FALSE);
3486 return NULL;
3487 }
3488
3489 VOID
3490 NTAPI
3491 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3492 IN PVOID Buffer)
3493 {
3494 /* FIXME: TODO */
3495 ASSERT(FALSE);
3496 }
3497
3498 VOID
3499 NTAPI
3500 PpInitializeDeviceReferenceTable(VOID)
3501 {
3502 /* Setup the guarded mutex and AVL table */
3503 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3504 RtlInitializeGenericTableAvl(
3505 &PpDeviceReferenceTable,
3506 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3507 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3508 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3509 NULL);
3510 }
3511
3512 BOOLEAN
3513 NTAPI
3514 PiInitPhase0(VOID)
3515 {
3516 /* Initialize the resource when accessing device registry data */
3517 ExInitializeResourceLite(&PpRegistryDeviceResource);
3518
3519 /* Setup the device reference AVL table */
3520 PpInitializeDeviceReferenceTable();
3521 return TRUE;
3522 }
3523
3524 BOOLEAN
3525 NTAPI
3526 PpInitSystem(VOID)
3527 {
3528 /* Check the initialization phase */
3529 switch (ExpInitializationPhase)
3530 {
3531 case 0:
3532
3533 /* Do Phase 0 */
3534 return PiInitPhase0();
3535
3536 case 1:
3537
3538 /* Do Phase 1 */
3539 return TRUE;
3540 //return PiInitPhase1();
3541
3542 default:
3543
3544 /* Don't know any other phase! Bugcheck! */
3545 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3546 return FALSE;
3547 }
3548 }
3549
3550 LONG IopNumberDeviceNodes;
3551
3552 PDEVICE_NODE
3553 NTAPI
3554 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3555 {
3556 PDEVICE_NODE DeviceNode;
3557 PAGED_CODE();
3558
3559 /* Allocate it */
3560 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
3561 if (!DeviceNode) return DeviceNode;
3562
3563 /* Statistics */
3564 InterlockedIncrement(&IopNumberDeviceNodes);
3565
3566 /* Set it up */
3567 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3568 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3569 DeviceNode->BusNumber = -1;
3570 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3571 DeviceNode->ChildBusNumber = -1;
3572 DeviceNode->ChildBusTypeIndex = -1;
3573 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3574 InitializeListHead(&DeviceNode->DeviceArbiterList);
3575 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3576 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3577 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3578 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3579
3580 /* Check if there is a PDO */
3581 if (PhysicalDeviceObject)
3582 {
3583 /* Link it and remove the init flag */
3584 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3585 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3586 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3587 }
3588
3589 /* Return the node */
3590 return DeviceNode;
3591 }
3592
3593 /* PUBLIC FUNCTIONS **********************************************************/
3594
3595 NTSTATUS
3596 NTAPI
3597 PnpBusTypeGuidGet(IN USHORT Index,
3598 IN LPGUID BusTypeGuid)
3599 {
3600 NTSTATUS Status = STATUS_SUCCESS;
3601
3602 /* Acquire the lock */
3603 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
3604
3605 /* Validate size */
3606 if (Index < PnpBusTypeGuidList->GuidCount)
3607 {
3608 /* Copy the data */
3609 RtlCopyMemory(BusTypeGuid, &PnpBusTypeGuidList->Guids[Index], sizeof(GUID));
3610 }
3611 else
3612 {
3613 /* Failure path */
3614 Status = STATUS_OBJECT_NAME_NOT_FOUND;
3615 }
3616
3617 /* Release lock and return status */
3618 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
3619 return Status;
3620 }
3621
3622 NTSTATUS
3623 NTAPI
3624 PnpDeviceObjectToDeviceInstance(IN PDEVICE_OBJECT DeviceObject,
3625 IN PHANDLE DeviceInstanceHandle,
3626 IN ACCESS_MASK DesiredAccess)
3627 {
3628 NTSTATUS Status;
3629 HANDLE KeyHandle;
3630 PDEVICE_NODE DeviceNode;
3631 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
3632 PAGED_CODE();
3633
3634 /* Open the enum key */
3635 Status = IopOpenRegistryKeyEx(&KeyHandle,
3636 NULL,
3637 &KeyName,
3638 KEY_READ);
3639 if (!NT_SUCCESS(Status)) return Status;
3640
3641 /* Make sure we have an instance path */
3642 DeviceNode = IopGetDeviceNode(DeviceObject);
3643 if ((DeviceNode) && (DeviceNode->InstancePath.Length))
3644 {
3645 /* Get the instance key */
3646 Status = IopOpenRegistryKeyEx(DeviceInstanceHandle,
3647 KeyHandle,
3648 &DeviceNode->InstancePath,
3649 DesiredAccess);
3650 }
3651 else
3652 {
3653 /* Fail */
3654 Status = STATUS_INVALID_DEVICE_REQUEST;
3655 }
3656
3657 /* Close the handle and return status */
3658 ZwClose(KeyHandle);
3659 return Status;
3660 }
3661
3662 ULONG
3663 NTAPI
3664 PnpDetermineResourceListSize(IN PCM_RESOURCE_LIST ResourceList)
3665 {
3666 ULONG FinalSize, PartialSize, EntrySize, i, j;
3667 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
3668 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
3669
3670 /* If we don't have one, that's easy */
3671 if (!ResourceList) return 0;
3672
3673 /* Start with the minimum size possible */
3674 FinalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
3675
3676 /* Loop each full descriptor */
3677 FullDescriptor = ResourceList->List;
3678 for (i = 0; i < ResourceList->Count; i++)
3679 {
3680 /* Start with the minimum size possible */
3681 PartialSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
3682 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors);
3683
3684 /* Loop each partial descriptor */
3685 PartialDescriptor = FullDescriptor->PartialResourceList.PartialDescriptors;
3686 for (j = 0; j < FullDescriptor->PartialResourceList.Count; j++)
3687 {
3688 /* Start with the minimum size possible */
3689 EntrySize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
3690
3691 /* Check if there is extra data */
3692 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific)
3693 {
3694 /* Add that data */
3695 EntrySize += PartialDescriptor->u.DeviceSpecificData.DataSize;
3696 }
3697
3698 /* The size of partial descriptors is bigger */
3699 PartialSize += EntrySize;
3700
3701 /* Go to the next partial descriptor */
3702 PartialDescriptor = (PVOID)((ULONG_PTR)PartialDescriptor + EntrySize);
3703 }
3704
3705 /* The size of full descriptors is bigger */
3706 FinalSize += PartialSize;
3707
3708 /* Go to the next full descriptor */
3709 FullDescriptor = (PVOID)((ULONG_PTR)FullDescriptor + PartialSize);
3710 }
3711
3712 /* Return the final size */
3713 return FinalSize;
3714 }
3715
3716 NTSTATUS
3717 NTAPI
3718 PiGetDeviceRegistryProperty(IN PDEVICE_OBJECT DeviceObject,
3719 IN ULONG ValueType,
3720 IN PWSTR ValueName,
3721 IN PWSTR KeyName,
3722 OUT PVOID Buffer,
3723 IN PULONG BufferLength)
3724 {
3725 NTSTATUS Status;
3726 HANDLE KeyHandle, SubHandle;
3727 UNICODE_STRING KeyString;
3728 PKEY_VALUE_FULL_INFORMATION KeyValueInfo = NULL;
3729 ULONG Length;
3730 PAGED_CODE();
3731
3732 /* Find the instance key */
3733 Status = PnpDeviceObjectToDeviceInstance(DeviceObject, &KeyHandle, KEY_READ);
3734 if (NT_SUCCESS(Status))
3735 {
3736 /* Check for name given by caller */
3737 if (KeyName)
3738 {
3739 /* Open this key */
3740 RtlInitUnicodeString(&KeyString, KeyName);
3741 Status = IopOpenRegistryKeyEx(&SubHandle,
3742 KeyHandle,
3743 &KeyString,
3744 KEY_READ);
3745 if (NT_SUCCESS(Status))
3746 {
3747 /* And use this handle instead */
3748 ZwClose(KeyHandle);
3749 KeyHandle = SubHandle;
3750 }
3751 }
3752
3753 /* Check if sub-key handle succeeded (or no-op if no key name given) */
3754 if (NT_SUCCESS(Status))
3755 {
3756 /* Now get the size of the property */
3757 Status = IopGetRegistryValue(KeyHandle,
3758 ValueName,
3759 &KeyValueInfo);
3760 }
3761
3762 /* Close the key */
3763 ZwClose(KeyHandle);
3764 }
3765
3766 /* Fail if any of the registry operations failed */
3767 if (!NT_SUCCESS(Status)) return Status;
3768
3769 /* Check how much data we have to copy */
3770 Length = KeyValueInfo->DataLength;
3771 if (*BufferLength >= Length)
3772 {
3773 /* Check for a match in the value type */
3774 if (KeyValueInfo->Type == ValueType)
3775 {
3776 /* Copy the data */
3777 RtlCopyMemory(Buffer,
3778 (PVOID)((ULONG_PTR)KeyValueInfo +
3779 KeyValueInfo->DataOffset),
3780 Length);
3781 }
3782 else
3783 {
3784 /* Invalid registry property type, fail */
3785 Status = STATUS_INVALID_PARAMETER_2;
3786 }
3787 }
3788 else
3789 {
3790 /* Buffer is too small to hold data */
3791 Status = STATUS_BUFFER_TOO_SMALL;
3792 }
3793
3794 /* Return the required buffer length, free the buffer, and return status */
3795 *BufferLength = Length;
3796 ExFreePool(KeyValueInfo);
3797 return Status;
3798 }
3799
3800 #define PIP_RETURN_DATA(x, y) {ReturnLength = x; Data = y; Status = STATUS_SUCCESS; break;}
3801 #define PIP_REGISTRY_DATA(x, y) {ValueName = x; ValueType = y; break;}
3802 #define PIP_UNIMPLEMENTED() {UNIMPLEMENTED; while(TRUE); break;}
3803
3804 /*
3805 * @implemented
3806 */
3807 NTSTATUS
3808 NTAPI
3809 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
3810 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
3811 IN ULONG BufferLength,
3812 OUT PVOID PropertyBuffer,
3813 OUT PULONG ResultLength)
3814 {
3815 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
3816 DEVICE_CAPABILITIES DeviceCaps;
3817 ULONG ReturnLength = 0, Length = 0, ValueType;
3818 PWCHAR ValueName = NULL, EnumeratorNameEnd, DeviceInstanceName;
3819 PVOID Data = NULL;
3820 NTSTATUS Status = STATUS_BUFFER_TOO_SMALL;
3821 GUID BusTypeGuid;
3822 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
3823 BOOLEAN NullTerminate = FALSE;
3824
3825 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
3826
3827 /* Assume failure */
3828 *ResultLength = 0;
3829
3830 /* Only PDOs can call this */
3831 if (!DeviceNode) return STATUS_INVALID_DEVICE_REQUEST;
3832
3833 /* Handle all properties */
3834 switch (DeviceProperty)
3835 {
3836 case DevicePropertyBusTypeGuid:
3837
3838 /* Get the GUID from the internal cache */
3839 Status = PnpBusTypeGuidGet(DeviceNode->ChildBusTypeIndex, &BusTypeGuid);
3840 if (!NT_SUCCESS(Status)) return Status;
3841
3842 /* This is the format of the returned data */
3843 PIP_RETURN_DATA(sizeof(GUID), &BusTypeGuid);
3844
3845 case DevicePropertyLegacyBusType:
3846
3847 /* Validate correct interface type */
3848 if (DeviceNode->ChildInterfaceType == InterfaceTypeUndefined)
3849 return STATUS_OBJECT_NAME_NOT_FOUND;
3850
3851 /* This is the format of the returned data */
3852 PIP_RETURN_DATA(sizeof(INTERFACE_TYPE), &DeviceNode->ChildInterfaceType);
3853
3854 case DevicePropertyBusNumber:
3855
3856 /* Validate correct bus number */
3857 if ((DeviceNode->ChildBusNumber & 0x80000000) == 0x80000000)
3858 return STATUS_OBJECT_NAME_NOT_FOUND;
3859
3860 /* This is the format of the returned data */
3861 PIP_RETURN_DATA(sizeof(ULONG), &DeviceNode->ChildBusNumber);
3862
3863 case DevicePropertyEnumeratorName:
3864
3865 /* Get the instance path */
3866 DeviceInstanceName = DeviceNode->InstancePath.Buffer;
3867
3868 /* Sanity checks */
3869 ASSERT((BufferLength & 1) == 0);
3870 ASSERT(DeviceInstanceName != NULL);
3871
3872 /* Get the name from the path */
3873 EnumeratorNameEnd = wcschr(DeviceInstanceName, OBJ_NAME_PATH_SEPARATOR);
3874 ASSERT(EnumeratorNameEnd);
3875
3876 /* This string needs to be NULL-terminated */
3877 NullTerminate = TRUE;
3878
3879 /* This is the format of the returned data */
3880 PIP_RETURN_DATA((ULONG)(EnumeratorNameEnd - DeviceInstanceName) * sizeof(WCHAR),
3881 DeviceInstanceName);
3882
3883 case DevicePropertyAddress:
3884
3885 /* Query the device caps */
3886 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
3887 if (!NT_SUCCESS(Status) || (DeviceCaps.Address == MAXULONG))
3888 return STATUS_OBJECT_NAME_NOT_FOUND;
3889
3890 /* This is the format of the returned data */
3891 PIP_RETURN_DATA(sizeof(ULONG), &DeviceCaps.Address);
3892
3893 case DevicePropertyBootConfigurationTranslated:
3894
3895 /* Validate we have resources */
3896 if (!DeviceNode->BootResources)
3897 // if (!DeviceNode->BootResourcesTranslated) // FIXFIX: Need this field
3898 {
3899 /* No resources will still fake success, but with 0 bytes */
3900 *ResultLength = 0;
3901 return STATUS_SUCCESS;
3902 }
3903
3904 /* This is the format of the returned data */
3905 PIP_RETURN_DATA(PnpDetermineResourceListSize(DeviceNode->BootResources), // FIXFIX: Should use BootResourcesTranslated
3906 DeviceNode->BootResources); // FIXFIX: Should use BootResourcesTranslated
3907
3908 case DevicePropertyPhysicalDeviceObjectName:
3909
3910 /* Sanity check for Unicode-sized string */
3911 ASSERT((BufferLength & 1) == 0);
3912
3913 /* Allocate name buffer */
3914 Length = BufferLength + sizeof(OBJECT_NAME_INFORMATION);
3915 ObjectNameInfo = ExAllocatePool(PagedPool, Length);
3916 if (!ObjectNameInfo) return STATUS_INSUFFICIENT_RESOURCES;
3917
3918 /* Query the PDO name */
3919 Status = ObQueryNameString(DeviceObject,
3920 ObjectNameInfo,
3921 Length,
3922 ResultLength);
3923 if (Status == STATUS_INFO_LENGTH_MISMATCH)
3924 {
3925 /* It's up to the caller to try again */
3926 Status = STATUS_BUFFER_TOO_SMALL;
3927 }
3928
3929 /* This string needs to be NULL-terminated */
3930 NullTerminate = TRUE;
3931
3932 /* Return if successful */
3933 if (NT_SUCCESS(Status)) PIP_RETURN_DATA(ObjectNameInfo->Name.Length,
3934 ObjectNameInfo->Name.Buffer);
3935
3936 /* Let the caller know how big the name is */
3937 *ResultLength -= sizeof(OBJECT_NAME_INFORMATION);
3938 break;
3939
3940 /* Handle the registry-based properties */
3941 case DevicePropertyUINumber:
3942 PIP_REGISTRY_DATA(REGSTR_VAL_UI_NUMBER, REG_DWORD);
3943 case DevicePropertyLocationInformation:
3944 PIP_REGISTRY_DATA(REGSTR_VAL_LOCATION_INFORMATION, REG_SZ);
3945 case DevicePropertyDeviceDescription:
3946 PIP_REGISTRY_DATA(REGSTR_VAL_DEVDESC, REG_SZ);
3947 case DevicePropertyHardwareID:
3948 PIP_REGISTRY_DATA(REGSTR_VAL_HARDWAREID, REG_MULTI_SZ);
3949 case DevicePropertyCompatibleIDs:
3950 PIP_REGISTRY_DATA(REGSTR_VAL_COMPATIBLEIDS, REG_MULTI_SZ);
3951 case DevicePropertyBootConfiguration:
3952 PIP_REGISTRY_DATA(REGSTR_VAL_BOOTCONFIG, REG_RESOURCE_LIST);
3953 case DevicePropertyClassName:
3954 PIP_REGISTRY_DATA(REGSTR_VAL_CLASS, REG_SZ);
3955 case DevicePropertyClassGuid:
3956 PIP_REGISTRY_DATA(REGSTR_VAL_CLASSGUID, REG_SZ);
3957 case DevicePropertyDriverKeyName:
3958 PIP_REGISTRY_DATA(REGSTR_VAL_DRIVER, REG_SZ);
3959 case DevicePropertyManufacturer:
3960 PIP_REGISTRY_DATA(REGSTR_VAL_MFG, REG_SZ);
3961 case DevicePropertyFriendlyName:
3962 PIP_REGISTRY_DATA(REGSTR_VAL_FRIENDLYNAME, REG_SZ);
3963 case DevicePropertyContainerID:
3964 //PIP_REGISTRY_DATA(REGSTR_VAL_CONTAINERID, REG_SZ); // Win7
3965 PIP_UNIMPLEMENTED();
3966 case DevicePropertyRemovalPolicy:
3967 PIP_UNIMPLEMENTED();
3968 case DevicePropertyInstallState:
3969 PIP_UNIMPLEMENTED();
3970 case DevicePropertyResourceRequirements:
3971 PIP_UNIMPLEMENTED();
3972 case DevicePropertyAllocatedResources:
3973 PIP_UNIMPLEMENTED();
3974 default:
3975 return STATUS_INVALID_PARAMETER_2;
3976 }
3977
3978 /* Having a registry value name implies registry data */
3979 if (ValueName)
3980 {
3981 /* We know up-front how much data to expect */
3982 *ResultLength = BufferLength;
3983
3984 /* Go get the data, use the LogConf subkey if necessary */
3985 Status = PiGetDeviceRegistryProperty(DeviceObject,
3986 ValueType,
3987 ValueName,
3988 (DeviceProperty ==
3989 DevicePropertyBootConfiguration) ?
3990 L"LogConf": NULL,
3991 PropertyBuffer,
3992 ResultLength);
3993 }
3994 else if (NT_SUCCESS(Status))
3995 {
3996 /* We know up-front how much data to expect, check the caller's buffer */
3997 *ResultLength = ReturnLength + (NullTerminate ? sizeof(UNICODE_NULL) : 0);
3998 if (*ResultLength <= BufferLength)
3999 {
4000 /* Buffer is all good, copy the data */
4001 RtlCopyMemory(PropertyBuffer, Data, ReturnLength);
4002
4003 /* Check if we need to NULL-terminate the string */
4004 if (NullTerminate)
4005 {
4006 /* Terminate the string */
4007 ((PWCHAR)PropertyBuffer)[ReturnLength / sizeof(WCHAR)] = UNICODE_NULL;
4008 }
4009
4010 /* This is the success path */
4011 Status = STATUS_SUCCESS;
4012 }
4013 else
4014 {
4015 /* Failure path */
4016 Status = STATUS_BUFFER_TOO_SMALL;
4017 }
4018 }
4019
4020 /* Free any allocation we may have made, and return the status code */
4021 if (ObjectNameInfo) ExFreePool(ObjectNameInfo);
4022 return Status;
4023 }
4024
4025 /*
4026 * @implemented
4027 */
4028 VOID
4029 NTAPI
4030 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4031 {
4032 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4033 IO_STACK_LOCATION Stack;
4034 ULONG PnPFlags;
4035 NTSTATUS Status;
4036 IO_STATUS_BLOCK IoStatusBlock;
4037
4038 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
4039 Stack.MajorFunction = IRP_MJ_PNP;
4040 Stack.MinorFunction = IRP_MN_QUERY_PNP_DEVICE_STATE;
4041
4042 Status = IopSynchronousCall(PhysicalDeviceObject, &Stack, (PVOID*)&PnPFlags);
4043 if (!NT_SUCCESS(Status))
4044 {
4045 DPRINT1("IRP_MN_QUERY_PNP_DEVICE_STATE failed with status 0x%x\n", Status);
4046 return;
4047 }
4048
4049 if (PnPFlags & PNP_DEVICE_NOT_DISABLEABLE)
4050 DeviceNode->UserFlags |= DNUF_NOT_DISABLEABLE;
4051 else
4052 DeviceNode->UserFlags &= ~DNUF_NOT_DISABLEABLE;
4053
4054 if (PnPFlags & PNP_DEVICE_DONT_DISPLAY_IN_UI)
4055 DeviceNode->UserFlags |= DNUF_DONT_SHOW_IN_UI;
4056 else
4057 DeviceNode->UserFlags &= ~DNUF_DONT_SHOW_IN_UI;
4058
4059 if ((PnPFlags & PNP_DEVICE_REMOVED) ||
4060 ((PnPFlags & PNP_DEVICE_FAILED) && !(PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)))
4061 {
4062 /* Surprise removal */
4063
4064 IopSendSurpriseRemoval(PhysicalDeviceObject);
4065
4066 /* Tell the user-mode PnP manager that a device was removed */
4067 IopQueueTargetDeviceEvent(&GUID_DEVICE_SURPRISE_REMOVAL,
4068 &DeviceNode->InstancePath);
4069
4070 IopSendRemoveDevice(PhysicalDeviceObject);
4071 }
4072 else if ((PnPFlags & PNP_DEVICE_FAILED) && (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED))
4073 {
4074 /* Stop for resource rebalance */
4075
4076 Status = IopStopDevice(DeviceNode);
4077 if (!NT_SUCCESS(Status))
4078 {
4079 DPRINT1("Failed to stop device for rebalancing\n");
4080
4081 /* Stop failed so don't rebalance */
4082 PnPFlags &= ~PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED;
4083 }
4084 }
4085
4086 /* Resource rebalance */
4087 if (PnPFlags & PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED)
4088 {
4089 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
4090
4091 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4092 &IoStatusBlock,
4093 IRP_MN_QUERY_RESOURCES,
4094 NULL);
4095 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
4096 {
4097 DeviceNode->BootResources =
4098 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
4099 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
4100 }
4101 else
4102 {
4103 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
4104 DeviceNode->BootResources = NULL;
4105 }
4106
4107 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
4108
4109 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4110 &IoStatusBlock,
4111 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
4112 NULL);
4113 if (NT_SUCCESS(Status))
4114 {
4115 DeviceNode->ResourceRequirements =
4116 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
4117 }
4118 else
4119 {
4120 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
4121 DeviceNode->ResourceRequirements = NULL;
4122 }
4123
4124 /* IRP_MN_FILTER_RESOURCE_REQUIREMENTS is called indirectly by IopStartDevice */
4125 if (IopStartDevice(DeviceNode) != STATUS_SUCCESS)
4126 {
4127 DPRINT1("Restart after resource rebalance failed\n");
4128
4129 DeviceNode->Flags &= ~(DNF_STARTED | DNF_START_REQUEST_PENDING);
4130 DeviceNode->Flags |= DNF_START_FAILED;
4131
4132 IopRemoveDevice(DeviceNode);
4133 }
4134 }
4135 }
4136
4137 /**
4138 * @name IoOpenDeviceRegistryKey
4139 *
4140 * Open a registry key unique for a specified driver or device instance.
4141 *
4142 * @param DeviceObject Device to get the registry key for.
4143 * @param DevInstKeyType Type of the key to return.
4144 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4145 * @param DevInstRegKey Handle to the opened registry key on
4146 * successful return.
4147 *
4148 * @return Status.
4149 *
4150 * @implemented
4151 */
4152 NTSTATUS
4153 NTAPI
4154 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4155 IN ULONG DevInstKeyType,
4156 IN ACCESS_MASK DesiredAccess,
4157 OUT PHANDLE DevInstRegKey)
4158 {
4159 static WCHAR RootKeyName[] =
4160 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4161 static WCHAR ProfileKeyName[] =
4162 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4163 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4164 static WCHAR EnumKeyName[] = L"Enum\\";
4165 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4166 ULONG KeyNameLength;
4167 LPWSTR KeyNameBuffer;
4168 UNICODE_STRING KeyName;
4169 ULONG DriverKeyLength;
4170 OBJECT_ATTRIBUTES ObjectAttributes;
4171 PDEVICE_NODE DeviceNode = NULL;
4172 NTSTATUS Status;
4173
4174 DPRINT("IoOpenDeviceRegistryKey() called\n");
4175
4176 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4177 {
4178 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4179 return STATUS_INVALID_PARAMETER;
4180 }
4181
4182 if (!IopIsValidPhysicalDeviceObject(DeviceObject))
4183 return STATUS_INVALID_DEVICE_REQUEST;
4184 DeviceNode = IopGetDeviceNode(DeviceObject);
4185
4186 /*
4187 * Calculate the length of the base key name. This is the full
4188 * name for driver key or the name excluding "Device Parameters"
4189 * subkey for device key.
4190 */
4191
4192 KeyNameLength = sizeof(RootKeyName);
4193 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4194 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4195 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4196 {
4197 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4198 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4199 0, NULL, &DriverKeyLength);
4200 if (Status != STATUS_BUFFER_TOO_SMALL)
4201 return Status;
4202 KeyNameLength += DriverKeyLength;
4203 }
4204 else
4205 {
4206 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4207 DeviceNode->InstancePath.Length;
4208 }
4209
4210 /*
4211 * Now allocate the buffer for the key name...
4212 */
4213
4214 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4215 if (KeyNameBuffer == NULL)
4216 return STATUS_INSUFFICIENT_RESOURCES;
4217
4218 KeyName.Length = 0;
4219 KeyName.MaximumLength = (USHORT)KeyNameLength;
4220 KeyName.Buffer = KeyNameBuffer;
4221
4222 /*
4223 * ...and build the key name.
4224 */
4225
4226 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4227 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4228
4229 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4230 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4231
4232 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4233 {
4234 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4235 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4236 DriverKeyLength, KeyNameBuffer +
4237 (KeyName.Length / sizeof(WCHAR)),
4238 &DriverKeyLength);
4239 if (!NT_SUCCESS(Status))
4240 {
4241 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4242 ExFreePool(KeyNameBuffer);
4243 return Status;
4244 }
4245 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4246 }
4247 else
4248 {
4249 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4250 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4251 if (DeviceNode->InstancePath.Length == 0)
4252 {
4253 ExFreePool(KeyNameBuffer);
4254 return Status;
4255 }
4256 }
4257
4258 /*
4259 * Open the base key.
4260 */
4261 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4262 if (!NT_SUCCESS(Status))
4263 {
4264 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4265 ExFreePool(KeyNameBuffer);
4266 return Status;
4267 }
4268 ExFreePool(KeyNameBuffer);
4269
4270 /*
4271 * For driver key we're done now.
4272 */
4273
4274 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4275 return Status;
4276
4277 /*
4278 * Let's go further. For device key we must open "Device Parameters"
4279 * subkey and create it if it doesn't exist yet.
4280 */
4281
4282 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4283 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
4284 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
4285 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4286 0, NULL, ExpInTextModeSetup ? REG_OPTION_VOLATILE : 0, NULL);
4287 ZwClose(ObjectAttributes.RootDirectory);
4288
4289 return Status;
4290 }
4291
4292 static
4293 NTSTATUS
4294 IopQueryRemoveChildDevices(PDEVICE_NODE ParentDeviceNode, BOOLEAN Force)
4295 {
4296 PDEVICE_NODE ChildDeviceNode, NextDeviceNode, FailedRemoveDevice;
4297 NTSTATUS Status;
4298 KIRQL OldIrql;
4299
4300 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4301 ChildDeviceNode = ParentDeviceNode->Child;
4302 while (ChildDeviceNode != NULL)
4303 {
4304 NextDeviceNode = ChildDeviceNode->Sibling;
4305 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4306
4307 Status = IopPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject, Force);
4308 if (!NT_SUCCESS(Status))
4309 {
4310 FailedRemoveDevice = ChildDeviceNode;
4311 goto cleanup;
4312 }
4313
4314 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4315 ChildDeviceNode = NextDeviceNode;
4316 }
4317 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4318
4319 return STATUS_SUCCESS;
4320
4321 cleanup:
4322 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4323 ChildDeviceNode = ParentDeviceNode->Child;
4324 while (ChildDeviceNode != NULL)
4325 {
4326 NextDeviceNode = ChildDeviceNode->Sibling;
4327 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4328
4329 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4330
4331 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4332 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4333 if (ChildDeviceNode == FailedRemoveDevice)
4334 return Status;
4335
4336 ChildDeviceNode = NextDeviceNode;
4337
4338 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4339 }
4340 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4341
4342 return Status;
4343 }
4344
4345 static
4346 VOID
4347 IopSendRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4348 {
4349 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4350 KIRQL OldIrql;
4351
4352 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4353 ChildDeviceNode = ParentDeviceNode->Child;
4354 while (ChildDeviceNode != NULL)
4355 {
4356 NextDeviceNode = ChildDeviceNode->Sibling;
4357 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4358
4359 IopSendRemoveDevice(ChildDeviceNode->PhysicalDeviceObject);
4360
4361 ChildDeviceNode = NextDeviceNode;
4362
4363 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4364 }
4365 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4366 }
4367
4368 static
4369 VOID
4370 IopCancelRemoveChildDevices(PDEVICE_NODE ParentDeviceNode)
4371 {
4372 PDEVICE_NODE ChildDeviceNode, NextDeviceNode;
4373 KIRQL OldIrql;
4374
4375 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4376 ChildDeviceNode = ParentDeviceNode->Child;
4377 while (ChildDeviceNode != NULL)
4378 {
4379 NextDeviceNode = ChildDeviceNode->Sibling;
4380 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4381
4382 IopCancelPrepareDeviceForRemoval(ChildDeviceNode->PhysicalDeviceObject);
4383
4384 ChildDeviceNode = NextDeviceNode;
4385
4386 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
4387 }
4388 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
4389 }
4390
4391 static
4392 NTSTATUS
4393 IopQueryRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations, BOOLEAN Force)
4394 {
4395 /* This function DOES NOT dereference the device objects on SUCCESS
4396 * but it DOES dereference device objects on FAILURE */
4397
4398 ULONG i, j;
4399 NTSTATUS Status;
4400
4401 for (i = 0; i < DeviceRelations->Count; i++)
4402 {
4403 Status = IopPrepareDeviceForRemoval(DeviceRelations->Objects[i], Force);
4404 if (!NT_SUCCESS(Status))
4405 {
4406 j = i;
4407 goto cleanup;
4408 }
4409 }
4410
4411 return STATUS_SUCCESS;
4412
4413 cleanup:
4414 /* IRP_MN_CANCEL_REMOVE_DEVICE is also sent to the device
4415 * that failed the IRP_MN_QUERY_REMOVE_DEVICE request */
4416 for (i = 0; i <= j; i++)
4417 {
4418 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4419 ObDereferenceObject(DeviceRelations->Objects[i]);
4420 DeviceRelations->Objects[i] = NULL;
4421 }
4422 for (; i < DeviceRelations->Count; i++)
4423 {
4424 ObDereferenceObject(DeviceRelations->Objects[i]);
4425 DeviceRelations->Objects[i] = NULL;
4426 }
4427 ExFreePool(DeviceRelations);
4428
4429 return Status;
4430 }
4431
4432 static
4433 VOID
4434 IopSendRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4435 {
4436 /* This function DOES dereference the device objects in all cases */
4437
4438 ULONG i;
4439
4440 for (i = 0; i < DeviceRelations->Count; i++)
4441 {
4442 IopSendRemoveDevice(DeviceRelations->Objects[i]);
4443 ObDereferenceObject(DeviceRelations->Objects[i]);
4444 DeviceRelations->Objects[i] = NULL;
4445 }
4446
4447 ExFreePool(DeviceRelations);
4448 }
4449
4450 static
4451 VOID
4452 IopCancelRemoveDeviceRelations(PDEVICE_RELATIONS DeviceRelations)
4453 {
4454 /* This function DOES dereference the device objects in all cases */
4455
4456 ULONG i;
4457
4458 for (i = 0; i < DeviceRelations->Count; i++)
4459 {
4460 IopCancelPrepareDeviceForRemoval(DeviceRelations->Objects[i]);
4461 ObDereferenceObject(DeviceRelations->Objects[i]);
4462 DeviceRelations->Objects[i] = NULL;
4463 }
4464
4465 ExFreePool(DeviceRelations);
4466 }
4467
4468 VOID
4469 IopCancelPrepareDeviceForRemoval(PDEVICE_OBJECT DeviceObject)
4470 {
4471 IO_STACK_LOCATION Stack;
4472 IO_STATUS_BLOCK IoStatusBlock;
4473 PDEVICE_RELATIONS DeviceRelations;
4474 NTSTATUS Status;
4475
4476 IopCancelRemoveDevice(DeviceObject);
4477
4478 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4479
4480 Status = IopInitiatePnpIrp(DeviceObject,
4481 &IoStatusBlock,
4482 IRP_MN_QUERY_DEVICE_RELATIONS,
4483 &Stack);
4484 if (!NT_SUCCESS(Status))
4485 {
4486 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4487 DeviceRelations = NULL;
4488 }
4489 else
4490 {
4491 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4492 }
4493
4494 if (DeviceRelations)
4495 IopCancelRemoveDeviceRelations(DeviceRelations);
4496 }
4497
4498 NTSTATUS
4499 IopPrepareDeviceForRemoval(IN PDEVICE_OBJECT DeviceObject, BOOLEAN Force)
4500 {
4501 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4502 IO_STACK_LOCATION Stack;
4503 IO_STATUS_BLOCK IoStatusBlock;
4504 PDEVICE_RELATIONS DeviceRelations;
4505 NTSTATUS Status;
4506
4507 if ((DeviceNode->UserFlags & DNUF_NOT_DISABLEABLE) && !Force)
4508 {
4509 DPRINT1("Removal not allowed for %wZ\n", &DeviceNode->InstancePath);
4510 return STATUS_UNSUCCESSFUL;
4511 }
4512
4513 if (!Force && IopQueryRemoveDevice(DeviceObject) != STATUS_SUCCESS)
4514 {
4515 DPRINT1("Removal vetoed by failing the query remove request\n");
4516
4517 IopCancelRemoveDevice(DeviceObject);
4518
4519 return STATUS_UNSUCCESSFUL;
4520 }
4521
4522 Stack.Parameters.QueryDeviceRelations.Type = RemovalRelations;
4523
4524 Status = IopInitiatePnpIrp(DeviceObject,
4525 &IoStatusBlock,
4526 IRP_MN_QUERY_DEVICE_RELATIONS,
4527 &Stack);
4528 if (!NT_SUCCESS(Status))
4529 {
4530 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4531 DeviceRelations = NULL;
4532 }
4533 else
4534 {
4535 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4536 }
4537
4538 if (DeviceRelations)
4539 {
4540 Status = IopQueryRemoveDeviceRelations(DeviceRelations, Force);
4541 if (!NT_SUCCESS(Status))
4542 return Status;
4543 }
4544
4545 Status = IopQueryRemoveChildDevices(DeviceNode, Force);
4546 if (!NT_SUCCESS(Status))
4547 {
4548 if (DeviceRelations)
4549 IopCancelRemoveDeviceRelations(DeviceRelations);
4550 return Status;
4551 }
4552
4553 DeviceNode->Flags |= DNF_WILL_BE_REMOVED;
4554 if (DeviceRelations)
4555 IopSendRemoveDeviceRelations(DeviceRelations);
4556 IopSendRemoveChildDevices(DeviceNode);
4557
4558 return STATUS_SUCCESS;
4559 }
4560
4561 NTSTATUS
4562 IopRemoveDevice(PDEVICE_NODE DeviceNode)
4563 {
4564 NTSTATUS Status;
4565
4566 DPRINT("Removing device: %wZ\n", &DeviceNode->InstancePath);
4567
4568 Status = IopPrepareDeviceForRemoval(DeviceNode->PhysicalDeviceObject, FALSE);
4569 if (NT_SUCCESS(Status))
4570 {
4571 IopSendRemoveDevice(DeviceNode->PhysicalDeviceObject);
4572 IopQueueTargetDeviceEvent(&GUID_DEVICE_SAFE_REMOVAL,
4573 &DeviceNode->InstancePath);
4574 return STATUS_SUCCESS;
4575 }
4576
4577 return Status;
4578 }
4579
4580 /*
4581 * @implemented
4582 */
4583 VOID
4584 NTAPI
4585 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4586 {
4587 PDEVICE_NODE DeviceNode = IopGetDeviceNode(PhysicalDeviceObject);
4588 PDEVICE_RELATIONS DeviceRelations;
4589 IO_STATUS_BLOCK IoStatusBlock;
4590 IO_STACK_LOCATION Stack;
4591 DEVICE_CAPABILITIES Capabilities;
4592 NTSTATUS Status;
4593
4594 IopQueueTargetDeviceEvent(&GUID_DEVICE_KERNEL_INITIATED_EJECT,
4595 &DeviceNode->InstancePath);
4596
4597 if (IopQueryDeviceCapabilities(DeviceNode, &Capabilities) != STATUS_SUCCESS)
4598 {
4599 goto cleanup;
4600 }
4601
4602 Stack.Parameters.QueryDeviceRelations.Type = EjectionRelations;
4603
4604 Status = IopInitiatePnpIrp(PhysicalDeviceObject,
4605 &IoStatusBlock,
4606 IRP_MN_QUERY_DEVICE_RELATIONS,
4607 &Stack);
4608 if (!NT_SUCCESS(Status))
4609 {
4610 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
4611 DeviceRelations = NULL;
4612 }
4613 else
4614 {
4615 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
4616 }
4617
4618 if (DeviceRelations)
4619 {
4620 Status = IopQueryRemoveDeviceRelations(DeviceRelations, FALSE);
4621 if (!NT_SUCCESS(Status))
4622 goto cleanup;
4623 }
4624
4625 Status = IopQueryRemoveChildDevices(DeviceNode, FALSE);
4626 if (!NT_SUCCESS(Status))
4627 {
4628 if (DeviceRelations)
4629 IopCancelRemoveDeviceRelations(DeviceRelations);
4630 goto cleanup;
4631 }
4632
4633 if (IopPrepareDeviceForRemoval(PhysicalDeviceObject, FALSE) != STATUS_SUCCESS)
4634 {
4635 if (DeviceRelations)
4636 IopCancelRemoveDeviceRelations(DeviceRelations);
4637 IopCancelRemoveChildDevices(DeviceNode);
4638 goto cleanup;
4639 }
4640
4641 if (DeviceRelations)
4642 IopSendRemoveDeviceRelations(DeviceRelations);
4643 IopSendRemoveChildDevices(DeviceNode);
4644
4645 if (Capabilities.EjectSupported)
4646 {
4647 if (IopSendEject(PhysicalDeviceObject) != STATUS_SUCCESS)
4648 {
4649 goto cleanup;
4650 }
4651 }
4652 else
4653 {
4654 DeviceNode->Flags |= DNF_DISABLED;
4655 }
4656
4657 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT,
4658 &DeviceNode->InstancePath);
4659
4660 return;
4661
4662 cleanup:
4663 IopQueueTargetDeviceEvent(&GUID_DEVICE_EJECT_VETOED,
4664 &DeviceNode->InstancePath);
4665 }
4666
4667 /*
4668 * @implemented
4669 */
4670 VOID
4671 NTAPI
4672 IoInvalidateDeviceRelations(
4673 IN PDEVICE_OBJECT DeviceObject,
4674 IN DEVICE_RELATION_TYPE Type)
4675 {
4676 PIO_WORKITEM WorkItem;
4677 PINVALIDATE_DEVICE_RELATION_DATA Data;
4678
4679 Data = ExAllocatePool(NonPagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
4680 if (!Data)
4681 return;
4682 WorkItem = IoAllocateWorkItem(DeviceObject);
4683 if (!WorkItem)
4684 {
4685 ExFreePool(Data);
4686 return;
4687 }
4688
4689 ObReferenceObject(DeviceObject);
4690 Data->DeviceObject = DeviceObject;
4691 Data->Type = Type;
4692 Data->WorkItem = WorkItem;
4693
4694 IoQueueWorkItem(
4695 WorkItem,
4696 IopAsynchronousInvalidateDeviceRelations,
4697 DelayedWorkQueue,
4698 Data);
4699 }
4700
4701 /*
4702 * @implemented
4703 */
4704 NTSTATUS
4705 NTAPI
4706 IoSynchronousInvalidateDeviceRelations(
4707 IN PDEVICE_OBJECT DeviceObject,
4708 IN DEVICE_RELATION_TYPE Type)
4709 {
4710 PAGED_CODE();
4711
4712 switch (Type)
4713 {
4714 case BusRelations:
4715 /* Enumerate the device */
4716 return IopEnumerateDevice(DeviceObject);
4717 case PowerRelations:
4718 /* Not handled yet */
4719 return STATUS_NOT_IMPLEMENTED;
4720 case TargetDeviceRelation:
4721 /* Nothing to do */
4722 return STATUS_SUCCESS;
4723 default:
4724 /* Ejection relations are not supported */
4725 return STATUS_NOT_SUPPORTED;
4726 }
4727 }
4728
4729 /*
4730 * @implemented
4731 */
4732 BOOLEAN
4733 NTAPI
4734 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4735 IN ULONG BusNumber,
4736 IN PHYSICAL_ADDRESS BusAddress,
4737 IN OUT PULONG AddressSpace,
4738 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4739 {
4740 /* FIXME: Notify the resource arbiter */
4741
4742 return HalTranslateBusAddress(InterfaceType,
4743 BusNumber,
4744 BusAddress,
4745 AddressSpace,
4746 TranslatedAddress);
4747 }