1be3d8cbac703ef93567a111778c2d16718021b2
[reactos.git] / reactos / ntoskrnl / io / pnpmgr.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 *
7 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 PDEVICE_NODE IopRootDeviceNode;
20 KSPIN_LOCK IopDeviceTreeLock;
21
22 /* DATA **********************************************************************/
23
24 PDRIVER_OBJECT IopRootDriverObject;
25 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
26
27 /* FUNCTIONS *****************************************************************/
28
29 PDEVICE_NODE FASTCALL
30 IopGetDeviceNode(
31 PDEVICE_OBJECT DeviceObject)
32 {
33 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
34 }
35
36 NTSTATUS
37 STDCALL
38 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
39 PDEVICE_CAPABILITIES DeviceCaps)
40 {
41 IO_STATUS_BLOCK StatusBlock;
42 IO_STACK_LOCATION Stack;
43
44 /* Set up the Header */
45 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
46 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
47 DeviceCaps->Version = 1;
48 DeviceCaps->Address = -1;
49 DeviceCaps->UINumber = -1;
50
51 /* Set up the Stack */
52 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
53 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
54
55 /* Send the IRP */
56 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
57 &StatusBlock,
58 IRP_MN_QUERY_CAPABILITIES,
59 &Stack);
60 }
61
62 /*
63 * @implemented
64 */
65 VOID
66 STDCALL
67 IoInvalidateDeviceRelations(
68 IN PDEVICE_OBJECT DeviceObject,
69 IN DEVICE_RELATION_TYPE Type)
70 {
71 IopInvalidateDeviceRelations(IopGetDeviceNode(DeviceObject), Type);
72 }
73
74 /*
75 * @unimplemented
76 */
77 NTSTATUS
78 STDCALL
79 IoGetDeviceProperty(
80 IN PDEVICE_OBJECT DeviceObject,
81 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
82 IN ULONG BufferLength,
83 OUT PVOID PropertyBuffer,
84 OUT PULONG ResultLength)
85 {
86 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
87 DEVICE_CAPABILITIES DeviceCaps;
88 ULONG Length;
89 PVOID Data = NULL;
90 PWSTR Ptr;
91 NTSTATUS Status;
92
93 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
94
95 if (DeviceNode == NULL)
96 return STATUS_INVALID_DEVICE_REQUEST;
97
98 switch (DeviceProperty)
99 {
100 case DevicePropertyBusNumber:
101 Length = sizeof(ULONG);
102 Data = &DeviceNode->ChildBusNumber;
103 break;
104
105 /* Complete, untested */
106 case DevicePropertyBusTypeGuid:
107 /* Sanity check */
108 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
109 (DeviceNode->ChildBusTypeIndex < IopBusTypeGuidList->GuidCount))
110 {
111 /* Return the GUID */
112 *ResultLength = sizeof(GUID);
113
114 /* Check if the buffer given was large enough */
115 if (BufferLength < *ResultLength)
116 {
117 return STATUS_BUFFER_TOO_SMALL;
118 }
119
120 /* Copy the GUID */
121 RtlCopyMemory(PropertyBuffer,
122 &(IopBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
123 sizeof(GUID));
124 return STATUS_SUCCESS;
125 }
126 else
127 {
128 return STATUS_OBJECT_NAME_NOT_FOUND;
129 }
130 break;
131
132 case DevicePropertyLegacyBusType:
133 Length = sizeof(INTERFACE_TYPE);
134 Data = &DeviceNode->ChildInterfaceType;
135 break;
136
137 case DevicePropertyAddress:
138
139 /* Query the device caps */
140 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
141 if (NT_SUCCESS(Status) && (DeviceCaps.Address != -1))
142 {
143 /* Return length */
144 *ResultLength = sizeof(ULONG);
145
146 /* Check if the buffer given was large enough */
147 if (BufferLength < *ResultLength)
148 {
149 return STATUS_BUFFER_TOO_SMALL;
150 }
151
152 /* Return address */
153 *(PULONG)PropertyBuffer = DeviceCaps.Address;
154 return STATUS_SUCCESS;
155 }
156 else
157 {
158 return STATUS_OBJECT_NAME_NOT_FOUND;
159 }
160 break;
161
162 // case DevicePropertyUINumber:
163 // if (DeviceNode->CapabilityFlags == NULL)
164 // return STATUS_INVALID_DEVICE_REQUEST;
165 // Length = sizeof(ULONG);
166 // Data = &DeviceNode->CapabilityFlags->UINumber;
167 // break;
168
169 case DevicePropertyClassName:
170 case DevicePropertyClassGuid:
171 case DevicePropertyDriverKeyName:
172 case DevicePropertyManufacturer:
173 case DevicePropertyFriendlyName:
174 case DevicePropertyHardwareID:
175 case DevicePropertyCompatibleIDs:
176 case DevicePropertyDeviceDescription:
177 case DevicePropertyLocationInformation:
178 case DevicePropertyUINumber:
179 {
180 LPWSTR RegistryPropertyName, KeyNameBuffer;
181 UNICODE_STRING KeyName, ValueName;
182 OBJECT_ATTRIBUTES ObjectAttributes;
183 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
184 ULONG ValueInformationLength;
185 HANDLE KeyHandle;
186 NTSTATUS Status;
187
188 switch (DeviceProperty)
189 {
190 case DevicePropertyClassName:
191 RegistryPropertyName = L"Class"; break;
192 case DevicePropertyClassGuid:
193 RegistryPropertyName = L"ClassGuid"; break;
194 case DevicePropertyDriverKeyName:
195 RegistryPropertyName = L"Driver"; break;
196 case DevicePropertyManufacturer:
197 RegistryPropertyName = L"Mfg"; break;
198 case DevicePropertyFriendlyName:
199 RegistryPropertyName = L"FriendlyName"; break;
200 case DevicePropertyHardwareID:
201 RegistryPropertyName = L"HardwareID"; break;
202 case DevicePropertyCompatibleIDs:
203 RegistryPropertyName = L"CompatibleIDs"; break;
204 case DevicePropertyDeviceDescription:
205 RegistryPropertyName = L"DeviceDesc"; break;
206 case DevicePropertyLocationInformation:
207 RegistryPropertyName = L"LocationInformation"; break;
208 case DevicePropertyUINumber:
209 RegistryPropertyName = L"UINumber"; break;
210 default:
211 RegistryPropertyName = NULL; break;
212 }
213
214 KeyNameBuffer = ExAllocatePool(PagedPool,
215 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
216
217 DPRINT("KeyNameBuffer: 0x%p, value %S\n",
218 KeyNameBuffer, RegistryPropertyName);
219
220 if (KeyNameBuffer == NULL)
221 return STATUS_INSUFFICIENT_RESOURCES;
222
223 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
224 wcscat(KeyNameBuffer, DeviceNode->InstancePath.Buffer);
225 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
226 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
227 OBJ_CASE_INSENSITIVE, NULL, NULL);
228
229 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
230 ExFreePool(KeyNameBuffer);
231 if (!NT_SUCCESS(Status))
232 return Status;
233
234 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
235 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
236 Data[0]) + BufferLength;
237 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
238 if (ValueInformation == NULL)
239 {
240 ZwClose(KeyHandle);
241 return STATUS_INSUFFICIENT_RESOURCES;
242 }
243
244 Status = ZwQueryValueKey(KeyHandle, &ValueName,
245 KeyValuePartialInformation, ValueInformation,
246 ValueInformationLength,
247 &ValueInformationLength);
248 *ResultLength = ValueInformation->DataLength;
249 ZwClose(KeyHandle);
250
251 if (ValueInformation->DataLength > BufferLength)
252 Status = STATUS_BUFFER_TOO_SMALL;
253
254 if (!NT_SUCCESS(Status))
255 {
256 ExFreePool(ValueInformation);
257 return Status;
258 }
259
260 /* FIXME: Verify the value (NULL-terminated, correct format). */
261
262 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
263 ValueInformation->DataLength);
264 ExFreePool(ValueInformation);
265
266 return STATUS_SUCCESS;
267 }
268
269 case DevicePropertyBootConfiguration:
270 Length = 0;
271 if (DeviceNode->BootResources->Count != 0)
272 {
273 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
274 }
275 Data = &DeviceNode->BootResources;
276 break;
277
278 /* FIXME: use a translated boot configuration instead */
279 case DevicePropertyBootConfigurationTranslated:
280 Length = 0;
281 if (DeviceNode->BootResources->Count != 0)
282 {
283 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
284 }
285 Data = &DeviceNode->BootResources;
286 break;
287
288 case DevicePropertyEnumeratorName:
289 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
290 if (Ptr != NULL)
291 {
292 Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR);
293 Data = DeviceNode->InstancePath.Buffer;
294 }
295 else
296 {
297 Length = 0;
298 Data = NULL;
299 }
300 break;
301
302 case DevicePropertyPhysicalDeviceObjectName:
303 Length = DeviceNode->InstancePath.Length + sizeof(WCHAR);
304 Data = DeviceNode->InstancePath.Buffer;
305 break;
306
307 default:
308 return STATUS_INVALID_PARAMETER_2;
309 }
310
311 *ResultLength = Length;
312 if (BufferLength < Length)
313 return STATUS_BUFFER_TOO_SMALL;
314 RtlCopyMemory(PropertyBuffer, Data, Length);
315
316 /* Terminate the string */
317 if (DeviceProperty == DevicePropertyEnumeratorName
318 || DeviceProperty == DevicePropertyPhysicalDeviceObjectName)
319 {
320 Ptr = (PWSTR)PropertyBuffer;
321 Ptr[(Length / sizeof(WCHAR)) - 1] = 0;
322 }
323
324 return STATUS_SUCCESS;
325 }
326
327 /*
328 * @unimplemented
329 */
330 VOID
331 STDCALL
332 IoInvalidateDeviceState(
333 IN PDEVICE_OBJECT PhysicalDeviceObject)
334 {
335 }
336
337 /**
338 * @name IoOpenDeviceRegistryKey
339 *
340 * Open a registry key unique for a specified driver or device instance.
341 *
342 * @param DeviceObject Device to get the registry key for.
343 * @param DevInstKeyType Type of the key to return.
344 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
345 * @param DevInstRegKey Handle to the opened registry key on
346 * successful return.
347 *
348 * @return Status.
349 *
350 * @implemented
351 */
352 NTSTATUS
353 STDCALL
354 IoOpenDeviceRegistryKey(
355 IN PDEVICE_OBJECT DeviceObject,
356 IN ULONG DevInstKeyType,
357 IN ACCESS_MASK DesiredAccess,
358 OUT PHANDLE DevInstRegKey)
359 {
360 static WCHAR RootKeyName[] =
361 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
362 static WCHAR ProfileKeyName[] =
363 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
364 static WCHAR ClassKeyName[] = L"Control\\Class\\";
365 static WCHAR EnumKeyName[] = L"Enum\\";
366 static WCHAR DeviceParametersKeyName[] = L"Device Parameters\\";
367 ULONG KeyNameLength;
368 LPWSTR KeyNameBuffer;
369 UNICODE_STRING KeyName;
370 ULONG DriverKeyLength;
371 OBJECT_ATTRIBUTES ObjectAttributes;
372 PDEVICE_NODE DeviceNode = NULL;
373 NTSTATUS Status;
374
375 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
376 return STATUS_INVALID_PARAMETER;
377
378 /*
379 * Calculate the length of the base key name. This is the full
380 * name for driver key or the name excluding "Device Parameters"
381 * subkey for device key.
382 */
383
384 KeyNameLength = sizeof(RootKeyName);
385 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
386 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
387 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
388 {
389 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
390 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
391 0, NULL, &DriverKeyLength);
392 if (Status != STATUS_BUFFER_TOO_SMALL)
393 return Status;
394 KeyNameLength += DriverKeyLength;
395 }
396 else
397 {
398 DeviceNode = IopGetDeviceNode(DeviceObject);
399 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
400 DeviceNode->InstancePath.Length;
401 }
402
403 /*
404 * Now allocate the buffer for the key name...
405 */
406
407 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
408 if (KeyNameBuffer == NULL)
409 return STATUS_INSUFFICIENT_RESOURCES;
410
411 KeyName.Length = 0;
412 KeyName.MaximumLength = KeyNameLength;
413 KeyName.Buffer = KeyNameBuffer;
414
415 /*
416 * ...and build the key name.
417 */
418
419 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
420 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
421
422 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
423 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
424
425 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
426 {
427 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
428 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
429 DriverKeyLength, KeyNameBuffer +
430 (KeyName.Length / sizeof(WCHAR)),
431 &DriverKeyLength);
432 if (!NT_SUCCESS(Status))
433 {
434 ExFreePool(KeyNameBuffer);
435 return Status;
436 }
437 KeyName.Length += DriverKeyLength - sizeof(UNICODE_NULL);
438 }
439 else
440 {
441 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
442 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
443 if (DeviceNode->InstancePath.Length == 0)
444 {
445 ExFreePool(KeyNameBuffer);
446 return Status;
447 }
448 }
449
450 /*
451 * Open the base key.
452 */
453
454 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
455 OBJ_CASE_INSENSITIVE, NULL, NULL);
456 Status = ZwOpenKey(DevInstRegKey, DesiredAccess, &ObjectAttributes);
457 ExFreePool(KeyNameBuffer);
458
459 /*
460 * For driver key we're done now. Also if the base key doesn't
461 * exist we can bail out with error...
462 */
463
464 if ((DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) || !NT_SUCCESS(Status))
465 return Status;
466
467 /*
468 * Let's go further. For device key we must open "Device Parameters"
469 * subkey and create it if it doesn't exist yet.
470 */
471
472 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
473 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
474 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
475 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
476 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
477 ZwClose(ObjectAttributes.RootDirectory);
478
479 return Status;
480 }
481
482 /*
483 * @unimplemented
484 */
485 VOID
486 STDCALL
487 IoRequestDeviceEject(
488 IN PDEVICE_OBJECT PhysicalDeviceObject
489 )
490 {
491 UNIMPLEMENTED;
492 }
493
494
495 NTSTATUS
496 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
497 {
498 KIRQL OldIrql;
499
500 if (PopSystemPowerDeviceNode)
501 {
502 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
503 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
504 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
505
506 return STATUS_SUCCESS;
507 }
508
509 return STATUS_UNSUCCESSFUL;
510 }
511
512 USHORT
513 STDCALL
514 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
515 {
516 USHORT i = 0, FoundIndex = 0xFFFF;
517 ULONG NewSize;
518 PVOID NewList;
519
520 /* Acquire the lock */
521 ExAcquireFastMutex(&IopBusTypeGuidList->Lock);
522
523 /* Loop all entries */
524 while (i < IopBusTypeGuidList->GuidCount)
525 {
526 /* Try to find a match */
527 if (RtlCompareMemory(BusTypeGuid,
528 &IopBusTypeGuidList->Guids[i],
529 sizeof(GUID)))
530 {
531 /* Found it */
532 FoundIndex = i;
533 goto Quickie;
534 }
535 }
536
537 /* Check if we have to grow the list */
538 if (IopBusTypeGuidList->GuidCount)
539 {
540 /* Calculate the new size */
541 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
542 (sizeof(GUID) * IopBusTypeGuidList->GuidCount);
543
544 /* Allocate the new copy */
545 NewList = ExAllocatePool(PagedPool, NewSize);
546
547 /* Now copy them, decrease the size too */
548 NewSize -= sizeof(GUID);
549 RtlCopyMemory(NewList, IopBusTypeGuidList, NewSize);
550
551 /* Free the old list */
552 ExFreePool(IopBusTypeGuidList);
553
554 /* Use the new buffer */
555 IopBusTypeGuidList = NewList;
556 }
557
558 /* Copy the new GUID */
559 RtlCopyMemory(&IopBusTypeGuidList->Guids[IopBusTypeGuidList->GuidCount],
560 BusTypeGuid,
561 sizeof(GUID));
562
563 /* The new entry is the index */
564 FoundIndex = IopBusTypeGuidList->GuidCount;
565 IopBusTypeGuidList->GuidCount++;
566
567 Quickie:
568 ExReleaseFastMutex(&IopBusTypeGuidList->Lock);
569 return FoundIndex;
570 }
571
572 /*
573 * DESCRIPTION
574 * Creates a device node
575 *
576 * ARGUMENTS
577 * ParentNode = Pointer to parent device node
578 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
579 * to have the root device node create one
580 * (eg. for legacy drivers)
581 * DeviceNode = Pointer to storage for created device node
582 *
583 * RETURN VALUE
584 * Status
585 */
586 NTSTATUS
587 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
588 PDEVICE_OBJECT PhysicalDeviceObject,
589 PDEVICE_NODE *DeviceNode)
590 {
591 PDEVICE_NODE Node;
592 NTSTATUS Status;
593 KIRQL OldIrql;
594
595 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p\n",
596 ParentNode, PhysicalDeviceObject);
597
598 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
599 if (!Node)
600 {
601 return STATUS_INSUFFICIENT_RESOURCES;
602 }
603
604 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
605
606 if (!PhysicalDeviceObject)
607 {
608 Status = PnpRootCreateDevice(&PhysicalDeviceObject);
609 if (!NT_SUCCESS(Status))
610 {
611 ExFreePool(Node);
612 return Status;
613 }
614
615 /* This is for drivers passed on the command line to ntoskrnl.exe */
616 IopDeviceNodeSetFlag(Node, DNF_STARTED);
617 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
618 }
619
620 Node->PhysicalDeviceObject = PhysicalDeviceObject;
621
622 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
623
624 if (ParentNode)
625 {
626 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
627 Node->Parent = ParentNode;
628 Node->NextSibling = ParentNode->Child;
629 if (ParentNode->Child != NULL)
630 {
631 ParentNode->Child->PrevSibling = Node;
632 }
633 ParentNode->Child = Node;
634 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
635 }
636
637 *DeviceNode = Node;
638
639 return STATUS_SUCCESS;
640 }
641
642 NTSTATUS
643 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
644 {
645 KIRQL OldIrql;
646
647 /* All children must be deleted before a parent is deleted */
648 ASSERT(!DeviceNode->Child);
649
650 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
651
652 ASSERT(DeviceNode->PhysicalDeviceObject);
653
654 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
655
656 /* Unlink from parent if it exists */
657
658 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
659 {
660 DeviceNode->Parent->Child = DeviceNode->NextSibling;
661 }
662
663 /* Unlink from sibling list */
664
665 if (DeviceNode->PrevSibling)
666 {
667 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
668 }
669
670 if (DeviceNode->NextSibling)
671 {
672 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
673 }
674
675 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
676
677 RtlFreeUnicodeString(&DeviceNode->InstancePath);
678
679 RtlFreeUnicodeString(&DeviceNode->ServiceName);
680
681 if (DeviceNode->ResourceList)
682 {
683 ExFreePool(DeviceNode->ResourceList);
684 }
685
686 if (DeviceNode->ResourceListTranslated)
687 {
688 ExFreePool(DeviceNode->ResourceListTranslated);
689 }
690
691 if (DeviceNode->ResourceRequirements)
692 {
693 ExFreePool(DeviceNode->ResourceRequirements);
694 }
695
696 if (DeviceNode->BootResources)
697 {
698 ExFreePool(DeviceNode->BootResources);
699 }
700
701 ExFreePool(DeviceNode);
702
703 return STATUS_SUCCESS;
704 }
705
706 NTSTATUS
707 IopInitiatePnpIrp(
708 PDEVICE_OBJECT DeviceObject,
709 PIO_STATUS_BLOCK IoStatusBlock,
710 ULONG MinorFunction,
711 PIO_STACK_LOCATION Stack OPTIONAL)
712 {
713 PDEVICE_OBJECT TopDeviceObject;
714 PIO_STACK_LOCATION IrpSp;
715 NTSTATUS Status;
716 KEVENT Event;
717 PIRP Irp;
718
719 /* Always call the top of the device stack */
720 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
721
722 KeInitializeEvent(
723 &Event,
724 NotificationEvent,
725 FALSE);
726
727 Irp = IoBuildSynchronousFsdRequest(
728 IRP_MJ_PNP,
729 TopDeviceObject,
730 NULL,
731 0,
732 NULL,
733 &Event,
734 IoStatusBlock);
735
736 /* PNP IRPs are always initialized with a status code of
737 STATUS_NOT_IMPLEMENTED */
738 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
739 Irp->IoStatus.Information = 0;
740
741 IrpSp = IoGetNextIrpStackLocation(Irp);
742 IrpSp->MinorFunction = MinorFunction;
743
744 if (Stack)
745 {
746 RtlMoveMemory(
747 &IrpSp->Parameters,
748 &Stack->Parameters,
749 sizeof(Stack->Parameters));
750 }
751
752 Status = IoCallDriver(TopDeviceObject, Irp);
753 if (Status == STATUS_PENDING)
754 {
755 KeWaitForSingleObject(
756 &Event,
757 Executive,
758 KernelMode,
759 FALSE,
760 NULL);
761 Status = IoStatusBlock->Status;
762 }
763
764 ObDereferenceObject(TopDeviceObject);
765
766 return Status;
767 }
768
769
770 NTSTATUS
771 IopTraverseDeviceTreeNode(
772 PDEVICETREE_TRAVERSE_CONTEXT Context)
773 {
774 PDEVICE_NODE ParentDeviceNode;
775 PDEVICE_NODE ChildDeviceNode;
776 NTSTATUS Status;
777
778 /* Copy context data so we don't overwrite it in subsequent calls to this function */
779 ParentDeviceNode = Context->DeviceNode;
780
781 /* Call the action routine */
782 Status = (Context->Action)(ParentDeviceNode, Context->Context);
783 if (!NT_SUCCESS(Status))
784 {
785 return Status;
786 }
787
788 /* Traversal of all children nodes */
789 for (ChildDeviceNode = ParentDeviceNode->Child;
790 ChildDeviceNode != NULL;
791 ChildDeviceNode = ChildDeviceNode->NextSibling)
792 {
793 /* Pass the current device node to the action routine */
794 Context->DeviceNode = ChildDeviceNode;
795
796 Status = IopTraverseDeviceTreeNode(Context);
797 if (!NT_SUCCESS(Status))
798 {
799 return Status;
800 }
801 }
802
803 return Status;
804 }
805
806
807 NTSTATUS
808 IopTraverseDeviceTree(
809 PDEVICETREE_TRAVERSE_CONTEXT Context)
810 {
811 NTSTATUS Status;
812
813 DPRINT("Context 0x%p\n", Context);
814
815 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
816 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
817
818 /* Start from the specified device node */
819 Context->DeviceNode = Context->FirstDeviceNode;
820
821 /* Recursively traverse the device tree */
822 Status = IopTraverseDeviceTreeNode(Context);
823 if (Status == STATUS_UNSUCCESSFUL)
824 {
825 /* The action routine just wanted to terminate the traversal with status
826 code STATUS_SUCCESS */
827 Status = STATUS_SUCCESS;
828 }
829
830 return Status;
831 }
832
833
834 static NTSTATUS
835 IopCreateDeviceKeyPath(PWSTR Path,
836 PHANDLE Handle)
837 {
838 OBJECT_ATTRIBUTES ObjectAttributes;
839 WCHAR KeyBuffer[MAX_PATH];
840 UNICODE_STRING KeyName;
841 HANDLE KeyHandle;
842 NTSTATUS Status;
843 PWCHAR Current;
844 PWCHAR Next;
845
846 *Handle = NULL;
847
848 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
849 {
850 return STATUS_INVALID_PARAMETER;
851 }
852
853 wcsncpy (KeyBuffer, Path, MAX_PATH-1);
854
855 /* Skip \\Registry\\ */
856 Current = KeyBuffer;
857 Current = wcschr (Current, L'\\') + 1;
858 Current = wcschr (Current, L'\\') + 1;
859
860 while (TRUE)
861 {
862 Next = wcschr (Current, L'\\');
863 if (Next == NULL)
864 {
865 /* The end */
866 }
867 else
868 {
869 *Next = 0;
870 }
871
872 RtlInitUnicodeString (&KeyName, KeyBuffer);
873 InitializeObjectAttributes (&ObjectAttributes,
874 &KeyName,
875 OBJ_CASE_INSENSITIVE,
876 NULL,
877 NULL);
878
879 DPRINT("Create '%S'\n", KeyName.Buffer);
880
881 Status = ZwCreateKey (&KeyHandle,
882 KEY_ALL_ACCESS,
883 &ObjectAttributes,
884 0,
885 NULL,
886 0,
887 NULL);
888 if (!NT_SUCCESS (Status))
889 {
890 DPRINT ("ZwCreateKey() failed with status %x\n", Status);
891 return Status;
892 }
893
894 if (Next == NULL)
895 {
896 *Handle = KeyHandle;
897 return STATUS_SUCCESS;
898 }
899 else
900 {
901 ZwClose (KeyHandle);
902 *Next = L'\\';
903 }
904
905 Current = Next + 1;
906 }
907
908 return STATUS_UNSUCCESSFUL;
909 }
910
911
912 static NTSTATUS
913 IopSetDeviceInstanceData(HANDLE InstanceKey,
914 PDEVICE_NODE DeviceNode)
915 {
916 OBJECT_ATTRIBUTES ObjectAttributes;
917 UNICODE_STRING KeyName;
918 HANDLE LogConfKey;
919 ULONG ResCount;
920 ULONG ListSize;
921 NTSTATUS Status;
922
923 DPRINT("IopSetDeviceInstanceData() called\n");
924
925 /* Create the 'LogConf' key */
926 RtlInitUnicodeString(&KeyName,
927 L"LogConf");
928 InitializeObjectAttributes(&ObjectAttributes,
929 &KeyName,
930 OBJ_CASE_INSENSITIVE,
931 InstanceKey,
932 NULL);
933 Status = ZwCreateKey(&LogConfKey,
934 KEY_ALL_ACCESS,
935 &ObjectAttributes,
936 0,
937 NULL,
938 0,
939 NULL);
940 if (NT_SUCCESS(Status))
941 {
942 /* Set 'BootConfig' value */
943 if (DeviceNode->BootResources != NULL)
944 {
945 ResCount = DeviceNode->BootResources->Count;
946 if (ResCount != 0)
947 {
948 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
949
950 RtlInitUnicodeString(&KeyName,
951 L"BootConfig");
952 Status = ZwSetValueKey(LogConfKey,
953 &KeyName,
954 0,
955 REG_RESOURCE_LIST,
956 &DeviceNode->BootResources,
957 ListSize);
958 }
959 }
960
961 /* Set 'BasicConfigVector' value */
962 if (DeviceNode->ResourceRequirements != NULL &&
963 DeviceNode->ResourceRequirements->ListSize != 0)
964 {
965 RtlInitUnicodeString(&KeyName,
966 L"BasicConfigVector");
967 Status = ZwSetValueKey(LogConfKey,
968 &KeyName,
969 0,
970 REG_RESOURCE_REQUIREMENTS_LIST,
971 DeviceNode->ResourceRequirements,
972 DeviceNode->ResourceRequirements->ListSize);
973 }
974
975 ZwClose(LogConfKey);
976 }
977
978 #if 0
979 if (DeviceNode->PhysicalDeviceObject != NULL)
980 {
981 /* Create the 'Control' key */
982 RtlInitUnicodeString(&KeyName,
983 L"Control");
984 InitializeObjectAttributes(&ObjectAttributes,
985 &KeyName,
986 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
987 InstanceKey,
988 NULL);
989 Status = ZwCreateKey(&LogConfKey,
990 KEY_ALL_ACCESS,
991 &ObjectAttributes,
992 0,
993 NULL,
994 REG_OPTION_VOLATILE,
995 NULL);
996 if (NT_SUCCESS(Status))
997 {
998 ULONG Reference = (ULONG)DeviceNode->PhysicalDeviceObject;
999 RtlInitUnicodeString(&KeyName,
1000 L"DeviceReference");
1001 Status = ZwSetValueKey(LogConfKey,
1002 &KeyName,
1003 0,
1004 REG_DWORD,
1005 &Reference,
1006 sizeof(PVOID));
1007
1008 ZwClose(LogConfKey);
1009 }
1010 }
1011 #endif
1012
1013 DPRINT("IopSetDeviceInstanceData() done\n");
1014
1015 return STATUS_SUCCESS;
1016 }
1017
1018
1019 NTSTATUS
1020 IopAssignDeviceResources(
1021 PDEVICE_NODE DeviceNode)
1022 {
1023 PIO_RESOURCE_LIST ResourceList;
1024 PIO_RESOURCE_DESCRIPTOR ResourceDescriptor;
1025 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1026 ULONG NumberOfResources = 0;
1027 ULONG i;
1028 NTSTATUS Status;
1029
1030 /* Fill DeviceNode->ResourceList and DeviceNode->ResourceListTranslated;
1031 * by using DeviceNode->ResourceRequirements */
1032
1033 if (!DeviceNode->ResourceRequirements
1034 || DeviceNode->ResourceRequirements->AlternativeLists == 0)
1035 {
1036 DeviceNode->ResourceList = DeviceNode->ResourceListTranslated = NULL;
1037 return STATUS_SUCCESS;
1038 }
1039
1040 /* FIXME: that's here that PnP arbiter should go */
1041 /* Actually, simply use resource list #0 as assigned resource list */
1042 ResourceList = &DeviceNode->ResourceRequirements->List[0];
1043 if (ResourceList->Version != 1 || ResourceList->Revision != 1)
1044 {
1045 Status = STATUS_REVISION_MISMATCH;
1046 goto ByeBye;
1047 }
1048
1049 DeviceNode->ResourceList = ExAllocatePool(PagedPool,
1050 sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1051 if (!DeviceNode->ResourceList)
1052 {
1053 Status = STATUS_INSUFFICIENT_RESOURCES;
1054 goto ByeBye;
1055 }
1056
1057 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool,
1058 sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1059 if (!DeviceNode->ResourceListTranslated)
1060 {
1061 Status = STATUS_INSUFFICIENT_RESOURCES;
1062 goto ByeBye;
1063 }
1064
1065 DeviceNode->ResourceList->Count = 1;
1066 DeviceNode->ResourceList->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1067 DeviceNode->ResourceList->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1068 DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1;
1069 DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1;
1070
1071 DeviceNode->ResourceListTranslated->Count = 1;
1072 DeviceNode->ResourceListTranslated->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1073 DeviceNode->ResourceListTranslated->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1074 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Version = 1;
1075 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Revision = 1;
1076
1077 for (i = 0; i < ResourceList->Count; i++)
1078 {
1079 ResourceDescriptor = &ResourceList->Descriptors[i];
1080
1081 if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED)
1082 {
1083 DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1084 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1085 NumberOfResources++;
1086
1087 /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
1088 DescriptorRaw->Type = DescriptorTranslated->Type = ResourceDescriptor->Type;
1089 DescriptorRaw->ShareDisposition = DescriptorTranslated->ShareDisposition = ResourceDescriptor->ShareDisposition;
1090 DescriptorRaw->Flags = DescriptorTranslated->Flags = ResourceDescriptor->Flags;
1091 switch (ResourceDescriptor->Type)
1092 {
1093 case CmResourceTypePort:
1094 {
1095 ULONG AddressSpace = 0; /* IO space */
1096 DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress;
1097 DescriptorRaw->u.Port.Length = DescriptorTranslated->u.Port.Length
1098 = ResourceDescriptor->u.Port.Length;
1099 if (!HalTranslateBusAddress(
1100 DeviceNode->ResourceRequirements->InterfaceType,
1101 DeviceNode->ResourceRequirements->BusNumber,
1102 DescriptorRaw->u.Port.Start,
1103 &AddressSpace,
1104 &DescriptorTranslated->u.Port.Start))
1105 {
1106 Status = STATUS_UNSUCCESSFUL;
1107 goto ByeBye;
1108 }
1109 break;
1110 }
1111 case CmResourceTypeInterrupt:
1112 {
1113 INTERFACE_TYPE BusType;
1114 ULONG SlotNumber;
1115 ULONG ret;
1116 UCHAR Irq;
1117
1118 DescriptorRaw->u.Interrupt.Level = 0;
1119 DescriptorRaw->u.Interrupt.Vector = ResourceDescriptor->u.Interrupt.MinimumVector;
1120 /* FIXME: HACK: if we have a PCI device, we try
1121 * to keep the IRQ assigned by the BIOS */
1122 if (NT_SUCCESS(IoGetDeviceProperty(
1123 DeviceNode->PhysicalDeviceObject,
1124 DevicePropertyLegacyBusType,
1125 sizeof(INTERFACE_TYPE),
1126 &BusType,
1127 &ret)) && BusType == PCIBus)
1128 {
1129 /* We have a PCI bus */
1130 if (NT_SUCCESS(IoGetDeviceProperty(
1131 DeviceNode->PhysicalDeviceObject,
1132 DevicePropertyAddress,
1133 sizeof(ULONG),
1134 &SlotNumber,
1135 &ret)) && SlotNumber > 0)
1136 {
1137 /* We have a good slot number */
1138 ret = HalGetBusDataByOffset(PCIConfiguration,
1139 DeviceNode->ResourceRequirements->BusNumber,
1140 SlotNumber,
1141 &Irq,
1142 0x3c /* PCI_INTERRUPT_LINE */,
1143 sizeof(UCHAR));
1144 if (ret != 0 && ret != 2
1145 && ResourceDescriptor->u.Interrupt.MinimumVector <= Irq
1146 && ResourceDescriptor->u.Interrupt.MaximumVector >= Irq)
1147 {
1148 /* The device already has an assigned IRQ */
1149 DescriptorRaw->u.Interrupt.Vector = Irq;
1150 }
1151 else
1152 {
1153 DPRINT1("Trying to assign IRQ 0x%lx to %wZ\n",
1154 DescriptorRaw->u.Interrupt.Vector,
1155 &DeviceNode->InstancePath);
1156 Irq = (UCHAR)DescriptorRaw->u.Interrupt.Vector;
1157 ret = HalSetBusDataByOffset(PCIConfiguration,
1158 DeviceNode->ResourceRequirements->BusNumber,
1159 SlotNumber,
1160 &Irq,
1161 0x3c /* PCI_INTERRUPT_LINE */,
1162 sizeof(UCHAR));
1163 if (ret == 0 || ret == 2)
1164 KEBUGCHECK(0);
1165 }
1166 }
1167 }
1168
1169 DescriptorTranslated->u.Interrupt.Level = 0;
1170 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1171 DeviceNode->ResourceRequirements->InterfaceType,
1172 DeviceNode->ResourceRequirements->BusNumber,
1173 DescriptorRaw->u.Interrupt.Level,
1174 DescriptorRaw->u.Interrupt.Vector,
1175 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1176 &DescriptorRaw->u.Interrupt.Affinity);
1177 DescriptorTranslated->u.Interrupt.Affinity = DescriptorRaw->u.Interrupt.Affinity;
1178 break;
1179 }
1180 case CmResourceTypeMemory:
1181 {
1182 ULONG AddressSpace = 1; /* Memory space */
1183 DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress;
1184 DescriptorRaw->u.Memory.Length = DescriptorTranslated->u.Memory.Length
1185 = ResourceDescriptor->u.Memory.Length;
1186 if (!HalTranslateBusAddress(
1187 DeviceNode->ResourceRequirements->InterfaceType,
1188 DeviceNode->ResourceRequirements->BusNumber,
1189 DescriptorRaw->u.Memory.Start,
1190 &AddressSpace,
1191 &DescriptorTranslated->u.Memory.Start))
1192 {
1193 Status = STATUS_UNSUCCESSFUL;
1194 goto ByeBye;
1195 }
1196 break;
1197 }
1198 case CmResourceTypeDma:
1199 {
1200 DescriptorRaw->u.Dma.Channel = DescriptorTranslated->u.Dma.Channel
1201 = ResourceDescriptor->u.Dma.MinimumChannel;
1202 DescriptorRaw->u.Dma.Port = DescriptorTranslated->u.Dma.Port
1203 = 0; /* FIXME */
1204 DescriptorRaw->u.Dma.Reserved1 = DescriptorTranslated->u.Dma.Reserved1
1205 = 0;
1206 break;
1207 }
1208 /*case CmResourceTypeBusNumber:
1209 {
1210 DescriptorRaw->u.BusNumber.Start = DescriptorTranslated->u.BusNumber.Start
1211 = ResourceDescriptor->u.BusNumber.MinBusNumber;
1212 DescriptorRaw->u.BusNumber.Length = DescriptorTranslated->u.BusNumber.Length
1213 = ResourceDescriptor->u.BusNumber.Length;
1214 DescriptorRaw->u.BusNumber.Reserved = DescriptorTranslated->u.BusNumber.Reserved
1215 = ResourceDescriptor->u.BusNumber.Reserved;
1216 break;
1217 }*/
1218 /*CmResourceTypeDevicePrivate:
1219 case CmResourceTypePcCardConfig:
1220 case CmResourceTypeMfCardConfig:
1221 {
1222 RtlCopyMemory(
1223 &DescriptorRaw->u.DevicePrivate,
1224 &ResourceDescriptor->u.DevicePrivate,
1225 sizeof(ResourceDescriptor->u.DevicePrivate));
1226 RtlCopyMemory(
1227 &DescriptorTranslated->u.DevicePrivate,
1228 &ResourceDescriptor->u.DevicePrivate,
1229 sizeof(ResourceDescriptor->u.DevicePrivate));
1230 break;
1231 }*/
1232 default:
1233 DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
1234 NumberOfResources--;
1235 }
1236 }
1237
1238 }
1239
1240 DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
1241 DeviceNode->ResourceListTranslated->List[0].PartialResourceList.Count = NumberOfResources;
1242
1243 return STATUS_SUCCESS;
1244
1245 ByeBye:
1246 if (DeviceNode->ResourceList)
1247 {
1248 ExFreePool(DeviceNode->ResourceList);
1249 DeviceNode->ResourceList = NULL;
1250 }
1251 if (DeviceNode->ResourceListTranslated)
1252 {
1253 ExFreePool(DeviceNode->ResourceListTranslated);
1254 DeviceNode->ResourceListTranslated = NULL;
1255 }
1256
1257 return Status;
1258 }
1259
1260
1261 /*
1262 * IopActionInterrogateDeviceStack
1263 *
1264 * Retrieve information for all (direct) child nodes of a parent node.
1265 *
1266 * Parameters
1267 * DeviceNode
1268 * Pointer to device node.
1269 * Context
1270 * Pointer to parent node to retrieve child node information for.
1271 *
1272 * Remarks
1273 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1274 * when we reach a device node which is not a direct child of the device
1275 * node for which we retrieve information of child nodes for. Any errors
1276 * that occur is logged instead so that all child services have a chance
1277 * of being interrogated.
1278 */
1279
1280 NTSTATUS
1281 IopActionInterrogateDeviceStack(
1282 PDEVICE_NODE DeviceNode,
1283 PVOID Context)
1284 {
1285 IO_STATUS_BLOCK IoStatusBlock;
1286 PDEVICE_NODE ParentDeviceNode;
1287 WCHAR InstancePath[MAX_PATH];
1288 IO_STACK_LOCATION Stack;
1289 NTSTATUS Status;
1290 PWSTR KeyBuffer;
1291 PWSTR Ptr;
1292 USHORT Length;
1293 USHORT TotalLength;
1294 HANDLE InstanceKey = NULL;
1295 UNICODE_STRING ValueName;
1296 DEVICE_CAPABILITIES DeviceCapabilities;
1297 PKEY_VALUE_PARTIAL_INFORMATION ParentPrefixIdInformation = NULL;
1298
1299 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1300 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1301
1302 ParentDeviceNode = (PDEVICE_NODE)Context;
1303
1304 /*
1305 * We are called for the parent too, but we don't need to do special
1306 * handling for this node
1307 */
1308
1309 if (DeviceNode == ParentDeviceNode)
1310 {
1311 DPRINT("Success\n");
1312 return STATUS_SUCCESS;
1313 }
1314
1315 /*
1316 * Make sure this device node is a direct child of the parent device node
1317 * that is given as an argument
1318 */
1319
1320 if (DeviceNode->Parent != ParentDeviceNode)
1321 {
1322 /* Stop the traversal immediately and indicate successful operation */
1323 DPRINT("Stop\n");
1324 return STATUS_UNSUCCESSFUL;
1325 }
1326
1327 /*
1328 * FIXME: For critical errors, cleanup and disable device, but always
1329 * return STATUS_SUCCESS.
1330 */
1331
1332 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1333
1334 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1335 Status = IopInitiatePnpIrp(
1336 DeviceNode->PhysicalDeviceObject,
1337 &IoStatusBlock,
1338 IRP_MN_QUERY_ID,
1339 &Stack);
1340 if (NT_SUCCESS(Status))
1341 {
1342 /* Copy the device id string */
1343 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1344
1345 /*
1346 * FIXME: Check for valid characters, if there is invalid characters
1347 * then bugcheck.
1348 */
1349 }
1350 else
1351 {
1352 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1353 }
1354
1355 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1356
1357 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1358 if (!NT_SUCCESS(Status))
1359 {
1360 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1361 }
1362
1363 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1364
1365 if (!DeviceCapabilities.UniqueID)
1366 {
1367 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1368 DPRINT("Instance ID is not unique\n");
1369 if (DeviceNode->Parent->InstancePath.Length > 0)
1370 {
1371 /* Parent device node exists */
1372 HANDLE hKey;
1373 OBJECT_ATTRIBUTES ObjectAttributes;
1374 UNICODE_STRING KeyName;
1375 ULONG KeyNameBufferLength;
1376 PWSTR KeyNameBuffer = NULL;
1377
1378 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1379 ParentPrefixIdInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1380 KeyNameBuffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1381 if (ParentPrefixIdInformation && KeyNameBuffer)
1382 {
1383 /* Memory is allocated, let's try to read registry settings */
1384 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1385 wcscat(KeyNameBuffer, DeviceNode->Parent->InstancePath.Buffer);
1386 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
1387 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1388 Status = ZwOpenKey(&hKey, KEY_READ, &ObjectAttributes);
1389 if (NT_SUCCESS(Status))
1390 {
1391 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1392 Status = ZwQueryValueKey(
1393 hKey, &ValueName,
1394 KeyValuePartialInformation, ParentPrefixIdInformation,
1395 KeyNameBufferLength, &KeyNameBufferLength);
1396 if (NT_SUCCESS(Status))
1397 {
1398 /* NULL-terminate the string, as we have allocated enough place for it */
1399 ((PWSTR)ParentPrefixIdInformation->Data)[ParentPrefixIdInformation->DataLength / sizeof(WCHAR)] = 0;
1400 }
1401 else
1402 {
1403 ExFreePool(ParentPrefixIdInformation);
1404 ParentPrefixIdInformation = NULL;
1405 }
1406 ZwClose(hKey);
1407 }
1408 else
1409 {
1410 ExFreePool(ParentPrefixIdInformation);
1411 ParentPrefixIdInformation = NULL;
1412 }
1413 }
1414 ExFreePool(KeyNameBuffer);
1415 }
1416 }
1417
1418 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1419
1420 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1421 Status = IopInitiatePnpIrp(
1422 DeviceNode->PhysicalDeviceObject,
1423 &IoStatusBlock,
1424 IRP_MN_QUERY_ID,
1425 &Stack);
1426 if (NT_SUCCESS(Status))
1427 {
1428 /* Append the instance id string */
1429 wcscat(InstancePath, L"\\");
1430 if (ParentPrefixIdInformation && ParentPrefixIdInformation->Type == REG_SZ)
1431 {
1432 /* Add information from parent bus device to InstancePath */
1433 wcscat(InstancePath, (PWSTR)ParentPrefixIdInformation->Data);
1434 if (*(PWSTR)IoStatusBlock.Information)
1435 wcscat(InstancePath, L"&");
1436 }
1437 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1438
1439 /*
1440 * FIXME: Check for valid characters, if there is invalid characters
1441 * then bugcheck
1442 */
1443 }
1444 else
1445 {
1446 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1447 }
1448 ExFreePool(ParentPrefixIdInformation);
1449
1450 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1451 {
1452 DPRINT("No resources\n");
1453 /* FIXME: Cleanup and disable device */
1454 }
1455
1456 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1457
1458 /*
1459 * Create registry key for the instance id, if it doesn't exist yet
1460 */
1461 KeyBuffer = ExAllocatePool(
1462 PagedPool,
1463 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
1464 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1465 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
1466 Status = IopCreateDeviceKeyPath(KeyBuffer,
1467 &InstanceKey);
1468 ExFreePool(KeyBuffer);
1469 if (!NT_SUCCESS(Status))
1470 {
1471 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1472 }
1473
1474
1475 {
1476 /* Set 'Capabilities' value */
1477 RtlInitUnicodeString(&ValueName,
1478 L"Capabilities");
1479 Status = ZwSetValueKey(InstanceKey,
1480 &ValueName,
1481 0,
1482 REG_DWORD,
1483 (PVOID)&DeviceNode->CapabilityFlags,
1484 sizeof(ULONG));
1485
1486 /* Set 'UINumber' value */
1487 if (DeviceCapabilities.UINumber != (ULONG)-1)
1488 {
1489 RtlInitUnicodeString(&ValueName,
1490 L"UINumber");
1491 Status = ZwSetValueKey(InstanceKey,
1492 &ValueName,
1493 0,
1494 REG_DWORD,
1495 &DeviceCapabilities.UINumber,
1496 sizeof(ULONG));
1497 }
1498 }
1499
1500 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1501
1502 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1503 Status = IopInitiatePnpIrp(
1504 DeviceNode->PhysicalDeviceObject,
1505 &IoStatusBlock,
1506 IRP_MN_QUERY_ID,
1507 &Stack);
1508 if (NT_SUCCESS(Status))
1509 {
1510 /*
1511 * FIXME: Check for valid characters, if there is invalid characters
1512 * then bugcheck.
1513 */
1514 TotalLength = 0;
1515 Ptr = (PWSTR)IoStatusBlock.Information;
1516 DPRINT("Hardware IDs:\n");
1517 while (*Ptr)
1518 {
1519 DPRINT(" %S\n", Ptr);
1520 Length = wcslen(Ptr) + 1;
1521
1522 Ptr += Length;
1523 TotalLength += Length;
1524 }
1525 DPRINT("TotalLength: %hu\n", TotalLength);
1526 DPRINT("\n");
1527
1528 RtlInitUnicodeString(&ValueName,
1529 L"HardwareID");
1530 Status = ZwSetValueKey(InstanceKey,
1531 &ValueName,
1532 0,
1533 REG_MULTI_SZ,
1534 (PVOID)IoStatusBlock.Information,
1535 (TotalLength + 1) * sizeof(WCHAR));
1536 if (!NT_SUCCESS(Status))
1537 {
1538 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1539 }
1540 }
1541 else
1542 {
1543 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1544 }
1545
1546 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1547
1548 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1549 Status = IopInitiatePnpIrp(
1550 DeviceNode->PhysicalDeviceObject,
1551 &IoStatusBlock,
1552 IRP_MN_QUERY_ID,
1553 &Stack);
1554 if (NT_SUCCESS(Status))
1555 {
1556 /*
1557 * FIXME: Check for valid characters, if there is invalid characters
1558 * then bugcheck.
1559 */
1560 TotalLength = 0;
1561 Ptr = (PWSTR)IoStatusBlock.Information;
1562 DPRINT("Compatible IDs:\n");
1563 while (*Ptr)
1564 {
1565 DPRINT(" %S\n", Ptr);
1566 Length = wcslen(Ptr) + 1;
1567
1568 Ptr += Length;
1569 TotalLength += Length;
1570 }
1571 DPRINT("TotalLength: %hu\n", TotalLength);
1572 DPRINT("\n");
1573
1574 RtlInitUnicodeString(&ValueName,
1575 L"CompatibleIDs");
1576 Status = ZwSetValueKey(InstanceKey,
1577 &ValueName,
1578 0,
1579 REG_MULTI_SZ,
1580 (PVOID)IoStatusBlock.Information,
1581 (TotalLength + 1) * sizeof(WCHAR));
1582 if (!NT_SUCCESS(Status))
1583 {
1584 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1585 }
1586 }
1587 else
1588 {
1589 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1590 }
1591
1592
1593 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1594
1595 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1596 Stack.Parameters.QueryDeviceText.LocaleId = 0; /* FIXME */
1597 Status = IopInitiatePnpIrp(
1598 DeviceNode->PhysicalDeviceObject,
1599 &IoStatusBlock,
1600 IRP_MN_QUERY_DEVICE_TEXT,
1601 &Stack);
1602 if (NT_SUCCESS(Status))
1603 {
1604 RtlInitUnicodeString(&ValueName,
1605 L"DeviceDesc");
1606 Status = ZwSetValueKey(InstanceKey,
1607 &ValueName,
1608 0,
1609 REG_SZ,
1610 (PVOID)IoStatusBlock.Information,
1611 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1612 if (!NT_SUCCESS(Status))
1613 {
1614 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1615 }
1616 }
1617 else
1618 {
1619 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1620 }
1621
1622 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
1623
1624 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
1625 Stack.Parameters.QueryDeviceText.LocaleId = 0; // FIXME
1626 Status = IopInitiatePnpIrp(
1627 DeviceNode->PhysicalDeviceObject,
1628 &IoStatusBlock,
1629 IRP_MN_QUERY_DEVICE_TEXT,
1630 &Stack);
1631 if (NT_SUCCESS(Status))
1632 {
1633 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
1634 RtlInitUnicodeString(&ValueName,
1635 L"LocationInformation");
1636 Status = ZwSetValueKey(InstanceKey,
1637 &ValueName,
1638 0,
1639 REG_SZ,
1640 (PVOID)IoStatusBlock.Information,
1641 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1642 if (!NT_SUCCESS(Status))
1643 {
1644 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1645 }
1646 }
1647 else
1648 {
1649 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1650 }
1651
1652 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
1653
1654 Status = IopInitiatePnpIrp(
1655 DeviceNode->PhysicalDeviceObject,
1656 &IoStatusBlock,
1657 IRP_MN_QUERY_BUS_INFORMATION,
1658 NULL);
1659 if (NT_SUCCESS(Status))
1660 {
1661 PPNP_BUS_INFORMATION BusInformation =
1662 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
1663
1664 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
1665 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
1666 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
1667 ExFreePool(BusInformation);
1668 }
1669 else
1670 {
1671 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1672
1673 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
1674 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
1675 DeviceNode->ChildBusTypeIndex = -1;
1676 }
1677
1678 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
1679
1680 Status = IopInitiatePnpIrp(
1681 DeviceNode->PhysicalDeviceObject,
1682 &IoStatusBlock,
1683 IRP_MN_QUERY_RESOURCES,
1684 NULL);
1685 if (NT_SUCCESS(Status))
1686 {
1687 DeviceNode->BootResources =
1688 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
1689 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
1690 }
1691 else
1692 {
1693 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1694 DeviceNode->BootResources = NULL;
1695 }
1696
1697 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
1698
1699 Status = IopInitiatePnpIrp(
1700 DeviceNode->PhysicalDeviceObject,
1701 &IoStatusBlock,
1702 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
1703 NULL);
1704 if (NT_SUCCESS(Status))
1705 {
1706 DeviceNode->ResourceRequirements =
1707 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
1708 }
1709 else
1710 {
1711 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1712 DeviceNode->ResourceRequirements = NULL;
1713 }
1714
1715
1716 if (InstanceKey != NULL)
1717 {
1718 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
1719 }
1720
1721 ZwClose(InstanceKey);
1722
1723 Status = IopAssignDeviceResources(DeviceNode);
1724 if (!NT_SUCCESS(Status))
1725 {
1726 DPRINT("IopAssignDeviceResources() failed (Status %x)\n", Status);
1727 }
1728
1729 DeviceNode->Flags |= DNF_PROCESSED;
1730
1731 /* Report the device to the user-mode pnp manager */
1732 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
1733 &DeviceNode->InstancePath);
1734
1735 return STATUS_SUCCESS;
1736 }
1737
1738 /*
1739 * IopActionConfigureChildServices
1740 *
1741 * Retrieve configuration for all (direct) child nodes of a parent node.
1742 *
1743 * Parameters
1744 * DeviceNode
1745 * Pointer to device node.
1746 * Context
1747 * Pointer to parent node to retrieve child node configuration for.
1748 *
1749 * Remarks
1750 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1751 * when we reach a device node which is not a direct child of the device
1752 * node for which we configure child services for. Any errors that occur is
1753 * logged instead so that all child services have a chance of beeing
1754 * configured.
1755 */
1756
1757 NTSTATUS
1758 IopActionConfigureChildServices(
1759 PDEVICE_NODE DeviceNode,
1760 PVOID Context)
1761 {
1762 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1763 PDEVICE_NODE ParentDeviceNode;
1764 PUNICODE_STRING Service;
1765 NTSTATUS Status;
1766
1767 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
1768
1769 ParentDeviceNode = (PDEVICE_NODE)Context;
1770
1771 /*
1772 * We are called for the parent too, but we don't need to do special
1773 * handling for this node
1774 */
1775 if (DeviceNode == ParentDeviceNode)
1776 {
1777 DPRINT("Success\n");
1778 return STATUS_SUCCESS;
1779 }
1780
1781 /*
1782 * Make sure this device node is a direct child of the parent device node
1783 * that is given as an argument
1784 */
1785 if (DeviceNode->Parent != ParentDeviceNode)
1786 {
1787 /* Stop the traversal immediately and indicate successful operation */
1788 DPRINT("Stop\n");
1789 return STATUS_UNSUCCESSFUL;
1790 }
1791
1792 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
1793 {
1794 WCHAR RegKeyBuffer[MAX_PATH];
1795 UNICODE_STRING RegKey;
1796
1797 RegKey.Length = 0;
1798 RegKey.MaximumLength = sizeof(RegKeyBuffer);
1799 RegKey.Buffer = RegKeyBuffer;
1800
1801 /*
1802 * Retrieve configuration from Enum key
1803 */
1804
1805 Service = &DeviceNode->ServiceName;
1806
1807 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1808 RtlInitUnicodeString(Service, NULL);
1809
1810 QueryTable[0].Name = L"Service";
1811 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
1812 QueryTable[0].EntryContext = Service;
1813
1814 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1815 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
1816
1817 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
1818 RegKey.Buffer, QueryTable, NULL, NULL);
1819
1820 if (!NT_SUCCESS(Status))
1821 {
1822 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
1823 /* FIXME: Log the error */
1824 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
1825 DeviceNode->InstancePath.Buffer, Status);
1826 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1827 return STATUS_SUCCESS;
1828 }
1829
1830 if (Service->Buffer == NULL)
1831 {
1832 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1833 return STATUS_SUCCESS;
1834 }
1835
1836 DPRINT("Got Service %S\n", Service->Buffer);
1837 }
1838
1839 return STATUS_SUCCESS;
1840 }
1841
1842 /*
1843 * IopActionInitChildServices
1844 *
1845 * Initialize the service for all (direct) child nodes of a parent node
1846 *
1847 * Parameters
1848 * DeviceNode
1849 * Pointer to device node.
1850 * Context
1851 * Pointer to parent node to initialize child node services for.
1852 * BootDrivers
1853 * Load only driver marked as boot start.
1854 *
1855 * Remarks
1856 * If the driver image for a service is not loaded and initialized
1857 * it is done here too. We only return a status code indicating an
1858 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
1859 * not a direct child of the device node for which we initialize
1860 * child services for. Any errors that occur is logged instead so
1861 * that all child services have a chance of being initialized.
1862 */
1863
1864 NTSTATUS
1865 IopActionInitChildServices(
1866 PDEVICE_NODE DeviceNode,
1867 PVOID Context,
1868 BOOLEAN BootDrivers)
1869 {
1870 PDEVICE_NODE ParentDeviceNode;
1871 NTSTATUS Status;
1872
1873 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode, Context,
1874 BootDrivers);
1875
1876 ParentDeviceNode = (PDEVICE_NODE)Context;
1877
1878 /*
1879 * We are called for the parent too, but we don't need to do special
1880 * handling for this node
1881 */
1882 if (DeviceNode == ParentDeviceNode)
1883 {
1884 DPRINT("Success\n");
1885 return STATUS_SUCCESS;
1886 }
1887
1888 /*
1889 * Make sure this device node is a direct child of the parent device node
1890 * that is given as an argument
1891 */
1892 #if 0
1893 if (DeviceNode->Parent != ParentDeviceNode)
1894 {
1895 /*
1896 * Stop the traversal immediately and indicate unsuccessful operation
1897 */
1898 DPRINT("Stop\n");
1899 return STATUS_UNSUCCESSFUL;
1900 }
1901 #endif
1902
1903 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
1904 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
1905 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
1906 {
1907 PLDR_DATA_TABLE_ENTRY ModuleObject;
1908 PDRIVER_OBJECT DriverObject;
1909
1910 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
1911 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
1912 {
1913 if (Status != STATUS_IMAGE_ALREADY_LOADED)
1914 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
1915 &DeviceNode->ServiceName, FALSE, &DriverObject);
1916 else
1917 {
1918 /* get existing DriverObject pointer */
1919 Status = IopGetDriverObject(
1920 &DriverObject,
1921 &DeviceNode->ServiceName,
1922 FALSE);
1923 }
1924 if (NT_SUCCESS(Status))
1925 {
1926 /* Attach lower level filter drivers. */
1927 IopAttachFilterDrivers(DeviceNode, TRUE);
1928 /* Initialize the function driver for the device node */
1929 Status = IopInitializeDevice(DeviceNode, DriverObject);
1930 if (NT_SUCCESS(Status))
1931 {
1932 /* Attach upper level filter drivers. */
1933 IopAttachFilterDrivers(DeviceNode, FALSE);
1934 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
1935
1936 Status = IopStartDevice(DeviceNode);
1937 }
1938 }
1939 }
1940 else
1941 {
1942 /*
1943 * Don't disable when trying to load only boot drivers
1944 */
1945 if (!BootDrivers)
1946 {
1947 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
1948 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
1949 }
1950 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
1951 CPRINT("Initialization of service %S failed (Status %x)\n",
1952 DeviceNode->ServiceName.Buffer, Status);
1953 }
1954 } else
1955 {
1956 DPRINT("Service %S is disabled or already initialized\n",
1957 DeviceNode->ServiceName.Buffer);
1958 }
1959
1960 return STATUS_SUCCESS;
1961 }
1962
1963 /*
1964 * IopActionInitAllServices
1965 *
1966 * Initialize the service for all (direct) child nodes of a parent node. This
1967 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
1968 */
1969
1970 NTSTATUS
1971 IopActionInitAllServices(
1972 PDEVICE_NODE DeviceNode,
1973 PVOID Context)
1974 {
1975 return IopActionInitChildServices(DeviceNode, Context, FALSE);
1976 }
1977
1978 /*
1979 * IopActionInitBootServices
1980 *
1981 * Initialize the boot start services for all (direct) child nodes of a
1982 * parent node. This function just calls IopActionInitChildServices with
1983 * BootDrivers = TRUE.
1984 */
1985 NTSTATUS
1986 IopActionInitBootServices(
1987 PDEVICE_NODE DeviceNode,
1988 PVOID Context)
1989 {
1990 return IopActionInitChildServices(DeviceNode, Context, TRUE);
1991 }
1992
1993 /*
1994 * IopInitializePnpServices
1995 *
1996 * Initialize services for discovered children
1997 *
1998 * Parameters
1999 * DeviceNode
2000 * Top device node to start initializing services.
2001 *
2002 * BootDrivers
2003 * When set to TRUE, only drivers marked as boot start will
2004 * be loaded. Otherwise, all drivers will be loaded.
2005 *
2006 * Return Value
2007 * Status
2008 */
2009 NTSTATUS
2010 IopInitializePnpServices(
2011 IN PDEVICE_NODE DeviceNode,
2012 IN BOOLEAN BootDrivers)
2013 {
2014 DEVICETREE_TRAVERSE_CONTEXT Context;
2015
2016 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode, BootDrivers);
2017
2018 if (BootDrivers)
2019 {
2020 IopInitDeviceTreeTraverseContext(
2021 &Context,
2022 DeviceNode,
2023 IopActionInitBootServices,
2024 DeviceNode);
2025 }
2026 else
2027 {
2028 IopInitDeviceTreeTraverseContext(
2029 &Context,
2030 DeviceNode,
2031 IopActionInitAllServices,
2032 DeviceNode);
2033 }
2034
2035 return IopTraverseDeviceTree(&Context);
2036 }
2037
2038
2039 NTSTATUS
2040 IopInvalidateDeviceRelations(
2041 IN PDEVICE_NODE DeviceNode,
2042 IN DEVICE_RELATION_TYPE Type)
2043 {
2044 DEVICETREE_TRAVERSE_CONTEXT Context;
2045 PDEVICE_RELATIONS DeviceRelations;
2046 IO_STATUS_BLOCK IoStatusBlock;
2047 PDEVICE_NODE ChildDeviceNode;
2048 IO_STACK_LOCATION Stack;
2049 BOOL BootDrivers;
2050 OBJECT_ATTRIBUTES ObjectAttributes;
2051 UNICODE_STRING LinkName;
2052 HANDLE Handle;
2053 NTSTATUS Status;
2054 ULONG i;
2055
2056 DPRINT("DeviceNode 0x%p\n", DeviceNode);
2057
2058 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2059
2060 Stack.Parameters.QueryDeviceRelations.Type = Type/*BusRelations*/;
2061
2062 Status = IopInitiatePnpIrp(
2063 DeviceNode->PhysicalDeviceObject,
2064 &IoStatusBlock,
2065 IRP_MN_QUERY_DEVICE_RELATIONS,
2066 &Stack);
2067 if (!NT_SUCCESS(Status))
2068 {
2069 DPRINT("IopInitiatePnpIrp() failed\n");
2070 return Status;
2071 }
2072
2073 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2074
2075 if ((!DeviceRelations) || (DeviceRelations->Count <= 0))
2076 {
2077 DPRINT("No PDOs\n");
2078 if (DeviceRelations)
2079 {
2080 ExFreePool(DeviceRelations);
2081 }
2082 return STATUS_SUCCESS;
2083 }
2084
2085 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
2086
2087 /*
2088 * Create device nodes for all discovered devices
2089 */
2090
2091 for (i = 0; i < DeviceRelations->Count; i++)
2092 {
2093 Status = IopCreateDeviceNode(
2094 DeviceNode,
2095 DeviceRelations->Objects[i],
2096 &ChildDeviceNode);
2097 DeviceNode->Flags |= DNF_ENUMERATED;
2098 if (!NT_SUCCESS(Status))
2099 {
2100 DPRINT("No resources\n");
2101 for (i = 0; i < DeviceRelations->Count; i++)
2102 ObDereferenceObject(DeviceRelations->Objects[i]);
2103 ExFreePool(DeviceRelations);
2104 return STATUS_INSUFFICIENT_RESOURCES;
2105 }
2106 }
2107 ExFreePool(DeviceRelations);
2108
2109 /*
2110 * Retrieve information about all discovered children from the bus driver
2111 */
2112
2113 IopInitDeviceTreeTraverseContext(
2114 &Context,
2115 DeviceNode,
2116 IopActionInterrogateDeviceStack,
2117 DeviceNode);
2118
2119 Status = IopTraverseDeviceTree(&Context);
2120 if (!NT_SUCCESS(Status))
2121 {
2122 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
2123 return Status;
2124 }
2125
2126 /*
2127 * Retrieve configuration from the registry for discovered children
2128 */
2129
2130 IopInitDeviceTreeTraverseContext(
2131 &Context,
2132 DeviceNode,
2133 IopActionConfigureChildServices,
2134 DeviceNode);
2135
2136 Status = IopTraverseDeviceTree(&Context);
2137 if (!NT_SUCCESS(Status))
2138 {
2139 DPRINT("IopTraverseDeviceTree() failed with status (%x)\n", Status);
2140 return Status;
2141 }
2142
2143 /*
2144 * Get the state of the system boot. If the \\SystemRoot link isn't
2145 * created yet, we will assume that it's possible to load only boot
2146 * drivers.
2147 */
2148
2149 RtlInitUnicodeString(&LinkName, L"\\SystemRoot");
2150
2151 InitializeObjectAttributes(
2152 &ObjectAttributes,
2153 &LinkName,
2154 0,
2155 NULL,
2156 NULL);
2157
2158 Status = ZwOpenFile(
2159 &Handle,
2160 FILE_ALL_ACCESS,
2161 &ObjectAttributes,
2162 &IoStatusBlock,
2163 0,
2164 0);
2165 if(NT_SUCCESS(Status))
2166 {
2167 BootDrivers = FALSE;
2168 ZwClose(Handle);
2169 }
2170 else
2171 BootDrivers = TRUE;
2172
2173 /*
2174 * Initialize services for discovered children. Only boot drivers will
2175 * be loaded from boot driver!
2176 */
2177
2178 Status = IopInitializePnpServices(DeviceNode, BootDrivers);
2179 if (!NT_SUCCESS(Status))
2180 {
2181 DPRINT("IopInitializePnpServices() failed with status (%x)\n", Status);
2182 return Status;
2183 }
2184
2185 return STATUS_SUCCESS;
2186 }
2187
2188
2189 static NTSTATUS INIT_FUNCTION
2190 IopSetRootDeviceInstanceData(PDEVICE_NODE DeviceNode)
2191 {
2192 #if 0
2193 PWSTR KeyBuffer;
2194 HANDLE InstanceKey = NULL;
2195 NTSTATUS Status;
2196
2197 /* Create registry key for the instance id, if it doesn't exist yet */
2198 KeyBuffer = ExAllocatePool(PagedPool,
2199 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
2200 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2201 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
2202 Status = IopCreateDeviceKeyPath(KeyBuffer,
2203 &InstanceKey);
2204 ExFreePool(KeyBuffer);
2205 if (!NT_SUCCESS(Status))
2206 {
2207 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2208 return Status;
2209 }
2210
2211 /* FIXME: Set 'ConfigFlags' value */
2212
2213 ZwClose(InstanceKey);
2214
2215 return Status;
2216 #endif
2217 return STATUS_SUCCESS;
2218 }
2219
2220
2221 VOID INIT_FUNCTION
2222 PnpInit(VOID)
2223 {
2224 PDEVICE_OBJECT Pdo;
2225 NTSTATUS Status;
2226
2227 DPRINT("PnpInit()\n");
2228
2229 KeInitializeSpinLock(&IopDeviceTreeLock);
2230
2231 /* Initialize the Bus Type GUID List */
2232 IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
2233 RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
2234 ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
2235
2236 /* Initialize PnP-Event notification support */
2237 Status = IopInitPlugPlayEvents();
2238 if (!NT_SUCCESS(Status))
2239 {
2240 CPRINT("IopInitPlugPlayEvents() failed\n");
2241 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2242 }
2243
2244 /*
2245 * Create root device node
2246 */
2247
2248 Status = IopCreateDriverObject(&IopRootDriverObject, NULL, 0, FALSE, NULL, 0);
2249 if (!NT_SUCCESS(Status))
2250 {
2251 CPRINT("IoCreateDriverObject() failed\n");
2252 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2253 }
2254
2255 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
2256 0, FALSE, &Pdo);
2257 if (!NT_SUCCESS(Status))
2258 {
2259 CPRINT("IoCreateDevice() failed\n");
2260 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2261 }
2262
2263 Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
2264 if (!NT_SUCCESS(Status))
2265 {
2266 CPRINT("Insufficient resources\n");
2267 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2268 }
2269
2270 if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
2271 L"HTREE\\ROOT\\0"))
2272 {
2273 CPRINT("Failed to create the instance path!\n");
2274 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_UNSUCCESSFUL, 0, 0, 0);
2275 }
2276
2277 /* Report the device to the user-mode pnp manager */
2278 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2279 &IopRootDeviceNode->InstancePath);
2280
2281 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2282 PnpRootDriverEntry(IopRootDriverObject, NULL);
2283 IopRootDriverObject->DriverExtension->AddDevice(
2284 IopRootDriverObject,
2285 IopRootDeviceNode->PhysicalDeviceObject);
2286 }
2287
2288
2289 VOID INIT_FUNCTION
2290 PnpInit2(VOID)
2291 {
2292 NTSTATUS Status;
2293
2294 /* Set root device instance data */
2295 Status = IopSetRootDeviceInstanceData(IopRootDeviceNode);
2296 if (!NT_SUCCESS(Status))
2297 {
2298 CPRINT("Failed to set instance data\n");
2299 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
2300 }
2301 }
2302
2303 /* EOF */