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