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