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