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