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