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