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