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