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