- Export the InitSafeBootMode variable as per KB83764.
[reactos.git] / reactos / ntoskrnl / io / pnpmgr.c
1 /* $Id: pnpmgr.c,v 1.49 2004/11/07 22:55:38 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
6 * PURPOSE: Initializes the PnP manager
7 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * 16/04/2001 CSH Created
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #include <ole32/guiddef.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* GLOBALS *******************************************************************/
21
22 PDEVICE_NODE IopRootDeviceNode;
23 KSPIN_LOCK IopDeviceTreeLock;
24
25 /* DATA **********************************************************************/
26
27 PDRIVER_OBJECT IopRootDriverObject;
28
29 /* FUNCTIONS *****************************************************************/
30
31 /*
32 * @unimplemented
33 */
34 VOID
35 STDCALL
36 IoInvalidateDeviceRelations(
37 IN PDEVICE_OBJECT DeviceObject,
38 IN DEVICE_RELATION_TYPE Type)
39 {
40 CHECKPOINT1;
41 }
42
43 PDEVICE_NODE FASTCALL
44 IopGetDeviceNode(
45 PDEVICE_OBJECT DeviceObject)
46 {
47 return DeviceObject->DeviceObjectExtension->DeviceNode;
48 }
49
50 /*
51 * @unimplemented
52 */
53 NTSTATUS
54 STDCALL
55 IoGetDeviceProperty(
56 IN PDEVICE_OBJECT DeviceObject,
57 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
58 IN ULONG BufferLength,
59 OUT PVOID PropertyBuffer,
60 OUT PULONG ResultLength)
61 {
62 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
63 ULONG Length;
64 PVOID Data;
65 PWSTR Ptr;
66
67 DPRINT("IoGetDeviceProperty(%x %d)\n", DeviceObject, DeviceProperty);
68
69 if (DeviceNode == NULL)
70 return STATUS_INVALID_DEVICE_REQUEST;
71
72 switch (DeviceProperty)
73 {
74 case DevicePropertyBusNumber:
75 Length = sizeof(ULONG);
76 Data = &DeviceNode->ChildBusNumber;
77 break;
78
79 /* Complete, untested */
80 case DevicePropertyBusTypeGuid:
81 *ResultLength = 39 * sizeof(WCHAR);
82 if (BufferLength < (39 * sizeof(WCHAR)))
83 return STATUS_BUFFER_TOO_SMALL;
84 swprintf((PWSTR)PropertyBuffer,
85 L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
86 DeviceNode->BusTypeGuid.Data1,
87 DeviceNode->BusTypeGuid.Data2,
88 DeviceNode->BusTypeGuid.Data3,
89 DeviceNode->BusTypeGuid.Data4[0],
90 DeviceNode->BusTypeGuid.Data4[1],
91 DeviceNode->BusTypeGuid.Data4[2],
92 DeviceNode->BusTypeGuid.Data4[3],
93 DeviceNode->BusTypeGuid.Data4[4],
94 DeviceNode->BusTypeGuid.Data4[5],
95 DeviceNode->BusTypeGuid.Data4[6],
96 DeviceNode->BusTypeGuid.Data4[7]);
97 return STATUS_SUCCESS;
98
99 case DevicePropertyLegacyBusType:
100 Length = sizeof(INTERFACE_TYPE);
101 Data = &DeviceNode->ChildInterfaceType;
102 break;
103
104 case DevicePropertyAddress:
105 Length = sizeof(ULONG);
106 Data = &DeviceNode->Address;
107 break;
108
109 // case DevicePropertyUINumber:
110 // if (DeviceNode->CapabilityFlags == NULL)
111 // return STATUS_INVALID_DEVICE_REQUEST;
112 // Length = sizeof(ULONG);
113 // Data = &DeviceNode->CapabilityFlags->UINumber;
114 // break;
115
116 case DevicePropertyClassName:
117 case DevicePropertyClassGuid:
118 case DevicePropertyDriverKeyName:
119 case DevicePropertyManufacturer:
120 case DevicePropertyFriendlyName:
121 case DevicePropertyHardwareID:
122 case DevicePropertyCompatibleIDs:
123 case DevicePropertyDeviceDescription:
124 case DevicePropertyLocationInformation:
125 case DevicePropertyUINumber:
126 {
127 LPWSTR RegistryPropertyName, KeyNameBuffer;
128 UNICODE_STRING KeyName, ValueName;
129 OBJECT_ATTRIBUTES ObjectAttributes;
130 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
131 ULONG ValueInformationLength;
132 HANDLE KeyHandle;
133 NTSTATUS Status;
134
135 switch (DeviceProperty)
136 {
137 case DevicePropertyClassName:
138 RegistryPropertyName = L"Class"; break;
139 case DevicePropertyClassGuid:
140 RegistryPropertyName = L"ClassGuid"; break;
141 case DevicePropertyDriverKeyName:
142 RegistryPropertyName = L"Driver"; break;
143 case DevicePropertyManufacturer:
144 RegistryPropertyName = L"Mfg"; break;
145 case DevicePropertyFriendlyName:
146 RegistryPropertyName = L"FriendlyName"; break;
147 case DevicePropertyHardwareID:
148 RegistryPropertyName = L"HardwareID"; break;
149 case DevicePropertyCompatibleIDs:
150 RegistryPropertyName = L"CompatibleIDs"; break;
151 case DevicePropertyDeviceDescription:
152 RegistryPropertyName = L"DeviceDesc"; break;
153 case DevicePropertyLocationInformation:
154 RegistryPropertyName = L"LocationInformation"; break;
155 case DevicePropertyUINumber:
156 RegistryPropertyName = L"UINumber"; break;
157 default:
158 RegistryPropertyName = NULL; break;
159 }
160
161 KeyNameBuffer = ExAllocatePool(PagedPool,
162 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
163
164 DPRINT1("KeyNameBuffer: %x, value %S\n",
165 KeyNameBuffer, RegistryPropertyName);
166
167 if (KeyNameBuffer == NULL)
168 return STATUS_INSUFFICIENT_RESOURCES;
169
170 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
171 wcscat(KeyNameBuffer, DeviceNode->InstancePath.Buffer);
172 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
173 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
174 OBJ_CASE_INSENSITIVE, NULL, NULL);
175
176 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
177 ExFreePool(KeyNameBuffer);
178 if (!NT_SUCCESS(Status))
179 return Status;
180
181 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
182 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
183 Data[0]) + BufferLength;
184 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
185 if (ValueInformation == NULL)
186 {
187 ZwClose(KeyHandle);
188 return STATUS_INSUFFICIENT_RESOURCES;
189 }
190
191 Status = ZwQueryValueKey(KeyHandle, &ValueName,
192 KeyValuePartialInformation, ValueInformation,
193 ValueInformationLength,
194 &ValueInformationLength);
195 *ResultLength = ValueInformation->DataLength;
196 ZwClose(KeyHandle);
197
198 if (ValueInformation->DataLength > BufferLength)
199 Status = STATUS_BUFFER_TOO_SMALL;
200
201 if (!NT_SUCCESS(Status))
202 {
203 ExFreePool(ValueInformation);
204 return Status;
205 }
206
207 /* FIXME: Verify the value (NULL-terminated, correct format). */
208
209 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
210 ValueInformation->DataLength);
211 ExFreePool(ValueInformation);
212
213 return STATUS_SUCCESS;
214 }
215
216 case DevicePropertyBootConfiguration:
217 Length = 0;
218 if (DeviceNode->BootResources->Count != 0)
219 {
220 Length = FIELD_OFFSET(CM_RESOURCE_LIST, List) +
221 DeviceNode->BootResources->Count * sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
222 }
223 Data = &DeviceNode->BootResources;
224 break;
225
226 /* FIXME: use a translated boot configuration instead */
227 case DevicePropertyBootConfigurationTranslated:
228 Length = 0;
229 if (DeviceNode->BootResources->Count != 0)
230 {
231 Length = FIELD_OFFSET(CM_RESOURCE_LIST, List) +
232 DeviceNode->BootResources->Count * sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
233 }
234 Data = &DeviceNode->BootResources;
235 break;
236
237 case DevicePropertyEnumeratorName:
238 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
239 if (Ptr != NULL)
240 {
241 Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR);
242 }
243 else
244 {
245 Length = 0;
246 Data = NULL;
247 }
248
249 case DevicePropertyPhysicalDeviceObjectName:
250 return STATUS_NOT_IMPLEMENTED;
251
252 default:
253 return STATUS_INVALID_PARAMETER_2;
254 }
255
256 *ResultLength = Length;
257 if (BufferLength < Length)
258 return STATUS_BUFFER_TOO_SMALL;
259 RtlCopyMemory(PropertyBuffer, Data, Length);
260
261 /* Terminate the string */
262 if (DeviceProperty == DevicePropertyEnumeratorName)
263 {
264 Ptr = (PWSTR)PropertyBuffer;
265 Ptr[(Length / sizeof(WCHAR)) - 1] = 0;
266 }
267
268 return STATUS_SUCCESS;
269 }
270
271 /*
272 * @unimplemented
273 */
274 VOID
275 STDCALL
276 IoInvalidateDeviceState(
277 IN PDEVICE_OBJECT PhysicalDeviceObject)
278 {
279 }
280
281 /**
282 * @name IoOpenDeviceRegistryKey
283 *
284 * Open a registry key unique for a specified driver or device instance.
285 *
286 * @param DeviceObject Device to get the registry key for.
287 * @param DevInstKeyType Type of the key to return.
288 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
289 * @param DevInstRegKey Handle to the opened registry key on
290 * successful return.
291 *
292 * @return Status.
293 *
294 * @implemented
295 */
296 NTSTATUS
297 STDCALL
298 IoOpenDeviceRegistryKey(
299 IN PDEVICE_OBJECT DeviceObject,
300 IN ULONG DevInstKeyType,
301 IN ACCESS_MASK DesiredAccess,
302 OUT PHANDLE DevInstRegKey)
303 {
304 static WCHAR RootKeyName[] =
305 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
306 static WCHAR ProfileKeyName[] =
307 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
308 static WCHAR ClassKeyName[] = L"Control\\Class\\";
309 static WCHAR EnumKeyName[] = L"Enum\\";
310 static WCHAR DeviceParametersKeyName[] = L"Device Parameters\\";
311 ULONG KeyNameLength;
312 LPWSTR KeyNameBuffer;
313 UNICODE_STRING KeyName;
314 ULONG DriverKeyLength;
315 OBJECT_ATTRIBUTES ObjectAttributes;
316 PDEVICE_NODE DeviceNode = NULL;
317 NTSTATUS Status;
318
319 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
320 return STATUS_INVALID_PARAMETER;
321
322 /*
323 * Calculate the length of the base key name. This is the full
324 * name for driver key or the name excluding "Device Parameters"
325 * subkey for device key.
326 */
327
328 KeyNameLength = sizeof(RootKeyName);
329 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
330 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
331 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
332 {
333 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
334 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
335 0, NULL, &DriverKeyLength);
336 if (Status != STATUS_BUFFER_TOO_SMALL)
337 return Status;
338 KeyNameLength += DriverKeyLength;
339 }
340 else
341 {
342 DeviceNode = IopGetDeviceNode(DeviceObject);
343 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
344 DeviceNode->InstancePath.Length;
345 }
346
347 /*
348 * Now allocate the buffer for the key name...
349 */
350
351 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
352 if (KeyNameBuffer == NULL)
353 return STATUS_INSUFFICIENT_RESOURCES;
354
355 KeyName.Length = 0;
356 KeyName.MaximumLength = KeyNameLength;
357 KeyName.Buffer = KeyNameBuffer;
358
359 /*
360 * ...and build the key name.
361 */
362
363 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
364 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
365
366 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
367 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
368
369 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
370 {
371 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
372 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
373 DriverKeyLength, KeyNameBuffer +
374 (KeyName.Length / sizeof(WCHAR)),
375 &DriverKeyLength);
376 if (!NT_SUCCESS(Status))
377 {
378 ExFreePool(KeyNameBuffer);
379 return Status;
380 }
381 KeyName.Length += DriverKeyLength - sizeof(UNICODE_NULL);
382 }
383 else
384 {
385 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
386 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
387 if (DeviceNode->InstancePath.Length == 0)
388 {
389 ExFreePool(KeyNameBuffer);
390 return Status;
391 }
392 }
393
394 /*
395 * Open the base key.
396 */
397
398 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
399 OBJ_CASE_INSENSITIVE, NULL, NULL);
400 Status = ZwOpenKey(DevInstRegKey, DesiredAccess, &ObjectAttributes);
401 ExFreePool(KeyNameBuffer);
402
403 /*
404 * For driver key we're done now. Also if the base key doesn't
405 * exist we can bail out with error...
406 */
407
408 if ((DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) || !NT_SUCCESS(Status))
409 return Status;
410
411 /*
412 * Let's go further. For device key we must open "Device Parameters"
413 * subkey and create it if it doesn't exist yet.
414 */
415
416 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
417 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
418 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
419 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
420 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
421 ZwClose(ObjectAttributes.RootDirectory);
422
423 return Status;
424 }
425
426 /*
427 * @unimplemented
428 */
429 VOID
430 STDCALL
431 IoRequestDeviceEject(
432 IN PDEVICE_OBJECT PhysicalDeviceObject
433 )
434 {
435 UNIMPLEMENTED;
436 }
437
438
439 BOOLEAN
440 IopCreateUnicodeString(
441 PUNICODE_STRING Destination,
442 PWSTR Source,
443 POOL_TYPE PoolType)
444 {
445 ULONG Length;
446
447 if (!Source)
448 {
449 RtlInitUnicodeString(Destination, NULL);
450 return TRUE;
451 }
452
453 Length = (wcslen(Source) + 1) * sizeof(WCHAR);
454
455 Destination->Buffer = ExAllocatePool(PoolType, Length);
456
457 if (Destination->Buffer == NULL)
458 {
459 return FALSE;
460 }
461
462 RtlCopyMemory(Destination->Buffer, Source, Length);
463
464 Destination->MaximumLength = Length;
465
466 Destination->Length = Length - sizeof(WCHAR);
467
468 return TRUE;
469 }
470
471 NTSTATUS
472 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
473 {
474 KIRQL OldIrql;
475
476 if (PopSystemPowerDeviceNode)
477 {
478 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
479 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
480 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
481
482 return STATUS_SUCCESS;
483 }
484
485 return STATUS_UNSUCCESSFUL;
486 }
487
488 /**********************************************************************
489 * DESCRIPTION
490 * Creates a device node
491 *
492 * ARGUMENTS
493 * ParentNode = Pointer to parent device node
494 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
495 * to have the root device node create one
496 * (eg. for legacy drivers)
497 * DeviceNode = Pointer to storage for created device node
498 *
499 * RETURN VALUE
500 * Status
501 */
502 NTSTATUS
503 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
504 PDEVICE_OBJECT PhysicalDeviceObject,
505 PDEVICE_NODE *DeviceNode)
506 {
507 PDEVICE_NODE Node;
508 NTSTATUS Status;
509 KIRQL OldIrql;
510
511 DPRINT("ParentNode %x PhysicalDeviceObject %x\n",
512 ParentNode, PhysicalDeviceObject);
513
514 Node = (PDEVICE_NODE)ExAllocatePool(PagedPool, sizeof(DEVICE_NODE));
515 if (!Node)
516 {
517 return STATUS_INSUFFICIENT_RESOURCES;
518 }
519
520 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
521
522 if (!PhysicalDeviceObject)
523 {
524 Status = PnpRootCreateDevice(&PhysicalDeviceObject);
525 if (!NT_SUCCESS(Status))
526 {
527 ExFreePool(Node);
528 return Status;
529 }
530
531 /* This is for drivers passed on the command line to ntoskrnl.exe */
532 IopDeviceNodeSetFlag(Node, DNF_STARTED);
533 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
534 }
535
536 Node->PhysicalDeviceObject = PhysicalDeviceObject;
537
538 PhysicalDeviceObject->DeviceObjectExtension->DeviceNode = Node;
539
540 if (ParentNode)
541 {
542 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
543 Node->Parent = ParentNode;
544 Node->NextSibling = ParentNode->Child;
545 if (ParentNode->Child != NULL)
546 {
547 ParentNode->Child->PrevSibling = Node;
548 }
549 ParentNode->Child = Node;
550 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
551 }
552
553 *DeviceNode = Node;
554
555 return STATUS_SUCCESS;
556 }
557
558 NTSTATUS
559 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
560 {
561 KIRQL OldIrql;
562
563 /* All children must be deleted before a parent is deleted */
564 ASSERT(!DeviceNode->Child);
565
566 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
567
568 ASSERT(DeviceNode->PhysicalDeviceObject);
569
570 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
571
572 /* Unlink from parent if it exists */
573
574 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
575 {
576 DeviceNode->Parent->Child = DeviceNode->NextSibling;
577 }
578
579 /* Unlink from sibling list */
580
581 if (DeviceNode->PrevSibling)
582 {
583 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
584 }
585
586 if (DeviceNode->NextSibling)
587 {
588 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
589 }
590
591 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
592
593 RtlFreeUnicodeString(&DeviceNode->InstancePath);
594
595 RtlFreeUnicodeString(&DeviceNode->ServiceName);
596
597 if (DeviceNode->ResourceList)
598 {
599 ExFreePool(DeviceNode->ResourceList);
600 }
601
602 if (DeviceNode->ResourceListTranslated)
603 {
604 ExFreePool(DeviceNode->ResourceListTranslated);
605 }
606
607 if (DeviceNode->ResourceRequirements)
608 {
609 ExFreePool(DeviceNode->ResourceRequirements);
610 }
611
612 if (DeviceNode->BootResources)
613 {
614 ExFreePool(DeviceNode->BootResources);
615 }
616
617 ExFreePool(DeviceNode);
618
619 return STATUS_SUCCESS;
620 }
621
622 NTSTATUS
623 IopInitiatePnpIrp(
624 PDEVICE_OBJECT DeviceObject,
625 PIO_STATUS_BLOCK IoStatusBlock,
626 ULONG MinorFunction,
627 PIO_STACK_LOCATION Stack OPTIONAL)
628 {
629 PDEVICE_OBJECT TopDeviceObject;
630 PIO_STACK_LOCATION IrpSp;
631 NTSTATUS Status;
632 KEVENT Event;
633 PIRP Irp;
634
635 /* Always call the top of the device stack */
636 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
637
638 KeInitializeEvent(
639 &Event,
640 NotificationEvent,
641 FALSE);
642
643 Irp = IoBuildSynchronousFsdRequest(
644 IRP_MJ_PNP,
645 TopDeviceObject,
646 NULL,
647 0,
648 NULL,
649 &Event,
650 IoStatusBlock);
651
652 /* PNP IRPs are always initialized with a status code of
653 STATUS_NOT_IMPLEMENTED */
654 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
655 Irp->IoStatus.Information = 0;
656
657 IrpSp = IoGetNextIrpStackLocation(Irp);
658 IrpSp->MinorFunction = MinorFunction;
659
660 if (Stack)
661 {
662 RtlMoveMemory(
663 &IrpSp->Parameters,
664 &Stack->Parameters,
665 sizeof(Stack->Parameters));
666 }
667
668 Status = IoCallDriver(TopDeviceObject, Irp);
669 if (Status == STATUS_PENDING)
670 {
671 KeWaitForSingleObject(
672 &Event,
673 Executive,
674 KernelMode,
675 FALSE,
676 NULL);
677 Status = IoStatusBlock->Status;
678 }
679
680 ObDereferenceObject(TopDeviceObject);
681
682 return Status;
683 }
684
685
686 NTSTATUS
687 IopTraverseDeviceTreeNode(
688 PDEVICETREE_TRAVERSE_CONTEXT Context)
689 {
690 PDEVICE_NODE ParentDeviceNode;
691 PDEVICE_NODE ChildDeviceNode;
692 NTSTATUS Status;
693
694 /* Copy context data so we don't overwrite it in subsequent calls to this function */
695 ParentDeviceNode = Context->DeviceNode;
696
697 /* Call the action routine */
698 Status = (Context->Action)(ParentDeviceNode, Context->Context);
699 if (!NT_SUCCESS(Status))
700 {
701 return Status;
702 }
703
704 /* Traversal of all children nodes */
705 for (ChildDeviceNode = ParentDeviceNode->Child;
706 ChildDeviceNode != NULL;
707 ChildDeviceNode = ChildDeviceNode->NextSibling)
708 {
709 /* Pass the current device node to the action routine */
710 Context->DeviceNode = ChildDeviceNode;
711
712 Status = IopTraverseDeviceTreeNode(Context);
713 if (!NT_SUCCESS(Status))
714 {
715 return Status;
716 }
717 }
718
719 return Status;
720 }
721
722
723 NTSTATUS
724 IopTraverseDeviceTree(
725 PDEVICETREE_TRAVERSE_CONTEXT Context)
726 {
727 NTSTATUS Status;
728
729 DPRINT("Context %x\n", Context);
730
731 DPRINT("IopTraverseDeviceTree(DeviceNode %x FirstDeviceNode %x Action %x Context %x)\n",
732 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
733
734 /* Start from the specified device node */
735 Context->DeviceNode = Context->FirstDeviceNode;
736
737 /* Recursively traverse the device tree */
738 Status = IopTraverseDeviceTreeNode(Context);
739 if (Status == STATUS_UNSUCCESSFUL)
740 {
741 /* The action routine just wanted to terminate the traversal with status
742 code STATUS_SUCCESS */
743 Status = STATUS_SUCCESS;
744 }
745
746 return Status;
747 }
748
749
750 static NTSTATUS
751 IopCreateDeviceKeyPath(PWSTR Path,
752 PHANDLE Handle)
753 {
754 OBJECT_ATTRIBUTES ObjectAttributes;
755 WCHAR KeyBuffer[MAX_PATH];
756 UNICODE_STRING KeyName;
757 HANDLE KeyHandle;
758 NTSTATUS Status;
759 PWCHAR Current;
760 PWCHAR Next;
761
762 *Handle = NULL;
763
764 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
765 {
766 return STATUS_INVALID_PARAMETER;
767 }
768
769 wcsncpy (KeyBuffer, Path, MAX_PATH-1);
770 RtlInitUnicodeString (&KeyName, KeyBuffer);
771
772 /* Skip \\Registry\\ */
773 Current = KeyName.Buffer;
774 Current = wcschr (Current, '\\') + 1;
775 Current = wcschr (Current, '\\') + 1;
776
777 while (TRUE)
778 {
779 Next = wcschr (Current, '\\');
780 if (Next == NULL)
781 {
782 /* The end */
783 }
784 else
785 {
786 *Next = 0;
787 }
788
789 InitializeObjectAttributes (&ObjectAttributes,
790 &KeyName,
791 OBJ_CASE_INSENSITIVE,
792 NULL,
793 NULL);
794
795 DPRINT("Create '%S'\n", KeyName.Buffer);
796
797 Status = NtCreateKey (&KeyHandle,
798 KEY_ALL_ACCESS,
799 &ObjectAttributes,
800 0,
801 NULL,
802 0,
803 NULL);
804 if (!NT_SUCCESS (Status))
805 {
806 DPRINT ("NtCreateKey() failed with status %x\n", Status);
807 return Status;
808 }
809
810 if (Next == NULL)
811 {
812 *Handle = KeyHandle;
813 return STATUS_SUCCESS;
814 }
815 else
816 {
817 NtClose (KeyHandle);
818 *Next = L'\\';
819 }
820
821 Current = Next + 1;
822 }
823
824 return STATUS_UNSUCCESSFUL;
825 }
826
827
828 static NTSTATUS
829 IopSetDeviceInstanceData(HANDLE InstanceKey,
830 PDEVICE_NODE DeviceNode)
831 {
832 OBJECT_ATTRIBUTES ObjectAttributes;
833 UNICODE_STRING KeyName;
834 HANDLE LogConfKey;
835 ULONG ResCount;
836 ULONG ListSize;
837 NTSTATUS Status;
838
839 DPRINT("IopSetDeviceInstanceData() called\n");
840
841 /* Create the 'LogConf' key */
842 RtlInitUnicodeString(&KeyName,
843 L"LogConf");
844 InitializeObjectAttributes(&ObjectAttributes,
845 &KeyName,
846 OBJ_CASE_INSENSITIVE,
847 InstanceKey,
848 NULL);
849 Status = NtCreateKey(&LogConfKey,
850 KEY_ALL_ACCESS,
851 &ObjectAttributes,
852 0,
853 NULL,
854 0,
855 NULL);
856 if (NT_SUCCESS(Status))
857 {
858 /* Set 'BootConfig' value */
859 if (DeviceNode->BootResources != NULL)
860 {
861 ResCount = DeviceNode->BootResources->Count;
862 if (ResCount != 0)
863 {
864 ListSize = sizeof(CM_RESOURCE_LIST) +
865 ((ResCount - 1) * sizeof(CM_FULL_RESOURCE_DESCRIPTOR));
866
867 RtlInitUnicodeString(&KeyName,
868 L"BootConfig");
869 Status = NtSetValueKey(LogConfKey,
870 &KeyName,
871 0,
872 REG_RESOURCE_LIST,
873 &DeviceNode->BootResources,
874 ListSize);
875 }
876 }
877
878 /* Set 'BasicConfigVector' value */
879 if (DeviceNode->ResourceRequirements != NULL &&
880 DeviceNode->ResourceRequirements->ListSize != 0)
881 {
882 RtlInitUnicodeString(&KeyName,
883 L"BasicConfigVector");
884 Status = NtSetValueKey(LogConfKey,
885 &KeyName,
886 0,
887 REG_RESOURCE_REQUIREMENTS_LIST,
888 &DeviceNode->ResourceRequirements,
889 DeviceNode->ResourceRequirements->ListSize);
890 }
891
892 NtClose(LogConfKey);
893 }
894
895 DPRINT("IopSetDeviceInstanceData() done\n");
896
897 return STATUS_SUCCESS;
898 }
899
900
901 /*
902 * IopActionInterrogateDeviceStack
903 *
904 * Retrieve information for all (direct) child nodes of a parent node.
905 *
906 * Parameters
907 * DeviceNode
908 * Pointer to device node.
909 * Context
910 * Pointer to parent node to retrieve child node information for.
911 *
912 * Remarks
913 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
914 * when we reach a device node which is not a direct child of the device
915 * node for which we retrieve information of child nodes for. Any errors
916 * that occur is logged instead so that all child services have a chance
917 * of being interrogated.
918 */
919
920 NTSTATUS
921 IopActionInterrogateDeviceStack(
922 PDEVICE_NODE DeviceNode,
923 PVOID Context)
924 {
925 IO_STATUS_BLOCK IoStatusBlock;
926 PDEVICE_NODE ParentDeviceNode;
927 WCHAR InstancePath[MAX_PATH];
928 IO_STACK_LOCATION Stack;
929 NTSTATUS Status;
930 PWSTR KeyBuffer;
931 PWSTR Ptr;
932 USHORT Length;
933 USHORT TotalLength;
934 HANDLE InstanceKey = NULL;
935 UNICODE_STRING ValueName;
936 DEVICE_CAPABILITIES DeviceCapabilities;
937
938 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
939 DPRINT("PDO %x\n", DeviceNode->PhysicalDeviceObject);
940
941 ParentDeviceNode = (PDEVICE_NODE)Context;
942
943 /*
944 * We are called for the parent too, but we don't need to do special
945 * handling for this node
946 */
947
948 if (DeviceNode == ParentDeviceNode)
949 {
950 DPRINT("Success\n");
951 return STATUS_SUCCESS;
952 }
953
954 /*
955 * Make sure this device node is a direct child of the parent device node
956 * that is given as an argument
957 */
958
959 if (DeviceNode->Parent != ParentDeviceNode)
960 {
961 /* Stop the traversal immediately and indicate successful operation */
962 DPRINT("Stop\n");
963 return STATUS_UNSUCCESSFUL;
964 }
965
966 /*
967 * FIXME: For critical errors, cleanup and disable device, but always
968 * return STATUS_SUCCESS.
969 */
970
971 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
972
973 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
974 Status = IopInitiatePnpIrp(
975 DeviceNode->PhysicalDeviceObject,
976 &IoStatusBlock,
977 IRP_MN_QUERY_ID,
978 &Stack);
979 if (NT_SUCCESS(Status))
980 {
981 /* Copy the device id string */
982 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
983
984 /*
985 * FIXME: Check for valid characters, if there is invalid characters
986 * then bugcheck.
987 */
988 }
989 else
990 {
991 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
992 }
993
994 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
995
996 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
997 Status = IopInitiatePnpIrp(
998 DeviceNode->PhysicalDeviceObject,
999 &IoStatusBlock,
1000 IRP_MN_QUERY_ID,
1001 &Stack);
1002 if (NT_SUCCESS(Status))
1003 {
1004 /* Append the instance id string */
1005 wcscat(InstancePath, L"\\");
1006 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1007
1008 /*
1009 * FIXME: Check for valid characters, if there is invalid characters
1010 * then bugcheck
1011 */
1012 }
1013 else
1014 {
1015 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1016 }
1017
1018 RtlZeroMemory(&DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
1019 DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
1020 DeviceCapabilities.Version = 1;
1021 DeviceCapabilities.Address = -1;
1022 DeviceCapabilities.UINumber = -1;
1023
1024 Stack.Parameters.DeviceCapabilities.Capabilities = &DeviceCapabilities;
1025 Status = IopInitiatePnpIrp(
1026 DeviceNode->PhysicalDeviceObject,
1027 &IoStatusBlock,
1028 IRP_MN_QUERY_CAPABILITIES,
1029 &Stack);
1030 if (NT_SUCCESS(Status))
1031 {
1032 }
1033 else
1034 {
1035 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1036 }
1037
1038 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1039 DeviceNode->Address = DeviceCapabilities.Address;
1040
1041 if (!DeviceCapabilities.UniqueID)
1042 {
1043 DPRINT("Instance ID is not unique\n");
1044 /* FIXME: Add information from parent bus driver to InstancePath */
1045 }
1046
1047 if (!IopCreateUnicodeString(&DeviceNode->InstancePath, InstancePath, PagedPool))
1048 {
1049 DPRINT("No resources\n");
1050 /* FIXME: Cleanup and disable device */
1051 }
1052
1053 DPRINT1("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1054
1055 /*
1056 * Create registry key for the instance id, if it doesn't exist yet
1057 */
1058 KeyBuffer = ExAllocatePool(
1059 PagedPool,
1060 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
1061 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1062 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
1063 Status = IopCreateDeviceKeyPath(KeyBuffer,
1064 &InstanceKey);
1065 ExFreePool(KeyBuffer);
1066 if (!NT_SUCCESS(Status))
1067 {
1068 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1069 }
1070
1071
1072 {
1073 /* Set 'Capabilities' value */
1074 RtlInitUnicodeString(&ValueName,
1075 L"Capabilities");
1076 Status = NtSetValueKey(InstanceKey,
1077 &ValueName,
1078 0,
1079 REG_DWORD,
1080 (PVOID)&DeviceNode->CapabilityFlags,
1081 sizeof(ULONG));
1082
1083 /* Set 'UINumber' value */
1084 if (DeviceCapabilities.UINumber != (ULONG)-1)
1085 {
1086 RtlInitUnicodeString(&ValueName,
1087 L"UINumber");
1088 Status = NtSetValueKey(InstanceKey,
1089 &ValueName,
1090 0,
1091 REG_DWORD,
1092 &DeviceCapabilities.UINumber,
1093 sizeof(ULONG));
1094 }
1095 }
1096
1097 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1098
1099 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1100 Status = IopInitiatePnpIrp(
1101 DeviceNode->PhysicalDeviceObject,
1102 &IoStatusBlock,
1103 IRP_MN_QUERY_ID,
1104 &Stack);
1105 if (NT_SUCCESS(Status))
1106 {
1107 /*
1108 * FIXME: Check for valid characters, if there is invalid characters
1109 * then bugcheck.
1110 */
1111 TotalLength = 0;
1112 Ptr = (PWSTR)IoStatusBlock.Information;
1113 DPRINT("Hardware IDs:\n");
1114 while (*Ptr)
1115 {
1116 DPRINT(" %S\n", Ptr);
1117 Length = wcslen(Ptr) + 1;
1118
1119 Ptr += Length;
1120 TotalLength += Length;
1121 }
1122 DPRINT("TotalLength: %hu\n", TotalLength);
1123 DPRINT("\n");
1124
1125 RtlInitUnicodeString(&ValueName,
1126 L"HardwareID");
1127 Status = NtSetValueKey(InstanceKey,
1128 &ValueName,
1129 0,
1130 REG_MULTI_SZ,
1131 (PVOID)IoStatusBlock.Information,
1132 (TotalLength + 1) * sizeof(WCHAR));
1133 if (!NT_SUCCESS(Status))
1134 {
1135 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1136 }
1137 }
1138 else
1139 {
1140 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1141 }
1142
1143 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1144
1145 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1146 Status = IopInitiatePnpIrp(
1147 DeviceNode->PhysicalDeviceObject,
1148 &IoStatusBlock,
1149 IRP_MN_QUERY_ID,
1150 &Stack);
1151 if (NT_SUCCESS(Status))
1152 {
1153 /*
1154 * FIXME: Check for valid characters, if there is invalid characters
1155 * then bugcheck.
1156 */
1157 TotalLength = 0;
1158 Ptr = (PWSTR)IoStatusBlock.Information;
1159 DPRINT("Compatible IDs:\n");
1160 while (*Ptr)
1161 {
1162 DPRINT(" %S\n", Ptr);
1163 Length = wcslen(Ptr) + 1;
1164
1165 Ptr += Length;
1166 TotalLength += Length;
1167 }
1168 DPRINT("TotalLength: %hu\n", TotalLength);
1169 DPRINT("\n");
1170
1171 RtlInitUnicodeString(&ValueName,
1172 L"CompatibleIDs");
1173 Status = NtSetValueKey(InstanceKey,
1174 &ValueName,
1175 0,
1176 REG_MULTI_SZ,
1177 (PVOID)IoStatusBlock.Information,
1178 (TotalLength + 1) * sizeof(WCHAR));
1179 if (!NT_SUCCESS(Status))
1180 {
1181 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1182 }
1183 }
1184 else
1185 {
1186 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1187 }
1188
1189
1190 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1191
1192 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1193 Stack.Parameters.QueryDeviceText.LocaleId = 0; /* FIXME */
1194 Status = IopInitiatePnpIrp(
1195 DeviceNode->PhysicalDeviceObject,
1196 &IoStatusBlock,
1197 IRP_MN_QUERY_DEVICE_TEXT,
1198 &Stack);
1199 if (NT_SUCCESS(Status))
1200 {
1201 RtlInitUnicodeString(&ValueName,
1202 L"DeviceDesc");
1203 Status = NtSetValueKey(InstanceKey,
1204 &ValueName,
1205 0,
1206 REG_SZ,
1207 (PVOID)IoStatusBlock.Information,
1208 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1209 if (!NT_SUCCESS(Status))
1210 {
1211 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1212 }
1213 }
1214 else
1215 {
1216 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1217 }
1218
1219 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1220
1221 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
1222 Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
1223 Status = IopInitiatePnpIrp(
1224 DeviceNode->PhysicalDeviceObject,
1225 &IoStatusBlock,
1226 IRP_MN_QUERY_DEVICE_TEXT,
1227 &Stack);
1228 if (NT_SUCCESS(Status))
1229 {
1230 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
1231 RtlInitUnicodeString(&ValueName,
1232 L"LocationInformation");
1233 Status = NtSetValueKey(InstanceKey,
1234 &ValueName,
1235 0,
1236 REG_SZ,
1237 (PVOID)IoStatusBlock.Information,
1238 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1239 if (!NT_SUCCESS(Status))
1240 {
1241 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
1242 }
1243 }
1244 else
1245 {
1246 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1247 }
1248
1249 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1250
1251 Status = IopInitiatePnpIrp(
1252 DeviceNode->PhysicalDeviceObject,
1253 &IoStatusBlock,
1254 IRP_MN_QUERY_BUS_INFORMATION,
1255 NULL);
1256 if (NT_SUCCESS(Status))
1257 {
1258 PPNP_BUS_INFORMATION BusInformation =
1259 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1260
1261 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1262 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1263 memcpy(&DeviceNode->BusTypeGuid,
1264 &BusInformation->BusTypeGuid,
1265 sizeof(GUID));
1266 ExFreePool(BusInformation);
1267 }
1268 else
1269 {
1270 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1271
1272 DeviceNode->ChildBusNumber = -1;
1273 DeviceNode->ChildInterfaceType = -1;
1274 memset(&DeviceNode->BusTypeGuid,
1275 0,
1276 sizeof(GUID));
1277 }
1278
1279 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1280
1281 Status = IopInitiatePnpIrp(
1282 DeviceNode->PhysicalDeviceObject,
1283 &IoStatusBlock,
1284 IRP_MN_QUERY_RESOURCES,
1285 NULL);
1286 if (NT_SUCCESS(Status))
1287 {
1288 DeviceNode->BootResources =
1289 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1290 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
1291 }
1292 else
1293 {
1294 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1295 DeviceNode->BootResources = NULL;
1296 }
1297
1298 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1299
1300 Status = IopInitiatePnpIrp(
1301 DeviceNode->PhysicalDeviceObject,
1302 &IoStatusBlock,
1303 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1304 NULL);
1305 if (NT_SUCCESS(Status))
1306 {
1307 DeviceNode->ResourceRequirements =
1308 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1309 }
1310 else
1311 {
1312 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1313 DeviceNode->ResourceRequirements = NULL;
1314 }
1315
1316
1317 if (InstanceKey != NULL)
1318 {
1319 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1320 }
1321
1322 NtClose(InstanceKey);
1323
1324 DeviceNode->Flags |= DNF_PROCESSED;
1325
1326 return STATUS_SUCCESS;
1327 }
1328
1329 /*
1330 * IopActionConfigureChildServices
1331 *
1332 * Retrieve configuration for all (direct) child nodes of a parent node.
1333 *
1334 * Parameters
1335 * DeviceNode
1336 * Pointer to device node.
1337 * Context
1338 * Pointer to parent node to retrieve child node configuration for.
1339 *
1340 * Remarks
1341 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1342 * when we reach a device node which is not a direct child of the device
1343 * node for which we configure child services for. Any errors that occur is
1344 * logged instead so that all child services have a chance of beeing
1345 * configured.
1346 */
1347
1348 NTSTATUS
1349 IopActionConfigureChildServices(
1350 PDEVICE_NODE DeviceNode,
1351 PVOID Context)
1352 {
1353 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1354 PDEVICE_NODE ParentDeviceNode;
1355 PUNICODE_STRING Service;
1356 NTSTATUS Status;
1357
1358 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
1359
1360 ParentDeviceNode = (PDEVICE_NODE)Context;
1361
1362 /*
1363 * We are called for the parent too, but we don't need to do special
1364 * handling for this node
1365 */
1366 if (DeviceNode == ParentDeviceNode)
1367 {
1368 DPRINT("Success\n");
1369 return STATUS_SUCCESS;
1370 }
1371
1372 /*
1373 * Make sure this device node is a direct child of the parent device node
1374 * that is given as an argument
1375 */
1376 if (DeviceNode->Parent != ParentDeviceNode)
1377 {
1378 /* Stop the traversal immediately and indicate successful operation */
1379 DPRINT("Stop\n");
1380 return STATUS_UNSUCCESSFUL;
1381 }
1382
1383 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1384 {
1385 /*
1386 * Retrieve configuration from Enum key
1387 */
1388
1389 Service = &DeviceNode->ServiceName;
1390
1391 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1392 RtlInitUnicodeString(Service, NULL);
1393
1394 QueryTable[0].Name = L"Service";
1395 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1396 QueryTable[0].EntryContext = Service;
1397
1398 Status = RtlQueryRegistryValues(RTL_REGISTRY_ENUM,
1399 DeviceNode->InstancePath.Buffer, QueryTable, NULL, NULL);
1400
1401 if (!NT_SUCCESS(Status))
1402 {
1403 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1404 /* FIXME: Log the error */
1405 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1406 DeviceNode->InstancePath.Buffer, Status);
1407 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1408 return STATUS_SUCCESS;
1409 }
1410
1411 if (Service->Buffer == NULL)
1412 {
1413 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1414 return STATUS_SUCCESS;
1415 }
1416
1417 DPRINT("Got Service %S\n", Service->Buffer);
1418 }
1419
1420 return STATUS_SUCCESS;
1421 }
1422
1423 /*
1424 * IopActionInitChildServices
1425 *
1426 * Initialize the service for all (direct) child nodes of a parent node
1427 *
1428 * Parameters
1429 * DeviceNode
1430 * Pointer to device node.
1431 * Context
1432 * Pointer to parent node to initialize child node services for.
1433 * BootDrivers
1434 * Load only driver marked as boot start.
1435 *
1436 * Remarks
1437 * If the driver image for a service is not loaded and initialized
1438 * it is done here too. We only return a status code indicating an
1439 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1440 * not a direct child of the device node for which we initialize
1441 * child services for. Any errors that occur is logged instead so
1442 * that all child services have a chance of being initialized.
1443 */
1444
1445 NTSTATUS
1446 IopActionInitChildServices(
1447 PDEVICE_NODE DeviceNode,
1448 PVOID Context,
1449 BOOLEAN BootDrivers)
1450 {
1451 PDEVICE_NODE ParentDeviceNode;
1452 NTSTATUS Status;
1453
1454 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode, Context,
1455 BootDrivers);
1456
1457 ParentDeviceNode = (PDEVICE_NODE)Context;
1458
1459 /*
1460 * We are called for the parent too, but we don't need to do special
1461 * handling for this node
1462 */
1463 if (DeviceNode == ParentDeviceNode)
1464 {
1465 DPRINT("Success\n");
1466 return STATUS_SUCCESS;
1467 }
1468
1469 /*
1470 * Make sure this device node is a direct child of the parent device node
1471 * that is given as an argument
1472 */
1473 #if 0
1474 if (DeviceNode->Parent != ParentDeviceNode)
1475 {
1476 /*
1477 * Stop the traversal immediately and indicate unsuccessful operation
1478 */
1479 DPRINT("Stop\n");
1480 return STATUS_UNSUCCESSFUL;
1481 }
1482 #endif
1483
1484 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
1485 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
1486 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
1487 {
1488 PMODULE_OBJECT ModuleObject;
1489 PDRIVER_OBJECT DriverObject;
1490
1491 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
1492 if (NT_SUCCESS(Status))
1493 {
1494 Status = IopInitializeDriverModule(DeviceNode, ModuleObject, FALSE, &DriverObject);
1495 if (NT_SUCCESS(Status))
1496 {
1497 /* Attach lower level filter drivers. */
1498 IopAttachFilterDrivers(DeviceNode, TRUE);
1499 /* Initialize the function driver for the device node */
1500 Status = IopInitializeDevice(DeviceNode, DriverObject);
1501 if (NT_SUCCESS(Status))
1502 {
1503 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
1504 /* Attach upper level filter drivers. */
1505 IopAttachFilterDrivers(DeviceNode, FALSE);
1506 }
1507 }
1508 }
1509 else
1510 {
1511 /*
1512 * Don't disable when trying to load only boot drivers
1513 */
1514 if (!BootDrivers)
1515 {
1516 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1517 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
1518 }
1519 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1520 CPRINT("Initialization of service %S failed (Status %x)\n",
1521 DeviceNode->ServiceName.Buffer, Status);
1522 }
1523 } else
1524 {
1525 DPRINT("Service %S is disabled or already initialized\n",
1526 DeviceNode->ServiceName.Buffer);
1527 }
1528
1529 return STATUS_SUCCESS;
1530 }
1531
1532 /*
1533 * IopActionInitAllServices
1534 *
1535 * Initialize the service for all (direct) child nodes of a parent node. This
1536 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
1537 */
1538
1539 NTSTATUS
1540 IopActionInitAllServices(
1541 PDEVICE_NODE DeviceNode,
1542 PVOID Context)
1543 {
1544 return IopActionInitChildServices(DeviceNode, Context, FALSE);
1545 }
1546
1547 /*
1548 * IopActionInitBootServices
1549 *
1550 * Initialize the boot start services for all (direct) child nodes of a
1551 * parent node. This function just calls IopActionInitChildServices with
1552 * BootDrivers = TRUE.
1553 */
1554
1555 NTSTATUS
1556 IopActionInitBootServices(
1557 PDEVICE_NODE DeviceNode,
1558 PVOID Context)
1559 {
1560 return IopActionInitChildServices(DeviceNode, Context, TRUE);
1561 }
1562
1563 /*
1564 * IopInitializePnpServices
1565 *
1566 * Initialize services for discovered children
1567 *
1568 * Parameters
1569 * DeviceNode
1570 * Top device node to start initializing services.
1571 *
1572 * BootDrivers
1573 * When set to TRUE, only drivers marked as boot start will
1574 * be loaded. Otherwise, all drivers will be loaded.
1575 *
1576 * Return Value
1577 * Status
1578 */
1579
1580 NTSTATUS
1581 IopInitializePnpServices(
1582 IN PDEVICE_NODE DeviceNode,
1583 IN BOOLEAN BootDrivers)
1584 {
1585 DEVICETREE_TRAVERSE_CONTEXT Context;
1586
1587 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode, BootDrivers);
1588
1589 if (BootDrivers)
1590 {
1591 IopInitDeviceTreeTraverseContext(
1592 &Context,
1593 DeviceNode,
1594 IopActionInitBootServices,
1595 DeviceNode);
1596 } else
1597 {
1598 IopInitDeviceTreeTraverseContext(
1599 &Context,
1600 DeviceNode,
1601 IopActionInitAllServices,
1602 DeviceNode);
1603 }
1604
1605 return IopTraverseDeviceTree(&Context);
1606 }
1607
1608
1609 NTSTATUS
1610 IopInvalidateDeviceRelations(
1611 IN PDEVICE_NODE DeviceNode,
1612 IN DEVICE_RELATION_TYPE Type)
1613 {
1614 DEVICETREE_TRAVERSE_CONTEXT Context;
1615 PDEVICE_RELATIONS DeviceRelations;
1616 IO_STATUS_BLOCK IoStatusBlock;
1617 PDEVICE_NODE ChildDeviceNode;
1618 IO_STACK_LOCATION Stack;
1619 BOOL BootDrivers;
1620 OBJECT_ATTRIBUTES ObjectAttributes;
1621 UNICODE_STRING LinkName;
1622 HANDLE Handle;
1623 NTSTATUS Status;
1624 ULONG i;
1625
1626 DPRINT("DeviceNode %x\n", DeviceNode);
1627
1628 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1629
1630 Stack.Parameters.QueryDeviceRelations.Type = Type/*BusRelations*/;
1631
1632 Status = IopInitiatePnpIrp(
1633 DeviceNode->PhysicalDeviceObject,
1634 &IoStatusBlock,
1635 IRP_MN_QUERY_DEVICE_RELATIONS,
1636 &Stack);
1637 if (!NT_SUCCESS(Status))
1638 {
1639 DPRINT("IopInitiatePnpIrp() failed\n");
1640 return Status;
1641 }
1642
1643 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1644
1645 if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
1646 {
1647 DPRINT("No PDOs\n");
1648 if (DeviceRelations)
1649 {
1650 ExFreePool(DeviceRelations);
1651 }
1652 return STATUS_SUCCESS;
1653 }
1654
1655 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
1656
1657 /*
1658 * Create device nodes for all discovered devices
1659 */
1660
1661 for (i = 0; i < DeviceRelations->Count; i++)
1662 {
1663 Status = IopCreateDeviceNode(
1664 DeviceNode,
1665 DeviceRelations->Objects[i],
1666 &ChildDeviceNode);
1667 DeviceNode->Flags |= DNF_ENUMERATED;
1668 if (!NT_SUCCESS(Status))
1669 {
1670 DPRINT("No resources\n");
1671 for (i = 0; i < DeviceRelations->Count; i++)
1672 ObDereferenceObject(DeviceRelations->Objects[i]);
1673 ExFreePool(DeviceRelations);
1674 return STATUS_INSUFFICIENT_RESOURCES;
1675 }
1676 }
1677 ExFreePool(DeviceRelations);
1678
1679 /*
1680 * Retrieve information about all discovered children from the bus driver
1681 */
1682
1683 IopInitDeviceTreeTraverseContext(
1684 &Context,
1685 DeviceNode,
1686 IopActionInterrogateDeviceStack,
1687 DeviceNode);
1688
1689 Status = IopTraverseDeviceTree(&Context);
1690 if (!NT_SUCCESS(Status))
1691 {
1692 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1693 return Status;
1694 }
1695
1696 /*
1697 * Retrieve configuration from the registry for discovered children
1698 */
1699
1700 IopInitDeviceTreeTraverseContext(
1701 &Context,
1702 DeviceNode,
1703 IopActionConfigureChildServices,
1704 DeviceNode);
1705
1706 Status = IopTraverseDeviceTree(&Context);
1707 if (!NT_SUCCESS(Status))
1708 {
1709 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1710 return Status;
1711 }
1712
1713 /*
1714 * Get the state of the system boot. If the \\SystemRoot link isn't
1715 * created yet, we will assume that it's possible to load only boot
1716 * drivers.
1717 */
1718
1719 RtlInitUnicodeString(&LinkName, L"\\SystemRoot");
1720
1721 InitializeObjectAttributes(
1722 &ObjectAttributes,
1723 &LinkName,
1724 0,
1725 NULL,
1726 NULL);
1727
1728 Status = NtOpenFile(
1729 &Handle,
1730 FILE_ALL_ACCESS,
1731 &ObjectAttributes,
1732 &IoStatusBlock,
1733 0,
1734 0);
1735
1736 BootDrivers = NT_SUCCESS(Status) ? FALSE : TRUE;
1737
1738 NtClose(Handle);
1739
1740 /*
1741 * Initialize services for discovered children. Only boot drivers will
1742 * be loaded from boot driver!
1743 */
1744
1745 Status = IopInitializePnpServices(DeviceNode, BootDrivers);
1746 if (!NT_SUCCESS(Status))
1747 {
1748 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status);
1749 return Status;
1750 }
1751
1752 return STATUS_SUCCESS;
1753 }
1754
1755
1756 VOID INIT_FUNCTION
1757 PnpInit(VOID)
1758 {
1759 PDEVICE_OBJECT Pdo;
1760 NTSTATUS Status;
1761
1762 DPRINT("PnpInit()\n");
1763
1764 KeInitializeSpinLock(&IopDeviceTreeLock);
1765
1766 /*
1767 * Create root device node
1768 */
1769
1770 Status = IopCreateDriverObject(&IopRootDriverObject, NULL, FALSE, NULL, 0);
1771 if (!NT_SUCCESS(Status))
1772 {
1773 CPRINT("IoCreateDriverObject() failed\n");
1774 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1775 }
1776
1777 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
1778 0, FALSE, &Pdo);
1779 if (!NT_SUCCESS(Status))
1780 {
1781 CPRINT("IoCreateDevice() failed\n");
1782 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1783 }
1784
1785 Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
1786 if (!NT_SUCCESS(Status))
1787 {
1788 CPRINT("Insufficient resources\n");
1789 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
1790 }
1791
1792 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
1793 PnpRootDriverEntry(IopRootDriverObject, NULL);
1794 IopRootDriverObject->DriverExtension->AddDevice(
1795 IopRootDriverObject,
1796 IopRootDeviceNode->PhysicalDeviceObject);
1797 }
1798
1799 /* EOF */