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