IoCreateStreamFileObject(): force: Flags |= FO_SYNCHRONOUS_IO
[reactos.git] / ntoskrnl / io / pnpmgr.c
1 /* $Id$
2  *
3  * COPYRIGHT:      See COPYING in the top level directory
4  * PROJECT:        ReactOS kernel
5  * FILE:           ntoskrnl/io/pnpmgr.c
6  * PURPOSE:        Initializes the PnP manager
7  * 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 <internal/io.h>
16 #include <internal/po.h>
17 #include <internal/ldr.h>
18 #include <internal/registry.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
29 #define NDEBUG
30 #include <internal/debug.h>
31
32
33 /* GLOBALS *******************************************************************/
34
35 PDEVICE_NODE IopRootDeviceNode;
36 KSPIN_LOCK IopDeviceTreeLock;
37
38 /* DATA **********************************************************************/
39
40 PDRIVER_OBJECT IopRootDriverObject;
41
42 /* FUNCTIONS *****************************************************************/
43
44 VOID
45 STDCALL
46 IoInitializeRemoveLockEx(
47   IN PIO_REMOVE_LOCK Lock,
48   IN ULONG AllocateTag,
49   IN ULONG MaxLockedMinutes,
50   IN ULONG HighWatermark,
51   IN ULONG RemlockSize)
52 {
53 }
54
55 NTSTATUS
56 STDCALL
57 IoAcquireRemoveLockEx(
58   IN PIO_REMOVE_LOCK RemoveLock,
59   IN OPTIONAL PVOID Tag,
60   IN LPCSTR File,
61   IN ULONG Line,
62   IN ULONG RemlockSize)
63 {
64   return STATUS_NOT_IMPLEMENTED;
65 }
66
67 VOID
68 STDCALL
69 IoReleaseRemoveLockEx(
70   IN PIO_REMOVE_LOCK RemoveLock,
71   IN PVOID Tag,
72   IN ULONG RemlockSize)
73 {
74 }
75
76 VOID
77 STDCALL
78 IoReleaseRemoveLockAndWaitEx(
79   IN PIO_REMOVE_LOCK RemoveLock,
80   IN PVOID Tag,
81   IN ULONG RemlockSize)
82 {
83 }
84
85 VOID
86 STDCALL
87 IoAdjustPagingPathCount(
88   IN PLONG Count,
89   IN BOOLEAN Increment)
90 {
91 }
92
93 NTSTATUS
94 STDCALL
95 IoGetDeviceInterfaceAlias(
96   IN PUNICODE_STRING SymbolicLinkName,
97   IN CONST GUID *AliasInterfaceClassGuid,
98   OUT PUNICODE_STRING AliasSymbolicLinkName)
99 {
100   return STATUS_NOT_IMPLEMENTED;
101 }
102
103 NTSTATUS
104 STDCALL
105 IoGetDeviceInterfaces(
106   IN CONST GUID *InterfaceClassGuid,
107   IN PDEVICE_OBJECT PhysicalDeviceObject  OPTIONAL,
108   IN ULONG Flags,
109   OUT PWSTR *SymbolicLinkList)
110 {
111   return STATUS_NOT_IMPLEMENTED;
112 }
113
114 NTSTATUS
115 STDCALL
116 IoGetDeviceProperty(
117   IN PDEVICE_OBJECT DeviceObject,
118   IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
119   IN ULONG BufferLength,
120   OUT PVOID PropertyBuffer,
121   OUT PULONG ResultLength)
122 {
123   return STATUS_NOT_IMPLEMENTED;
124 }
125
126 VOID
127 STDCALL
128 IoInvalidateDeviceRelations(
129   IN PDEVICE_OBJECT DeviceObject,
130   IN DEVICE_RELATION_TYPE Type)
131 {
132 }
133
134 VOID
135 STDCALL
136 IoInvalidateDeviceState(
137   IN PDEVICE_OBJECT PhysicalDeviceObject)
138 {
139 }
140
141 NTSTATUS
142 STDCALL
143 IoOpenDeviceInterfaceRegistryKey(
144   IN PUNICODE_STRING SymbolicLinkName,
145   IN ACCESS_MASK DesiredAccess,
146   OUT PHANDLE DeviceInterfaceKey)
147 {
148   return STATUS_NOT_IMPLEMENTED;
149 }
150
151 NTSTATUS
152 STDCALL
153 IoOpenDeviceRegistryKey(
154   IN PDEVICE_OBJECT DeviceObject,
155   IN ULONG DevInstKeyType,
156   IN ACCESS_MASK DesiredAccess,
157   OUT PHANDLE DevInstRegKey)
158 {
159   return STATUS_NOT_IMPLEMENTED;
160 }
161
162 NTSTATUS
163 STDCALL
164 IoRegisterDeviceInterface(
165   IN PDEVICE_OBJECT PhysicalDeviceObject,
166   IN CONST GUID *InterfaceClassGuid,
167   IN PUNICODE_STRING ReferenceString  OPTIONAL,
168   OUT PUNICODE_STRING SymbolicLinkName)
169 {
170         PWCHAR KeyNameString = L"\\Device\\Serenum";
171
172         if (IsEqualGUID(InterfaceClassGuid, (LPGUID)&GUID_SERENUM_BUS_ENUMERATOR)) {
173         RtlInitUnicodeString(SymbolicLinkName, KeyNameString);
174                 return STATUS_SUCCESS;
175         }
176         return STATUS_INVALID_DEVICE_REQUEST;
177 //    return STATUS_NOT_IMPLEMENTED;
178 }
179
180 NTSTATUS
181 STDCALL
182 IoRegisterPlugPlayNotification(
183   IN IO_NOTIFICATION_EVENT_CATEGORY EventCategory,
184   IN ULONG EventCategoryFlags,
185   IN PVOID EventCategoryData  OPTIONAL,
186   IN PDRIVER_OBJECT DriverObject,
187   IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE CallbackRoutine,
188   IN PVOID Context,
189   OUT PVOID *NotificationEntry)
190 {
191   return STATUS_NOT_IMPLEMENTED;
192 }
193
194 NTSTATUS
195 STDCALL
196 IoReportDetectedDevice(
197   IN PDRIVER_OBJECT DriverObject,
198   IN INTERFACE_TYPE LegacyBusType,
199   IN ULONG BusNumber,
200   IN ULONG SlotNumber,
201   IN PCM_RESOURCE_LIST ResourceList,
202   IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceRequirements  OPTIONAL,
203   IN BOOLEAN ResourceAssigned,
204   IN OUT PDEVICE_OBJECT *DeviceObject)
205 {
206   return STATUS_NOT_IMPLEMENTED;
207 }
208
209 NTSTATUS
210 STDCALL
211 IoReportResourceForDetection(
212   IN PDRIVER_OBJECT DriverObject,
213   IN PCM_RESOURCE_LIST DriverList   OPTIONAL,
214   IN ULONG DriverListSize    OPTIONAL,
215   IN PDEVICE_OBJECT DeviceObject    OPTIONAL,
216   IN PCM_RESOURCE_LIST DeviceList   OPTIONAL,
217   IN ULONG DeviceListSize   OPTIONAL,
218   OUT PBOOLEAN ConflictDetected)
219 {
220   return STATUS_NOT_IMPLEMENTED;
221 }
222
223 NTSTATUS
224 STDCALL
225 IoReportTargetDeviceChange(
226   IN PDEVICE_OBJECT PhysicalDeviceObject,
227   IN PVOID NotificationStructure)
228 {
229   return STATUS_NOT_IMPLEMENTED;
230 }
231
232 NTSTATUS
233 STDCALL
234 IoReportTargetDeviceChangeAsynchronous(
235   IN PDEVICE_OBJECT PhysicalDeviceObject,
236   IN PVOID NotificationStructure,
237   IN PDEVICE_CHANGE_COMPLETE_CALLBACK Callback  OPTIONAL,
238   IN PVOID Context  OPTIONAL)
239 {
240   return STATUS_NOT_IMPLEMENTED;
241 }
242
243 VOID
244 STDCALL
245 IoRequestDeviceEject(
246   IN PDEVICE_OBJECT PhysicalDeviceObject)
247 {
248 }
249
250 NTSTATUS
251 STDCALL
252 IoSetDeviceInterfaceState(
253   IN PUNICODE_STRING SymbolicLinkName,
254   IN BOOLEAN Enable)
255 {
256         return STATUS_SUCCESS;
257
258 //      return STATUS_OBJECT_NAME_EXISTS;
259 //      return STATUS_OBJECT_NAME_NOT_FOUND;
260 //    return STATUS_NOT_IMPLEMENTED;
261 }
262
263 NTSTATUS
264 STDCALL
265 IoUnregisterPlugPlayNotification(
266   IN PVOID NotificationEntry)
267 {
268   return STATUS_NOT_IMPLEMENTED;
269 }
270
271
272 BOOLEAN
273 IopCreateUnicodeString(
274   PUNICODE_STRING       Destination,
275   PWSTR Source,
276   POOL_TYPE PoolType)
277 {
278   ULONG Length;
279
280   if (!Source)
281   {
282     RtlInitUnicodeString(Destination, NULL);
283     return TRUE;
284   }
285
286   Length = (wcslen(Source) + 1) * sizeof(WCHAR);
287
288   Destination->Buffer = ExAllocatePool(PoolType, Length);
289
290   if (Destination->Buffer == NULL)
291   {
292     return FALSE;
293   }
294
295   RtlCopyMemory(Destination->Buffer, Source, Length);
296
297   Destination->MaximumLength = Length;
298
299   Destination->Length = Length - sizeof(WCHAR);
300
301   return TRUE;
302 }
303
304 NTSTATUS
305 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
306 {
307   KIRQL OldIrql;
308
309   assert(PopSystemPowerDeviceNode);
310
311   KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
312   *DeviceObject = PopSystemPowerDeviceNode->Pdo;
313   KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
314
315   return STATUS_SUCCESS;
316 }
317
318 /**********************************************************************
319  * DESCRIPTION
320  *      Creates a device node
321  *
322  * ARGUMENTS
323  *   ParentNode           = Pointer to parent device node
324  *   PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
325  *                          to have the root device node create one
326  *                          (eg. for legacy drivers)
327  *   DeviceNode           = Pointer to storage for created device node
328  *
329  * RETURN VALUE
330  *      Status
331  */
332 NTSTATUS
333 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
334   PDEVICE_OBJECT PhysicalDeviceObject,
335   PDEVICE_NODE *DeviceNode)
336 {
337   PDEVICE_NODE Node;
338   NTSTATUS Status;
339   KIRQL OldIrql;
340
341   DPRINT("ParentNode %x PhysicalDeviceObject %x\n",
342     ParentNode, PhysicalDeviceObject);
343
344   Node = (PDEVICE_NODE)ExAllocatePool(PagedPool, sizeof(DEVICE_NODE));
345   if (!Node)
346     {
347       return STATUS_INSUFFICIENT_RESOURCES;
348     }
349
350   RtlZeroMemory(Node, sizeof(DEVICE_NODE));
351
352   if (!PhysicalDeviceObject)
353     {
354       Status = PnpRootCreateDevice(&PhysicalDeviceObject);
355       if (!NT_SUCCESS(Status))
356         {
357           ExFreePool(Node);
358           return Status;
359         }
360
361       /* This is for drivers passed on the command line to ntoskrnl.exe */
362       IopDeviceNodeSetFlag(Node, DNF_STARTED);
363       IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
364     }
365
366   Node->Pdo = PhysicalDeviceObject;
367
368   if (ParentNode)
369     {
370       KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
371       Node->Parent = ParentNode;
372       Node->NextSibling = ParentNode->Child;
373       if (ParentNode->Child != NULL)
374         {
375           ParentNode->Child->PrevSibling = Node;          
376         }
377       ParentNode->Child = Node;
378       KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
379     }
380
381   *DeviceNode = Node;
382
383   return STATUS_SUCCESS;
384 }
385
386 NTSTATUS
387 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
388 {
389   KIRQL OldIrql;
390
391   /* All children must be deleted before a parent is deleted */
392   assert(!DeviceNode->Child);
393
394   KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
395
396   assert(DeviceNode->Pdo);
397
398   ObDereferenceObject(DeviceNode->Pdo);
399
400   /* Unlink from parent if it exists */
401
402   if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
403     {
404       DeviceNode->Parent->Child = DeviceNode->NextSibling;
405     }
406
407   /* Unlink from sibling list */
408
409   if (DeviceNode->PrevSibling)
410     {
411       DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
412     }
413
414   if (DeviceNode->NextSibling)
415     {
416   DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
417     }
418
419   KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
420
421   RtlFreeUnicodeString(&DeviceNode->InstancePath);
422
423   RtlFreeUnicodeString(&DeviceNode->ServiceName);
424
425   if (DeviceNode->CapabilityFlags)
426     {
427   ExFreePool(DeviceNode->CapabilityFlags);
428     }
429
430   if (DeviceNode->CmResourceList)
431     {
432   ExFreePool(DeviceNode->CmResourceList);
433     }
434
435   if (DeviceNode->BootResourcesList)
436     {
437   ExFreePool(DeviceNode->BootResourcesList);
438     }
439
440   if (DeviceNode->ResourceRequirementsList)
441     {
442   ExFreePool(DeviceNode->ResourceRequirementsList);
443     }
444
445   RtlFreeUnicodeString(&DeviceNode->DeviceID);
446
447   RtlFreeUnicodeString(&DeviceNode->InstanceID);
448
449   RtlFreeUnicodeString(&DeviceNode->HardwareIDs);
450
451   RtlFreeUnicodeString(&DeviceNode->CompatibleIDs);
452
453   RtlFreeUnicodeString(&DeviceNode->DeviceText);
454
455   RtlFreeUnicodeString(&DeviceNode->DeviceTextLocation);
456
457   if (DeviceNode->BusInformation)
458     {
459   ExFreePool(DeviceNode->BusInformation);
460     }
461
462   ExFreePool(DeviceNode);
463
464   return STATUS_SUCCESS;
465 }
466
467 NTSTATUS
468 IopInitiatePnpIrp(
469   PDEVICE_OBJECT DeviceObject,
470   PIO_STATUS_BLOCK IoStatusBlock,
471   ULONG MinorFunction,
472   PIO_STACK_LOCATION Stack OPTIONAL)
473 {
474   PDEVICE_OBJECT TopDeviceObject;
475   PIO_STACK_LOCATION IrpSp;
476   NTSTATUS Status;
477   KEVENT Event;
478   PIRP Irp;
479
480   /* Always call the top of the device stack */
481   TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
482
483   KeInitializeEvent(
484     &Event,
485           NotificationEvent,
486           FALSE);
487
488   /* PNP IRPs are always initialized with a status code of
489      STATUS_NOT_IMPLEMENTED */
490   IoStatusBlock->Status = STATUS_NOT_IMPLEMENTED;
491   IoStatusBlock->Information = 0;
492
493   Irp = IoBuildSynchronousFsdRequest(
494     IRP_MJ_PNP,
495     TopDeviceObject,
496           NULL,
497           0,
498           NULL,
499           &Event,
500           IoStatusBlock);
501
502   IrpSp = IoGetNextIrpStackLocation(Irp);
503   IrpSp->MinorFunction = MinorFunction;
504
505   if (Stack)
506   {
507     RtlMoveMemory(
508       &IrpSp->Parameters,
509       &Stack->Parameters,
510       sizeof(Stack->Parameters));
511   }
512
513         Status = IoCallDriver(TopDeviceObject, Irp);
514         if (Status == STATUS_PENDING)
515           {
516                   KeWaitForSingleObject(
517         &Event,
518         Executive,
519                     KernelMode,
520                     FALSE,
521                     NULL);
522       Status = IoStatusBlock->Status;
523     }
524
525   ObDereferenceObject(TopDeviceObject);
526
527   return Status;
528 }
529
530
531 NTSTATUS
532 IopQueryCapabilities(
533   PDEVICE_OBJECT Pdo,
534   PDEVICE_CAPABILITIES *Capabilities)
535 {
536   IO_STATUS_BLOCK       IoStatusBlock;
537   PDEVICE_CAPABILITIES Caps;
538   IO_STACK_LOCATION Stack;
539   NTSTATUS Status;
540
541   DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
542
543   *Capabilities = NULL;
544
545   Caps = ExAllocatePool(PagedPool, sizeof(DEVICE_CAPABILITIES));
546   if (!Caps)
547   {
548     return STATUS_INSUFFICIENT_RESOURCES;
549   }
550
551   RtlZeroMemory(Caps, sizeof(DEVICE_CAPABILITIES));
552   Caps->Size = sizeof(DEVICE_CAPABILITIES);
553   Caps->Version = 1;
554   Caps->Address = -1;
555   Caps->UINumber = -1;
556
557   Stack.Parameters.DeviceCapabilities.Capabilities = Caps;
558
559   Status = IopInitiatePnpIrp(
560     Pdo,
561     &IoStatusBlock,
562     IRP_MN_QUERY_CAPABILITIES,
563     &Stack);
564   if (NT_SUCCESS(Status))
565   {
566     *Capabilities = Caps;
567   }
568   else
569   {
570     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
571   }
572
573   return Status;
574 }
575
576
577 NTSTATUS
578 IopTraverseDeviceTreeNode(
579   PDEVICETREE_TRAVERSE_CONTEXT Context)
580 {
581   PDEVICE_NODE ParentDeviceNode;
582   PDEVICE_NODE ChildDeviceNode;
583   NTSTATUS Status;
584
585   /* Copy context data so we don't overwrite it in subsequent calls to this function */
586   ParentDeviceNode = Context->DeviceNode;
587
588   /* Call the action routine */
589   Status = (Context->Action)(ParentDeviceNode, Context->Context);
590   if (!NT_SUCCESS(Status))
591   {
592     return Status;
593   }
594
595   /* Traversal of all children nodes */
596   for (ChildDeviceNode = ParentDeviceNode->Child;
597        ChildDeviceNode != NULL;
598        ChildDeviceNode = ChildDeviceNode->NextSibling)
599   {
600     /* Pass the current device node to the action routine */
601     Context->DeviceNode = ChildDeviceNode;
602
603     Status = IopTraverseDeviceTreeNode(Context);
604     if (!NT_SUCCESS(Status))
605     {
606       return Status;
607     }
608   }
609
610   return Status;
611 }
612
613
614 NTSTATUS
615 IopTraverseDeviceTree(
616   PDEVICETREE_TRAVERSE_CONTEXT Context)
617 {
618   NTSTATUS Status;
619
620   DPRINT("Context %x\n", Context);
621
622   DPRINT("IopTraverseDeviceTree(DeviceNode %x  FirstDeviceNode %x  Action %x  Context %x)\n",
623     Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
624
625   /* Start from the specified device node */
626   Context->DeviceNode = Context->FirstDeviceNode;
627
628   /* Recursively traverse the device tree */
629   Status = IopTraverseDeviceTreeNode(Context);
630   if (Status == STATUS_UNSUCCESSFUL)
631   {
632     /* The action routine just wanted to terminate the traversal with status
633        code STATUS_SUCCESS */
634     Status = STATUS_SUCCESS;
635   }
636
637   return Status;
638 }
639
640
641 NTSTATUS
642 IopActionInterrogateDeviceStack(
643   PDEVICE_NODE DeviceNode,
644   PVOID Context)
645 /*
646  * FUNCTION: Retrieve information for all (direct) child nodes of a parent node
647  * ARGUMENTS:
648  *   DeviceNode = Pointer to device node
649  *   Context    = Pointer to parent node to retrieve child node information for
650  * NOTES:
651  *   We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
652  *   when we reach a device node which is not a direct child of the device node
653  *   for which we retrieve information of child nodes for. Any errors that occur
654  *   is logged instead so that all child services have a chance of beeing
655  *   interrogated.
656  */
657 {
658   IO_STATUS_BLOCK       IoStatusBlock;
659   PDEVICE_NODE ParentDeviceNode;
660   WCHAR InstancePath[MAX_PATH];
661   IO_STACK_LOCATION Stack;
662   NTSTATUS Status;
663
664   DPRINT("DeviceNode %x  Context %x\n", DeviceNode, Context);
665
666   DPRINT("PDO %x\n", DeviceNode->Pdo);
667
668
669   ParentDeviceNode = (PDEVICE_NODE)Context;
670
671   /* We are called for the parent too, but we don't need to do special
672      handling for this node */
673   if (DeviceNode == ParentDeviceNode)
674   {
675     DPRINT("Success\n");
676     return STATUS_SUCCESS;
677   }
678
679   /* Make sure this device node is a direct child of the parent device node
680      that is given as an argument */
681   if (DeviceNode->Parent != ParentDeviceNode)
682   {
683     /* Stop the traversal immediately and indicate successful operation */
684     DPRINT("Stop\n");
685     return STATUS_UNSUCCESSFUL;
686   }
687
688
689   /* FIXME: For critical errors, cleanup and disable device, but always return STATUS_SUCCESS */
690
691
692   DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
693
694   Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
695
696   Status = IopInitiatePnpIrp(
697     DeviceNode->Pdo,
698     &IoStatusBlock,
699     IRP_MN_QUERY_ID,
700     &Stack);
701   if (NT_SUCCESS(Status))
702   {
703     RtlInitUnicodeString(
704       &DeviceNode->DeviceID,
705       (LPWSTR)IoStatusBlock.Information);
706
707     /* FIXME: Check for valid characters, if there is invalid characters then bugcheck */
708   }
709   else
710   {
711     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
712     RtlInitUnicodeString(&DeviceNode->DeviceID, NULL);
713   }
714
715
716   DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
717
718   Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
719
720   Status = IopInitiatePnpIrp(
721     DeviceNode->Pdo,
722     &IoStatusBlock,
723     IRP_MN_QUERY_ID,
724     &Stack);
725   if (NT_SUCCESS(Status))
726   {
727     RtlInitUnicodeString(
728       &DeviceNode->InstanceID,
729       (LPWSTR)IoStatusBlock.Information);
730
731     /* FIXME: Check for valid characters, if there is invalid characters then bugcheck */
732   }
733   else
734   {
735     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
736     RtlInitUnicodeString(&DeviceNode->InstanceID, NULL);
737   }
738
739
740   /* FIXME: SEND IRP_QUERY_ID.BusQueryHardwareIDs */
741   /* FIXME: SEND IRP_QUERY_ID.BusQueryCompatibleIDs */
742
743
744   Status = IopQueryCapabilities(DeviceNode->Pdo, &DeviceNode->CapabilityFlags);
745   if (NT_SUCCESS(Status))
746   {
747   }
748   else
749   {
750   }
751
752
753   DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
754
755   Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
756   Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
757
758   Status = IopInitiatePnpIrp(
759     DeviceNode->Pdo,
760     &IoStatusBlock,
761     IRP_MN_QUERY_DEVICE_TEXT,
762     &Stack);
763   if (NT_SUCCESS(Status))
764   {
765     RtlInitUnicodeString(
766       &DeviceNode->DeviceText,
767       (LPWSTR)IoStatusBlock.Information);
768   }
769   else
770   {
771     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
772     RtlInitUnicodeString(&DeviceNode->DeviceText, NULL);
773   }
774
775
776   DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
777
778   Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
779   Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
780
781   Status = IopInitiatePnpIrp(
782     DeviceNode->Pdo,
783     &IoStatusBlock,
784     IRP_MN_QUERY_DEVICE_TEXT,
785     &Stack);
786   if (NT_SUCCESS(Status))
787   {
788     RtlInitUnicodeString(
789       &DeviceNode->DeviceTextLocation,
790       (LPWSTR)IoStatusBlock.Information);
791   }
792   else
793   {
794     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
795     RtlInitUnicodeString(&DeviceNode->DeviceTextLocation, NULL);
796   }
797
798
799   DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
800
801   Status = IopInitiatePnpIrp(
802     DeviceNode->Pdo,
803     &IoStatusBlock,
804     IRP_MN_QUERY_BUS_INFORMATION,
805     NULL);
806   if (NT_SUCCESS(Status))
807   {
808     DeviceNode->BusInformation =
809       (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
810   }
811   else
812   {
813     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
814     DeviceNode->BusInformation = NULL;
815   }
816
817
818   DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
819
820   Status = IopInitiatePnpIrp(
821     DeviceNode->Pdo,
822     &IoStatusBlock,
823     IRP_MN_QUERY_RESOURCES,
824     NULL);
825   if (NT_SUCCESS(Status))
826   {
827     DeviceNode->BootResourcesList =
828       (PCM_RESOURCE_LIST)IoStatusBlock.Information;
829   }
830   else
831   {
832     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
833     DeviceNode->BootResourcesList = NULL;
834   }
835
836
837   DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
838
839   Status = IopInitiatePnpIrp(
840     DeviceNode->Pdo,
841     &IoStatusBlock,
842     IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
843     NULL);
844   if (NT_SUCCESS(Status))
845   {
846     DeviceNode->ResourceRequirementsList =
847       (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
848   }
849   else
850   {
851     DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
852     DeviceNode->ResourceRequirementsList = NULL;
853   }
854
855
856   /* Assemble the instance path for the device */
857
858   wcscpy(InstancePath, DeviceNode->DeviceID.Buffer);
859   wcscat(InstancePath, L"\\");
860   wcscat(InstancePath, DeviceNode->InstanceID.Buffer);
861
862   if (!DeviceNode->CapabilityFlags->UniqueID)
863   {
864     DPRINT("Instance ID is not unique\n");
865     /* FIXME: Add information from parent bus driver to InstancePath */
866   }
867
868   if (!IopCreateUnicodeString(&DeviceNode->InstancePath, InstancePath, PagedPool)) {
869     DPRINT("No resources\n");
870     /* FIXME: Cleanup and disable device */
871   }
872
873   DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
874
875   return STATUS_SUCCESS;
876 }
877
878
879 NTSTATUS
880 IopActionConfigureChildServices(
881   PDEVICE_NODE DeviceNode,
882   PVOID Context)
883 /*
884  * FUNCTION: Retrieve configuration for all (direct) child nodes of a parent node
885  * ARGUMENTS:
886  *   DeviceNode = Pointer to device node
887  *   Context    = Pointer to parent node to retrieve child node configuration for
888  * NOTES:
889  *   We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
890  *   when we reach a device node which is not a direct child of the device
891  *   node for which we configure child services for. Any errors that occur is
892  *   logged instead so that all child services have a chance of beeing
893  *   configured.
894  */
895 {
896   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
897   PDEVICE_NODE ParentDeviceNode;
898   PUNICODE_STRING Service;
899   HANDLE KeyHandle;
900   NTSTATUS Status;
901
902   DPRINT("DeviceNode %x  Context %x\n", DeviceNode, Context);
903
904   ParentDeviceNode = (PDEVICE_NODE)Context;
905
906   /* We are called for the parent too, but we don't need to do special
907      handling for this node */
908   if (DeviceNode == ParentDeviceNode)
909   {
910     DPRINT("Success\n");
911     return STATUS_SUCCESS;
912   }
913
914   /* Make sure this device node is a direct child of the parent device node
915      that is given as an argument */
916   if (DeviceNode->Parent != ParentDeviceNode)
917   {
918     /* Stop the traversal immediately and indicate successful operation */
919     DPRINT("Stop\n");
920     return STATUS_UNSUCCESSFUL;
921   }
922
923   /* Retrieve configuration from Enum key */
924
925   Service = &DeviceNode->ServiceName;
926
927   Status = RtlpGetRegistryHandle(
928     RTL_REGISTRY_ENUM,
929           DeviceNode->InstancePath.Buffer,
930                 TRUE,
931                 &KeyHandle);
932   if (!NT_SUCCESS(Status))
933   {
934     DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
935     return Status;
936   }
937
938   RtlZeroMemory(QueryTable, sizeof(QueryTable));
939
940   RtlInitUnicodeString(Service, NULL);
941
942   QueryTable[0].Name = L"Service";
943   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
944   QueryTable[0].EntryContext = Service;
945
946   Status = RtlQueryRegistryValues(
947     RTL_REGISTRY_HANDLE,
948                 (PWSTR)KeyHandle,
949                 QueryTable,
950                 NULL,
951                 NULL);
952   NtClose(KeyHandle);
953
954   DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
955
956   if (!NT_SUCCESS(Status))
957   {
958     /* FIXME: Log the error */
959     CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
960       DeviceNode->InstancePath.Buffer, Status);
961     IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
962     return STATUS_SUCCESS;
963   }
964
965   DPRINT("Got Service %S\n", Service->Buffer);
966
967   return STATUS_SUCCESS;
968 }
969
970
971 NTSTATUS
972 IopActionInitChildServices(
973   PDEVICE_NODE DeviceNode,
974   PVOID Context)
975 /*
976  * FUNCTION: Initialize the service for all (direct) child nodes of a parent node
977  * ARGUMENTS:
978  *   DeviceNode = Pointer to device node
979  *   Context    = Pointer to parent node to initialize child node services for
980  * NOTES:
981  *   If the driver image for a service is not loaded and initialized
982  *   it is done here too.
983  *   We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
984  *   when we reach a device node which is not a direct child of the device
985  *   node for which we initialize child services for. Any errors that occur is
986  *   logged instead so that all child services have a chance of beeing
987  *   initialized.
988  */
989 {
990   PDEVICE_NODE ParentDeviceNode;
991   NTSTATUS Status;
992
993   DPRINT("DeviceNode %x  Context %x\n", DeviceNode, Context);
994
995   ParentDeviceNode = (PDEVICE_NODE)Context;
996
997   /* We are called for the parent too, but we don't need to do special
998      handling for this node */
999   if (DeviceNode == ParentDeviceNode)
1000   {
1001     DPRINT("Success\n");
1002     return STATUS_SUCCESS;
1003   }
1004
1005   /* Make sure this device node is a direct child of the parent device node
1006      that is given as an argument */
1007   if (DeviceNode->Parent != ParentDeviceNode)
1008   {
1009     /* Stop the traversal immediately and indicate successful operation */
1010     DPRINT("Stop\n");
1011     return STATUS_UNSUCCESSFUL;
1012   }
1013
1014   if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
1015     !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
1016     !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
1017   {
1018     Status = IopInitializeDeviceNodeService(DeviceNode);
1019     if (NT_SUCCESS(Status))
1020     {
1021       IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
1022     }
1023     else
1024     {
1025       IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1026
1027       /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1028       CPRINT("Initialization of service %S failed (Status %x)\n",
1029         DeviceNode->ServiceName.Buffer, Status);
1030     }
1031   }
1032   else
1033   {
1034     DPRINT("Service %S is disabled or already initialized\n",
1035         DeviceNode->ServiceName.Buffer);
1036   }
1037
1038   return STATUS_SUCCESS;
1039 }
1040
1041
1042 NTSTATUS
1043 IopInterrogateBusExtender(
1044   PDEVICE_NODE DeviceNode,
1045   PDEVICE_OBJECT Pdo,
1046   BOOLEAN BootDriversOnly)
1047 {
1048   DEVICETREE_TRAVERSE_CONTEXT Context;
1049   PDEVICE_RELATIONS DeviceRelations;
1050         IO_STATUS_BLOCK IoStatusBlock;
1051   PDEVICE_NODE ChildDeviceNode;
1052   IO_STACK_LOCATION Stack;
1053   NTSTATUS Status;
1054   ULONG i;
1055
1056   DPRINT("DeviceNode %x  Pdo %x  BootDriversOnly %d\n", DeviceNode, Pdo, BootDriversOnly);
1057
1058   DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1059
1060   Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
1061
1062   Status = IopInitiatePnpIrp(
1063     Pdo,
1064     &IoStatusBlock,
1065     IRP_MN_QUERY_DEVICE_RELATIONS,
1066     &Stack);
1067   if (!NT_SUCCESS(Status))
1068   {
1069     DPRINT("IopInitiatePnpIrp() failed\n");
1070     return Status;
1071   }
1072
1073   DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1074
1075   if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
1076   {
1077     DPRINT("No PDOs\n");
1078     if (DeviceRelations)
1079     {
1080       ExFreePool(DeviceRelations);
1081     }
1082     return STATUS_SUCCESS;
1083   }
1084
1085   DPRINT("Got %d PDOs\n", DeviceRelations->Count);
1086
1087   /* Create device nodes for all discovered devices */
1088   for (i = 0; i < DeviceRelations->Count; i++)
1089   {
1090     Status = IopCreateDeviceNode(
1091       DeviceNode,
1092       DeviceRelations->Objects[i],
1093       &ChildDeviceNode);
1094     if (!NT_SUCCESS(Status))
1095     {
1096       DPRINT("No resources\n");
1097       for (i = 0; i < DeviceRelations->Count; i++)
1098         ObDereferenceObject(DeviceRelations->Objects[i]);
1099       ExFreePool(DeviceRelations);
1100       return STATUS_INSUFFICIENT_RESOURCES;
1101     }
1102   }
1103
1104   ExFreePool(DeviceRelations);
1105
1106
1107   /* Retrieve information about all discovered children from the bus driver */
1108
1109   IopInitDeviceTreeTraverseContext(
1110     &Context,
1111     DeviceNode,
1112     IopActionInterrogateDeviceStack,
1113     DeviceNode);
1114
1115   Status = IopTraverseDeviceTree(&Context);
1116   if (!NT_SUCCESS(Status))
1117   {
1118           DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1119     return Status;
1120   }
1121
1122
1123   /* Retrieve configuration from the registry for discovered children */
1124
1125   IopInitDeviceTreeTraverseContext(
1126     &Context,
1127     DeviceNode,
1128     IopActionConfigureChildServices,
1129     DeviceNode);
1130
1131   Status = IopTraverseDeviceTree(&Context);
1132   if (!NT_SUCCESS(Status))
1133   {
1134           DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1135     return Status;
1136   }
1137
1138
1139   /* Initialize services for discovered children */
1140
1141   IopInitDeviceTreeTraverseContext(
1142     &Context,
1143     DeviceNode,
1144     IopActionInitChildServices,
1145     DeviceNode);
1146
1147   Status = IopTraverseDeviceTree(&Context);
1148   if (!NT_SUCCESS(Status))
1149   {
1150           DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1151     return Status;
1152   }
1153
1154   return Status;
1155 }
1156
1157
1158 VOID IopLoadBootStartDrivers(VOID)
1159 {
1160   IopInterrogateBusExtender(
1161     IopRootDeviceNode,
1162     IopRootDeviceNode->Pdo,
1163     TRUE);
1164 }
1165
1166 VOID PnpInit(VOID)
1167 {
1168   PDEVICE_OBJECT Pdo;
1169   NTSTATUS Status;
1170
1171   DPRINT("Called\n");
1172
1173   KeInitializeSpinLock(&IopDeviceTreeLock);
1174
1175   Status = IopCreateDriverObject(&IopRootDriverObject, NULL, FALSE);
1176   if (!NT_SUCCESS(Status))
1177   {
1178     CPRINT("IoCreateDriverObject() failed\n");
1179     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1180   }
1181
1182   Status = IoCreateDevice(
1183     IopRootDriverObject,
1184     0,
1185     NULL,
1186     FILE_DEVICE_CONTROLLER,
1187     0,
1188     FALSE,
1189     &Pdo);
1190   if (!NT_SUCCESS(Status))
1191   {
1192     CPRINT("IoCreateDevice() failed\n");
1193     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1194   }
1195
1196   Status = IopCreateDeviceNode(
1197     NULL,
1198     Pdo,
1199     &IopRootDeviceNode);
1200   if (!NT_SUCCESS(Status))
1201   {
1202     CPRINT("Insufficient resources\n");
1203     KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1204   }
1205
1206   IopRootDeviceNode->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
1207
1208   IopRootDeviceNode->DriverObject = IopRootDriverObject;
1209
1210   PnpRootDriverEntry(IopRootDriverObject, NULL);
1211
1212   IopRootDriverObject->DriverExtension->AddDevice(
1213     IopRootDriverObject,
1214     IopRootDeviceNode->Pdo);
1215 }
1216
1217 /* EOF */