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