Added ObGetObjectHandleCount().
[reactos.git] / reactos / ntoskrnl / io / pnpmgr.c
1 /* $Id: pnpmgr.c,v 1.4 2001/09/16 13:19:32 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 ParentNode->Child->PrevSibling = Node;
354 ParentNode->Child = Node;
355 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
356 }
357
358 *DeviceNode = Node;
359
360 return STATUS_SUCCESS;
361 }
362
363 NTSTATUS
364 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
365 {
366 KIRQL OldIrql;
367
368 /* All children must be deleted before a parent is deleted */
369 assert(!DeviceNode->Child);
370
371 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
372
373 assert(DeviceNode->Pdo);
374
375 ObDereferenceObject(DeviceNode->Pdo);
376
377 /* Unlink from parent if it exists */
378
379 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
380 {
381 DeviceNode->Parent->Child = DeviceNode->NextSibling;
382 }
383
384 /* Unlink from sibling list */
385
386 if (DeviceNode->PrevSibling)
387 {
388 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
389 }
390
391 if (DeviceNode->NextSibling)
392 {
393 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
394 }
395
396 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
397
398 RtlFreeUnicodeString(&DeviceNode->InstancePath);
399
400 RtlFreeUnicodeString(&DeviceNode->ServiceName);
401
402 if (DeviceNode->CapabilityFlags)
403 {
404 ExFreePool(DeviceNode->CapabilityFlags);
405 }
406
407 if (DeviceNode->CmResourceList)
408 {
409 ExFreePool(DeviceNode->CmResourceList);
410 }
411
412 if (DeviceNode->BootResourcesList)
413 {
414 ExFreePool(DeviceNode->BootResourcesList);
415 }
416
417 if (DeviceNode->ResourceRequirementsList)
418 {
419 ExFreePool(DeviceNode->ResourceRequirementsList);
420 }
421
422 RtlFreeUnicodeString(&DeviceNode->DeviceID);
423
424 RtlFreeUnicodeString(&DeviceNode->InstanceID);
425
426 RtlFreeUnicodeString(&DeviceNode->HardwareIDs);
427
428 RtlFreeUnicodeString(&DeviceNode->CompatibleIDs);
429
430 RtlFreeUnicodeString(&DeviceNode->DeviceText);
431
432 RtlFreeUnicodeString(&DeviceNode->DeviceTextLocation);
433
434 if (DeviceNode->BusInformation)
435 {
436 ExFreePool(DeviceNode->BusInformation);
437 }
438
439 ExFreePool(DeviceNode);
440
441 return STATUS_SUCCESS;
442 }
443
444 NTSTATUS
445 IopInitiatePnpIrp(
446 PDEVICE_OBJECT DeviceObject,
447 PIO_STATUS_BLOCK IoStatusBlock,
448 ULONG MinorFunction,
449 PIO_STACK_LOCATION Stack OPTIONAL)
450 {
451 PDEVICE_OBJECT TopDeviceObject;
452 PIO_STACK_LOCATION IrpSp;
453 NTSTATUS Status;
454 KEVENT Event;
455 PIRP Irp;
456
457 /* Always call the top of the device stack */
458 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
459
460 KeInitializeEvent(
461 &Event,
462 NotificationEvent,
463 FALSE);
464
465 /* PNP IRPs are always initialized with a status code of
466 STATUS_NOT_IMPLEMENTED */
467 IoStatusBlock->Status = STATUS_NOT_IMPLEMENTED;
468 IoStatusBlock->Information = 0;
469
470 Irp = IoBuildSynchronousFsdRequest(
471 IRP_MJ_PNP,
472 TopDeviceObject,
473 NULL,
474 0,
475 NULL,
476 &Event,
477 IoStatusBlock);
478
479 IrpSp = IoGetNextIrpStackLocation(Irp);
480 IrpSp->MinorFunction = MinorFunction;
481
482 if (Stack)
483 {
484 RtlMoveMemory(
485 &IrpSp->Parameters,
486 &Stack->Parameters,
487 sizeof(Stack->Parameters));
488 }
489
490 Status = IoCallDriver(TopDeviceObject, Irp);
491 if (Status == STATUS_PENDING)
492 {
493 KeWaitForSingleObject(
494 &Event,
495 Executive,
496 KernelMode,
497 FALSE,
498 NULL);
499 Status = IoStatusBlock->Status;
500 }
501
502 ObDereferenceObject(TopDeviceObject);
503
504 return Status;
505 }
506
507
508 NTSTATUS
509 IopQueryCapabilities(
510 PDEVICE_OBJECT Pdo,
511 PDEVICE_CAPABILITIES *Capabilities)
512 {
513 IO_STATUS_BLOCK IoStatusBlock;
514 PDEVICE_CAPABILITIES Caps;
515 IO_STACK_LOCATION Stack;
516 NTSTATUS Status;
517
518 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
519
520 *Capabilities = NULL;
521
522 Caps = ExAllocatePool(PagedPool, sizeof(DEVICE_CAPABILITIES));
523 if (!Caps)
524 {
525 return STATUS_INSUFFICIENT_RESOURCES;
526 }
527
528 RtlZeroMemory(Caps, sizeof(DEVICE_CAPABILITIES));
529 Caps->Size = sizeof(DEVICE_CAPABILITIES);
530 Caps->Version = 1;
531 Caps->Address = -1;
532 Caps->UINumber = -1;
533
534 Stack.Parameters.DeviceCapabilities.Capabilities = Caps;
535
536 Status = IopInitiatePnpIrp(
537 Pdo,
538 &IoStatusBlock,
539 IRP_MN_QUERY_CAPABILITIES,
540 &Stack);
541 if (NT_SUCCESS(Status))
542 {
543 *Capabilities = Caps;
544 }
545 else
546 {
547 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
548 }
549
550 return Status;
551 }
552
553
554 NTSTATUS
555 IopTraverseDeviceTreeNode(
556 PDEVICETREE_TRAVERSE_CONTEXT Context)
557 {
558 PDEVICE_NODE ParentDeviceNode;
559 PDEVICE_NODE ChildDeviceNode;
560 NTSTATUS Status;
561
562 /* Copy context data so we don't overwrite it in subsequent calls to this function */
563 ParentDeviceNode = Context->DeviceNode;
564
565 /* Call the action routine */
566 Status = (Context->Action)(ParentDeviceNode, Context->Context);
567 if (!NT_SUCCESS(Status))
568 {
569 return Status;
570 }
571
572 /* Traversal of all children nodes */
573 for (ChildDeviceNode = ParentDeviceNode->Child;
574 ChildDeviceNode != NULL;
575 ChildDeviceNode = ChildDeviceNode->NextSibling)
576 {
577 /* Pass the current device node to the action routine */
578 Context->DeviceNode = ChildDeviceNode;
579
580 Status = IopTraverseDeviceTreeNode(Context);
581 if (!NT_SUCCESS(Status))
582 {
583 return Status;
584 }
585 }
586
587 return Status;
588 }
589
590
591 NTSTATUS
592 IopTraverseDeviceTree(
593 PDEVICETREE_TRAVERSE_CONTEXT Context)
594 {
595 NTSTATUS Status;
596
597 DPRINT("Context %x\n", Context);
598
599 DPRINT("IopTraverseDeviceTree(DeviceNode %x FirstDeviceNode %x Action %x Context %x)\n",
600 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
601
602 /* Start from the specified device node */
603 Context->DeviceNode = Context->FirstDeviceNode;
604
605 /* Recursively traverse the device tree */
606 Status = IopTraverseDeviceTreeNode(Context);
607 if (Status == STATUS_UNSUCCESSFUL)
608 {
609 /* The action routine just wanted to terminate the traversal with status
610 code STATUS_SUCCESS */
611 Status = STATUS_SUCCESS;
612 }
613
614 return Status;
615 }
616
617
618 NTSTATUS
619 IopActionInterrogateDeviceStack(
620 PDEVICE_NODE DeviceNode,
621 PVOID Context)
622 /*
623 * FUNCTION: Retrieve information for all (direct) child nodes of a parent node
624 * ARGUMENTS:
625 * DeviceNode = Pointer to device node
626 * Context = Pointer to parent node to retrieve child node information for
627 * NOTES:
628 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
629 * when we reach a device node which is not a direct child of the device node
630 * for which we retrieve information of child nodes for. Any errors that occur
631 * is logged instead so that all child services have a chance of beeing
632 * interrogated.
633 */
634 {
635 IO_STATUS_BLOCK IoStatusBlock;
636 PDEVICE_NODE ParentDeviceNode;
637 WCHAR InstancePath[MAX_PATH];
638 IO_STACK_LOCATION Stack;
639 NTSTATUS Status;
640
641 DPRINT("DeviceNode %x Context %x\n", DeviceNode, Context);
642
643 DPRINT("PDO %x\n", DeviceNode->Pdo);
644
645
646 ParentDeviceNode = (PDEVICE_NODE)Context;
647
648 /* We are called for the parent too, but we don't need to do special
649 handling for this node */
650 if (DeviceNode == ParentDeviceNode)
651 {
652 DPRINT("Success\n");
653 return STATUS_SUCCESS;
654 }
655
656 /* Make sure this device node is a direct child of the parent device node
657 that is given as an argument */
658 if (DeviceNode->Parent != ParentDeviceNode)
659 {
660 /* Stop the traversal immediately and indicate successful operation */
661 DPRINT("Stop\n");
662 return STATUS_UNSUCCESSFUL;
663 }
664
665
666 /* FIXME: For critical errors, cleanup and disable device, but always return STATUS_SUCCESS */
667
668
669 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
670
671 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
672
673 Status = IopInitiatePnpIrp(
674 DeviceNode->Pdo,
675 &IoStatusBlock,
676 IRP_MN_QUERY_ID,
677 &Stack);
678 if (NT_SUCCESS(Status))
679 {
680 RtlInitUnicodeString(
681 &DeviceNode->DeviceID,
682 (LPWSTR)IoStatusBlock.Information);
683
684 /* FIXME: Check for valid characters, if there is invalid characters then bugcheck */
685 }
686 else
687 {
688 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
689 RtlInitUnicodeString(&DeviceNode->DeviceID, NULL);
690 }
691
692
693 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
694
695 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
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->InstanceID,
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->InstanceID, NULL);
714 }
715
716
717 /* FIXME: SEND IRP_QUERY_ID.BusQueryHardwareIDs */
718 /* FIXME: SEND IRP_QUERY_ID.BusQueryCompatibleIDs */
719
720
721 Status = IopQueryCapabilities(DeviceNode->Pdo, &DeviceNode->CapabilityFlags);
722 if (NT_SUCCESS(Status))
723 {
724 }
725 else
726 {
727 }
728
729
730 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
731
732 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
733 Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
734
735 Status = IopInitiatePnpIrp(
736 DeviceNode->Pdo,
737 &IoStatusBlock,
738 IRP_MN_QUERY_DEVICE_TEXT,
739 &Stack);
740 if (NT_SUCCESS(Status))
741 {
742 RtlInitUnicodeString(
743 &DeviceNode->DeviceText,
744 (LPWSTR)IoStatusBlock.Information);
745 }
746 else
747 {
748 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
749 RtlInitUnicodeString(&DeviceNode->DeviceText, NULL);
750 }
751
752
753 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
754
755 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
756 Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
757
758 Status = IopInitiatePnpIrp(
759 DeviceNode->Pdo,
760 &IoStatusBlock,
761 IRP_MN_QUERY_DEVICE_TEXT,
762 &Stack);
763 if (NT_SUCCESS(Status))
764 {
765 RtlInitUnicodeString(
766 &DeviceNode->DeviceTextLocation,
767 (LPWSTR)IoStatusBlock.Information);
768 }
769 else
770 {
771 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
772 RtlInitUnicodeString(&DeviceNode->DeviceTextLocation, NULL);
773 }
774
775
776 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
777
778 Status = IopInitiatePnpIrp(
779 DeviceNode->Pdo,
780 &IoStatusBlock,
781 IRP_MN_QUERY_BUS_INFORMATION,
782 NULL);
783 if (NT_SUCCESS(Status))
784 {
785 DeviceNode->BusInformation =
786 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
787 }
788 else
789 {
790 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
791 DeviceNode->BusInformation = NULL;
792 }
793
794
795 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
796
797 Status = IopInitiatePnpIrp(
798 DeviceNode->Pdo,
799 &IoStatusBlock,
800 IRP_MN_QUERY_RESOURCES,
801 NULL);
802 if (NT_SUCCESS(Status))
803 {
804 DeviceNode->BootResourcesList =
805 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
806 }
807 else
808 {
809 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
810 DeviceNode->BootResourcesList = NULL;
811 }
812
813
814 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
815
816 Status = IopInitiatePnpIrp(
817 DeviceNode->Pdo,
818 &IoStatusBlock,
819 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
820 NULL);
821 if (NT_SUCCESS(Status))
822 {
823 DeviceNode->ResourceRequirementsList =
824 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
825 }
826 else
827 {
828 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
829 DeviceNode->ResourceRequirementsList = NULL;
830 }
831
832
833 /* Assemble the instance path for the device */
834
835 wcscpy(InstancePath, DeviceNode->DeviceID.Buffer);
836 wcscat(InstancePath, L"\\");
837 wcscat(InstancePath, DeviceNode->InstanceID.Buffer);
838
839 if (!DeviceNode->CapabilityFlags->UniqueID)
840 {
841 DPRINT("Instance ID is not unique\n");
842 /* FIXME: Add information from parent bus driver to InstancePath */
843 }
844
845 if (!IopCreateUnicodeString(&DeviceNode->InstancePath, InstancePath, PagedPool)) {
846 DPRINT("No resources\n");
847 /* FIXME: Cleanup and disable device */
848 }
849
850 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
851
852 return STATUS_SUCCESS;
853 }
854
855
856 NTSTATUS
857 IopActionConfigureChildServices(
858 PDEVICE_NODE DeviceNode,
859 PVOID Context)
860 /*
861 * FUNCTION: Retrieve configuration for all (direct) child nodes of a parent node
862 * ARGUMENTS:
863 * DeviceNode = Pointer to device node
864 * Context = Pointer to parent node to retrieve child node configuration for
865 * NOTES:
866 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
867 * when we reach a device node which is not a direct child of the device
868 * node for which we configure child services for. Any errors that occur is
869 * logged instead so that all child services have a chance of beeing
870 * configured.
871 */
872 {
873 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
874 PDEVICE_NODE ParentDeviceNode;
875 PUNICODE_STRING Service;
876 HANDLE KeyHandle;
877 NTSTATUS Status;
878
879 DPRINT("DeviceNode %x Context %x\n", DeviceNode, Context);
880
881 ParentDeviceNode = (PDEVICE_NODE)Context;
882
883 /* We are called for the parent too, but we don't need to do special
884 handling for this node */
885 if (DeviceNode == ParentDeviceNode)
886 {
887 DPRINT("Success\n");
888 return STATUS_SUCCESS;
889 }
890
891 /* Make sure this device node is a direct child of the parent device node
892 that is given as an argument */
893 if (DeviceNode->Parent != ParentDeviceNode)
894 {
895 /* Stop the traversal immediately and indicate successful operation */
896 DPRINT("Stop\n");
897 return STATUS_UNSUCCESSFUL;
898 }
899
900 /* Retrieve configuration from Enum key */
901
902 Service = &DeviceNode->ServiceName;
903
904 Status = RtlpGetRegistryHandle(
905 RTL_REGISTRY_ENUM,
906 DeviceNode->InstancePath.Buffer,
907 TRUE,
908 &KeyHandle);
909 if (!NT_SUCCESS(Status))
910 {
911 DPRINT("RtlpGetRegistryHandle() failed (Status %x)\n", Status);
912 return Status;
913 }
914
915 RtlZeroMemory(QueryTable, sizeof(QueryTable));
916
917 RtlInitUnicodeString(Service, NULL);
918
919 QueryTable[0].Name = L"Service";
920 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
921 QueryTable[0].EntryContext = Service;
922
923 Status = RtlQueryRegistryValues(
924 RTL_REGISTRY_HANDLE,
925 (PWSTR)KeyHandle,
926 QueryTable,
927 NULL,
928 NULL);
929 NtClose(KeyHandle);
930
931 DPRINT("RtlQueryRegistryValues() returned status %x\n", Status);
932
933 if (!NT_SUCCESS(Status))
934 {
935 /* FIXME: Log the error */
936 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
937 DeviceNode->InstancePath.Buffer, Status);
938 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
939 return STATUS_SUCCESS;
940 }
941
942 DPRINT("Got Service %S\n", Service->Buffer);
943
944 return STATUS_SUCCESS;
945 }
946
947
948 NTSTATUS
949 IopActionInitChildServices(
950 PDEVICE_NODE DeviceNode,
951 PVOID Context)
952 /*
953 * FUNCTION: Initialize the service for all (direct) child nodes of a parent node
954 * ARGUMENTS:
955 * DeviceNode = Pointer to device node
956 * Context = Pointer to parent node to initialize child node services for
957 * NOTES:
958 * If the driver image for a service is not loaded and initialized
959 * it is done here too.
960 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
961 * when we reach a device node which is not a direct child of the device
962 * node for which we initialize child services for. Any errors that occur is
963 * logged instead so that all child services have a chance of beeing
964 * initialized.
965 */
966 {
967 PDEVICE_NODE ParentDeviceNode;
968 NTSTATUS Status;
969
970 DPRINT("DeviceNode %x Context %x\n", DeviceNode, Context);
971
972 ParentDeviceNode = (PDEVICE_NODE)Context;
973
974 /* We are called for the parent too, but we don't need to do special
975 handling for this node */
976 if (DeviceNode == ParentDeviceNode)
977 {
978 DPRINT("Success\n");
979 return STATUS_SUCCESS;
980 }
981
982 /* Make sure this device node is a direct child of the parent device node
983 that is given as an argument */
984 if (DeviceNode->Parent != ParentDeviceNode)
985 {
986 /* Stop the traversal immediately and indicate successful operation */
987 DPRINT("Stop\n");
988 return STATUS_UNSUCCESSFUL;
989 }
990
991 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
992 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
993 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
994 {
995 Status = IopInitializeDeviceNodeService(DeviceNode);
996 if (NT_SUCCESS(Status))
997 {
998 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
999 }
1000 else
1001 {
1002 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1003
1004 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1005 CPRINT("Initialization of service %S failed (Status %x)\n",
1006 DeviceNode->ServiceName.Buffer, Status);
1007 }
1008 }
1009 else
1010 {
1011 DPRINT("Service %S is disabled or already initialized\n",
1012 DeviceNode->ServiceName.Buffer);
1013 }
1014
1015 return STATUS_SUCCESS;
1016 }
1017
1018
1019 NTSTATUS
1020 IopInterrogateBusExtender(
1021 PDEVICE_NODE DeviceNode,
1022 PDEVICE_OBJECT Pdo,
1023 BOOLEAN BootDriversOnly)
1024 {
1025 DEVICETREE_TRAVERSE_CONTEXT Context;
1026 PDEVICE_RELATIONS DeviceRelations;
1027 IO_STATUS_BLOCK IoStatusBlock;
1028 PDEVICE_NODE ChildDeviceNode;
1029 IO_STACK_LOCATION Stack;
1030 NTSTATUS Status;
1031 ULONG i;
1032
1033 DPRINT("DeviceNode %x Pdo %x BootDriversOnly %d\n", DeviceNode, Pdo, BootDriversOnly);
1034
1035 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
1036
1037 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
1038
1039 Status = IopInitiatePnpIrp(
1040 Pdo,
1041 &IoStatusBlock,
1042 IRP_MN_QUERY_DEVICE_RELATIONS,
1043 &Stack);
1044 if (!NT_SUCCESS(Status))
1045 {
1046 DPRINT("IopInitiatePnpIrp() failed\n");
1047 return Status;
1048 }
1049
1050 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
1051
1052 if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
1053 {
1054 DPRINT("No PDOs\n");
1055 if (DeviceRelations)
1056 {
1057 ExFreePool(DeviceRelations);
1058 }
1059 return STATUS_SUCCESS;
1060 }
1061
1062 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
1063
1064 #ifdef DBG
1065 {
1066 ULONG i;
1067
1068 DPRINT("DeviceRelations %x\n", DeviceRelations);
1069 DPRINT("Count %x\n", DeviceRelations->Count);
1070 for (i = 0; i < DeviceRelations->Count; i++)
1071 DPRINT("Object(PDO) %x\n", DeviceRelations->Objects[i]);
1072 }
1073 #endif
1074
1075 /* Create device nodes for all discovered devices */
1076 for (i = 0; i < DeviceRelations->Count; i++)
1077 {
1078 Status = IopCreateDeviceNode(
1079 DeviceNode,
1080 DeviceRelations->Objects[i],
1081 &ChildDeviceNode);
1082 if (!NT_SUCCESS(Status))
1083 {
1084 DPRINT("No resources\n");
1085 for (i = 0; i < DeviceRelations->Count; i++)
1086 ObDereferenceObject(DeviceRelations->Objects[i]);
1087 ExFreePool(DeviceRelations);
1088 return STATUS_INSUFFICIENT_RESOURCES;
1089 }
1090 }
1091
1092 ExFreePool(DeviceRelations);
1093
1094
1095 /* Retrieve information about all discovered children from the bus driver */
1096
1097 IopInitDeviceTreeTraverseContext(
1098 &Context,
1099 DeviceNode,
1100 IopActionInterrogateDeviceStack,
1101 DeviceNode);
1102
1103 Status = IopTraverseDeviceTree(&Context);
1104 if (!NT_SUCCESS(Status))
1105 {
1106 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1107 return Status;
1108 }
1109
1110
1111 /* Retrieve configuration from the registry for discovered children */
1112
1113 IopInitDeviceTreeTraverseContext(
1114 &Context,
1115 DeviceNode,
1116 IopActionConfigureChildServices,
1117 DeviceNode);
1118
1119 Status = IopTraverseDeviceTree(&Context);
1120 if (!NT_SUCCESS(Status))
1121 {
1122 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1123 return Status;
1124 }
1125
1126
1127 /* Initialize services for discovered children */
1128
1129 IopInitDeviceTreeTraverseContext(
1130 &Context,
1131 DeviceNode,
1132 IopActionInitChildServices,
1133 DeviceNode);
1134
1135 Status = IopTraverseDeviceTree(&Context);
1136 if (!NT_SUCCESS(Status))
1137 {
1138 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
1139 return Status;
1140 }
1141
1142 return Status;
1143 }
1144
1145
1146 VOID IopLoadBootStartDrivers(VOID)
1147 {
1148 IopInterrogateBusExtender(
1149 IopRootDeviceNode,
1150 IopRootDeviceNode->Pdo,
1151 TRUE);
1152 }
1153
1154 VOID PnpInit(VOID)
1155 {
1156 PDEVICE_OBJECT Pdo;
1157 NTSTATUS Status;
1158
1159 DPRINT("Called\n");
1160
1161 KeInitializeSpinLock(&IopDeviceTreeLock);
1162
1163 Status = IopCreateDriverObject(&IopRootDriverObject);
1164 if (!NT_SUCCESS(Status))
1165 {
1166 CPRINT("IoCreateDriverObject() failed\n");
1167 KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1168 }
1169
1170 Status = IoCreateDevice(
1171 IopRootDriverObject,
1172 0,
1173 NULL,
1174 FILE_DEVICE_CONTROLLER,
1175 0,
1176 FALSE,
1177 &Pdo);
1178 if (!NT_SUCCESS(Status))
1179 {
1180 CPRINT("IoCreateDevice() failed\n");
1181 KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1182 }
1183
1184 Status = IopCreateDeviceNode(
1185 NULL,
1186 Pdo,
1187 &IopRootDeviceNode);
1188 if (!NT_SUCCESS(Status))
1189 {
1190 CPRINT("Insufficient resources\n");
1191 KeBugCheck(PHASE1_INITIALIZATION_FAILED);
1192 }
1193
1194 IopRootDeviceNode->Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
1195
1196 IopRootDeviceNode->DriverObject = IopRootDriverObject;
1197
1198 PnpRootDriverEntry(IopRootDriverObject, NULL);
1199
1200 IopRootDriverObject->DriverExtension->AddDevice(
1201 IopRootDriverObject,
1202 IopRootDeviceNode->Pdo);
1203 }
1204
1205 /* EOF */