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