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