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