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