The code expects synchronous behaviour here, so until a better solution exists, IoSyn...
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / 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 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22
23 /* DATA **********************************************************************/
24
25 PDRIVER_OBJECT IopRootDriverObject;
26 PIO_BUS_TYPE_GUID_LIST IopBusTypeGuidList = NULL;
27
28 #if defined (ALLOC_PRAGMA)
29 #pragma alloc_text(INIT, PnpInit)
30 #pragma alloc_text(INIT, PnpInit2)
31 #endif
32
33 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
34 {
35 DEVICE_RELATION_TYPE Type;
36 PIO_WORKITEM WorkItem;
37 PKEVENT Event;
38 NTSTATUS Status;
39 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
40
41 static VOID NTAPI
42 IopInvalidateDeviceRelations(
43 IN PDEVICE_OBJECT DeviceObject,
44 IN PVOID InvalidateContext);
45
46 VOID
47 NTAPI
48 IoSynchronousInvalidateDeviceRelations(
49 IN PDEVICE_OBJECT DeviceObject,
50 IN DEVICE_RELATION_TYPE Type);
51
52
53 /* FUNCTIONS *****************************************************************/
54
55 PDEVICE_NODE
56 FASTCALL
57 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
58 {
59 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
60 }
61
62 NTSTATUS
63 FASTCALL
64 IopInitializeDevice(PDEVICE_NODE DeviceNode,
65 PDRIVER_OBJECT DriverObject)
66 {
67 PDEVICE_OBJECT Fdo;
68 NTSTATUS Status;
69 BOOLEAN IsPnpDriver = FALSE;
70
71 if (DriverObject->DriverExtension->AddDevice)
72 {
73 /* This is a Plug and Play driver */
74 DPRINT("Plug and Play driver found\n");
75
76 ASSERT(DeviceNode->PhysicalDeviceObject);
77
78 DPRINT("Calling driver AddDevice entrypoint at %08lx\n",
79 DriverObject->DriverExtension->AddDevice);
80
81 IsPnpDriver = !IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER);
82 Status = DriverObject->DriverExtension->AddDevice(
83 DriverObject, IsPnpDriver ? DeviceNode->PhysicalDeviceObject : NULL);
84
85 if (!NT_SUCCESS(Status))
86 {
87 return Status;
88 }
89
90 if (IsPnpDriver)
91 {
92 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
93
94 if (Fdo == DeviceNode->PhysicalDeviceObject)
95 {
96 /* FIXME: What do we do? Unload the driver or just disable the device? */
97 DbgPrint("An FDO was not attached\n");
98 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
99 return STATUS_UNSUCCESSFUL;
100 }
101
102 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
103 {
104 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
105
106 /* There can be only one system power device */
107 if (!SystemPowerDeviceNodeCreated)
108 {
109 PopSystemPowerDeviceNode = DeviceNode;
110 SystemPowerDeviceNodeCreated = TRUE;
111 }
112 }
113
114 ObDereferenceObject(Fdo);
115 }
116
117 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
118 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
119 }
120
121 return STATUS_SUCCESS;
122 }
123
124 NTSTATUS
125 IopStartDevice(
126 PDEVICE_NODE DeviceNode)
127 {
128 IO_STATUS_BLOCK IoStatusBlock;
129 IO_STACK_LOCATION Stack;
130 PDEVICE_OBJECT Fdo;
131 NTSTATUS Status;
132
133 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
134
135 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
136 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
137 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
138
139 Status = IopInitiatePnpIrp(
140 Fdo,
141 &IoStatusBlock,
142 IRP_MN_START_DEVICE,
143 &Stack);
144
145 if (!NT_SUCCESS(Status))
146 {
147 DPRINT("IopInitiatePnpIrp() failed\n");
148 }
149 else
150 {
151 if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
152 {
153 DPRINT("Device needs enumeration, invalidating bus relations\n");
154 /* Invalidate device relations synchronously
155 (otherwise there will be dirty read of DeviceNode) */
156 IoSynchronousInvalidateDeviceRelations(DeviceNode->PhysicalDeviceObject, BusRelations);
157 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
158 }
159 }
160
161 ObDereferenceObject(Fdo);
162
163 if (NT_SUCCESS(Status))
164 DeviceNode->Flags |= DN_STARTED;
165
166 return Status;
167 }
168
169 NTSTATUS
170 STDCALL
171 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
172 PDEVICE_CAPABILITIES DeviceCaps)
173 {
174 IO_STATUS_BLOCK StatusBlock;
175 IO_STACK_LOCATION Stack;
176
177 /* Set up the Header */
178 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
179 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
180 DeviceCaps->Version = 1;
181 DeviceCaps->Address = -1;
182 DeviceCaps->UINumber = -1;
183
184 /* Set up the Stack */
185 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
186 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
187
188 /* Send the IRP */
189 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
190 &StatusBlock,
191 IRP_MN_QUERY_CAPABILITIES,
192 &Stack);
193 }
194
195 /*
196 * @implemented
197 */
198 VOID
199 NTAPI
200 IoInvalidateDeviceRelations(
201 IN PDEVICE_OBJECT DeviceObject,
202 IN DEVICE_RELATION_TYPE Type)
203 {
204 PIO_WORKITEM WorkItem;
205 PINVALIDATE_DEVICE_RELATION_DATA Data;
206
207 Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
208 if (!Data)
209 return;
210 WorkItem = IoAllocateWorkItem(DeviceObject);
211 if (!WorkItem)
212 {
213 ExFreePool(Data);
214 return;
215 }
216
217 Data->Type = Type;
218 Data->WorkItem = WorkItem;
219 Data->Event = NULL;
220
221 IoQueueWorkItem(
222 WorkItem,
223 IopInvalidateDeviceRelations,
224 DelayedWorkQueue,
225 Data);
226 }
227
228 /*
229 * @implemented
230 */
231 VOID
232 NTAPI
233 IoSynchronousInvalidateDeviceRelations(
234 IN PDEVICE_OBJECT DeviceObject,
235 IN DEVICE_RELATION_TYPE Type)
236 {
237 PIO_WORKITEM WorkItem;
238 PINVALIDATE_DEVICE_RELATION_DATA Data;
239 KEVENT Event;
240
241 Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
242 if (!Data)
243 return;
244 WorkItem = IoAllocateWorkItem(DeviceObject);
245 if (!WorkItem)
246 {
247 ExFreePool(Data);
248 return;
249 }
250
251 KeInitializeEvent(&Event, NotificationEvent, FALSE);
252 Data->Type = Type;
253 Data->WorkItem = WorkItem;
254 Data->Event = &Event;
255
256 IoQueueWorkItem(
257 WorkItem,
258 IopInvalidateDeviceRelations,
259 DelayedWorkQueue,
260 Data);
261
262 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
263 ExFreePool(Data);
264 }
265
266 /*
267 * @unimplemented
268 */
269 NTSTATUS
270 STDCALL
271 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
272 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
273 IN ULONG BufferLength,
274 OUT PVOID PropertyBuffer,
275 OUT PULONG ResultLength)
276 {
277 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
278 DEVICE_CAPABILITIES DeviceCaps;
279 ULONG Length;
280 PVOID Data = NULL;
281 PWSTR Ptr;
282 NTSTATUS Status;
283
284 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
285
286 if (DeviceNode == NULL)
287 return STATUS_INVALID_DEVICE_REQUEST;
288
289 switch (DeviceProperty)
290 {
291 case DevicePropertyBusNumber:
292 Length = sizeof(ULONG);
293 Data = &DeviceNode->ChildBusNumber;
294 break;
295
296 /* Complete, untested */
297 case DevicePropertyBusTypeGuid:
298 /* Sanity check */
299 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
300 (DeviceNode->ChildBusTypeIndex < IopBusTypeGuidList->GuidCount))
301 {
302 /* Return the GUID */
303 *ResultLength = sizeof(GUID);
304
305 /* Check if the buffer given was large enough */
306 if (BufferLength < *ResultLength)
307 {
308 return STATUS_BUFFER_TOO_SMALL;
309 }
310
311 /* Copy the GUID */
312 RtlCopyMemory(PropertyBuffer,
313 &(IopBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
314 sizeof(GUID));
315 return STATUS_SUCCESS;
316 }
317 else
318 {
319 return STATUS_OBJECT_NAME_NOT_FOUND;
320 }
321 break;
322
323 case DevicePropertyLegacyBusType:
324 Length = sizeof(INTERFACE_TYPE);
325 Data = &DeviceNode->ChildInterfaceType;
326 break;
327
328 case DevicePropertyAddress:
329 /* Query the device caps */
330 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
331 if (NT_SUCCESS(Status) && (DeviceCaps.Address != (ULONG)-1))
332 {
333 /* Return length */
334 *ResultLength = sizeof(ULONG);
335
336 /* Check if the buffer given was large enough */
337 if (BufferLength < *ResultLength)
338 {
339 return STATUS_BUFFER_TOO_SMALL;
340 }
341
342 /* Return address */
343 *(PULONG)PropertyBuffer = DeviceCaps.Address;
344 return STATUS_SUCCESS;
345 }
346 else
347 {
348 return STATUS_OBJECT_NAME_NOT_FOUND;
349 }
350 break;
351
352 // case DevicePropertyUINumber:
353 // if (DeviceNode->CapabilityFlags == NULL)
354 // return STATUS_INVALID_DEVICE_REQUEST;
355 // Length = sizeof(ULONG);
356 // Data = &DeviceNode->CapabilityFlags->UINumber;
357 // break;
358
359 case DevicePropertyClassName:
360 case DevicePropertyClassGuid:
361 case DevicePropertyDriverKeyName:
362 case DevicePropertyManufacturer:
363 case DevicePropertyFriendlyName:
364 case DevicePropertyHardwareID:
365 case DevicePropertyCompatibleIDs:
366 case DevicePropertyDeviceDescription:
367 case DevicePropertyLocationInformation:
368 case DevicePropertyUINumber:
369 {
370 LPWSTR RegistryPropertyName, KeyNameBuffer;
371 UNICODE_STRING KeyName, ValueName;
372 OBJECT_ATTRIBUTES ObjectAttributes;
373 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
374 ULONG ValueInformationLength;
375 HANDLE KeyHandle;
376 NTSTATUS Status;
377
378 switch (DeviceProperty)
379 {
380 case DevicePropertyClassName:
381 RegistryPropertyName = L"Class"; break;
382 case DevicePropertyClassGuid:
383 RegistryPropertyName = L"ClassGuid"; break;
384 case DevicePropertyDriverKeyName:
385 RegistryPropertyName = L"Driver"; break;
386 case DevicePropertyManufacturer:
387 RegistryPropertyName = L"Mfg"; break;
388 case DevicePropertyFriendlyName:
389 RegistryPropertyName = L"FriendlyName"; break;
390 case DevicePropertyHardwareID:
391 RegistryPropertyName = L"HardwareID"; break;
392 case DevicePropertyCompatibleIDs:
393 RegistryPropertyName = L"CompatibleIDs"; break;
394 case DevicePropertyDeviceDescription:
395 RegistryPropertyName = L"DeviceDesc"; break;
396 case DevicePropertyLocationInformation:
397 RegistryPropertyName = L"LocationInformation"; break;
398 case DevicePropertyUINumber:
399 RegistryPropertyName = L"UINumber"; break;
400 default:
401 RegistryPropertyName = NULL; break;
402 }
403
404 KeyNameBuffer = ExAllocatePool(PagedPool,
405 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
406
407 DPRINT("KeyNameBuffer: 0x%p, value %S\n", KeyNameBuffer, RegistryPropertyName);
408
409 if (KeyNameBuffer == NULL)
410 return STATUS_INSUFFICIENT_RESOURCES;
411
412 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
413 wcscat(KeyNameBuffer, DeviceNode->InstancePath.Buffer);
414 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
415 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
416 OBJ_CASE_INSENSITIVE, NULL, NULL);
417
418 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
419 ExFreePool(KeyNameBuffer);
420 if (!NT_SUCCESS(Status))
421 return Status;
422
423 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
424 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
425 Data[0]) + BufferLength;
426 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
427 if (ValueInformation == NULL)
428 {
429 ZwClose(KeyHandle);
430 return STATUS_INSUFFICIENT_RESOURCES;
431 }
432
433 Status = ZwQueryValueKey(KeyHandle, &ValueName,
434 KeyValuePartialInformation, ValueInformation,
435 ValueInformationLength,
436 &ValueInformationLength);
437 *ResultLength = ValueInformation->DataLength;
438 ZwClose(KeyHandle);
439
440 if (!NT_SUCCESS(Status))
441 {
442 ExFreePool(ValueInformation);
443 if (Status == STATUS_BUFFER_OVERFLOW)
444 return STATUS_BUFFER_TOO_SMALL;
445 else
446 return Status;
447 }
448
449 /* FIXME: Verify the value (NULL-terminated, correct format). */
450
451 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
452 ValueInformation->DataLength);
453 ExFreePool(ValueInformation);
454
455 return STATUS_SUCCESS;
456 }
457
458 case DevicePropertyBootConfiguration:
459 Length = 0;
460 if (DeviceNode->BootResources->Count != 0)
461 {
462 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
463 }
464 Data = &DeviceNode->BootResources;
465 break;
466
467 /* FIXME: use a translated boot configuration instead */
468 case DevicePropertyBootConfigurationTranslated:
469 Length = 0;
470 if (DeviceNode->BootResources->Count != 0)
471 {
472 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
473 }
474 Data = &DeviceNode->BootResources;
475 break;
476
477 case DevicePropertyEnumeratorName:
478 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
479 if (Ptr != NULL)
480 {
481 Length = (ULONG)((ULONG_PTR)Ptr - (ULONG_PTR)DeviceNode->InstancePath.Buffer) + sizeof(WCHAR);
482 Data = DeviceNode->InstancePath.Buffer;
483 }
484 else
485 {
486 Length = 0;
487 Data = NULL;
488 }
489 break;
490
491 case DevicePropertyPhysicalDeviceObjectName:
492 Length = DeviceNode->InstancePath.Length + sizeof(WCHAR);
493 Data = DeviceNode->InstancePath.Buffer;
494 break;
495
496 default:
497 return STATUS_INVALID_PARAMETER_2;
498 }
499
500 *ResultLength = Length;
501 if (BufferLength < Length)
502 return STATUS_BUFFER_TOO_SMALL;
503 RtlCopyMemory(PropertyBuffer, Data, Length);
504
505 /* Terminate the string */
506 if (DeviceProperty == DevicePropertyEnumeratorName
507 || DeviceProperty == DevicePropertyPhysicalDeviceObjectName)
508 {
509 Ptr = (PWSTR)PropertyBuffer;
510 Ptr[(Length / sizeof(WCHAR)) - 1] = 0;
511 }
512
513 return STATUS_SUCCESS;
514 }
515
516 /*
517 * @unimplemented
518 */
519 VOID
520 STDCALL
521 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
522 {
523 UNIMPLEMENTED;
524 }
525
526 /**
527 * @name IoOpenDeviceRegistryKey
528 *
529 * Open a registry key unique for a specified driver or device instance.
530 *
531 * @param DeviceObject Device to get the registry key for.
532 * @param DevInstKeyType Type of the key to return.
533 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
534 * @param DevInstRegKey Handle to the opened registry key on
535 * successful return.
536 *
537 * @return Status.
538 *
539 * @implemented
540 */
541 NTSTATUS
542 STDCALL
543 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
544 IN ULONG DevInstKeyType,
545 IN ACCESS_MASK DesiredAccess,
546 OUT PHANDLE DevInstRegKey)
547 {
548 static WCHAR RootKeyName[] =
549 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
550 static WCHAR ProfileKeyName[] =
551 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
552 static WCHAR ClassKeyName[] = L"Control\\Class\\";
553 static WCHAR EnumKeyName[] = L"Enum\\";
554 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
555 ULONG KeyNameLength;
556 LPWSTR KeyNameBuffer;
557 UNICODE_STRING KeyName;
558 ULONG DriverKeyLength;
559 OBJECT_ATTRIBUTES ObjectAttributes;
560 PDEVICE_NODE DeviceNode = NULL;
561 NTSTATUS Status;
562
563 DPRINT("IoOpenDeviceRegistryKey() called\n");
564
565 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
566 {
567 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
568 return STATUS_INVALID_PARAMETER;
569 }
570
571 /*
572 * Calculate the length of the base key name. This is the full
573 * name for driver key or the name excluding "Device Parameters"
574 * subkey for device key.
575 */
576
577 KeyNameLength = sizeof(RootKeyName);
578 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
579 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
580 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
581 {
582 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
583 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
584 0, NULL, &DriverKeyLength);
585 if (Status != STATUS_BUFFER_TOO_SMALL)
586 return Status;
587 KeyNameLength += DriverKeyLength;
588 }
589 else
590 {
591 DeviceNode = IopGetDeviceNode(DeviceObject);
592 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
593 DeviceNode->InstancePath.Length;
594 }
595
596 /*
597 * Now allocate the buffer for the key name...
598 */
599
600 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
601 if (KeyNameBuffer == NULL)
602 return STATUS_INSUFFICIENT_RESOURCES;
603
604 KeyName.Length = 0;
605 KeyName.MaximumLength = (USHORT)KeyNameLength;
606 KeyName.Buffer = KeyNameBuffer;
607
608 /*
609 * ...and build the key name.
610 */
611
612 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
613 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
614
615 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
616 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
617
618 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
619 {
620 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
621 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
622 DriverKeyLength, KeyNameBuffer +
623 (KeyName.Length / sizeof(WCHAR)),
624 &DriverKeyLength);
625 if (!NT_SUCCESS(Status))
626 {
627 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
628 ExFreePool(KeyNameBuffer);
629 return Status;
630 }
631 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
632 }
633 else
634 {
635 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
636 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
637 if (DeviceNode->InstancePath.Length == 0)
638 {
639 ExFreePool(KeyNameBuffer);
640 return Status;
641 }
642 }
643
644 /*
645 * Open the base key.
646 */
647
648 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
649 OBJ_CASE_INSENSITIVE, NULL, NULL);
650 Status = ZwOpenKey(DevInstRegKey, DesiredAccess, &ObjectAttributes);
651 if (!NT_SUCCESS(Status))
652 {
653 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
654 ExFreePool(KeyNameBuffer);
655 return Status;
656 }
657 ExFreePool(KeyNameBuffer);
658
659 /*
660 * For driver key we're done now.
661 */
662
663 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
664 return Status;
665
666 /*
667 * Let's go further. For device key we must open "Device Parameters"
668 * subkey and create it if it doesn't exist yet.
669 */
670
671 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
672 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
673 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
674 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
675 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
676 ZwClose(ObjectAttributes.RootDirectory);
677
678 return Status;
679 }
680
681 /*
682 * @unimplemented
683 */
684 VOID
685 STDCALL
686 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
687 {
688 UNIMPLEMENTED;
689 }
690
691
692 NTSTATUS
693 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
694 {
695 KIRQL OldIrql;
696
697 if (PopSystemPowerDeviceNode)
698 {
699 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
700 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
701 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
702
703 return STATUS_SUCCESS;
704 }
705
706 return STATUS_UNSUCCESSFUL;
707 }
708
709 USHORT
710 STDCALL
711 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
712 {
713 USHORT i = 0, FoundIndex = 0xFFFF;
714 ULONG NewSize;
715 PVOID NewList;
716
717 /* Acquire the lock */
718 ExAcquireFastMutex(&IopBusTypeGuidList->Lock);
719
720 /* Loop all entries */
721 while (i < IopBusTypeGuidList->GuidCount)
722 {
723 /* Try to find a match */
724 if (RtlCompareMemory(BusTypeGuid,
725 &IopBusTypeGuidList->Guids[i],
726 sizeof(GUID)) == sizeof(GUID))
727 {
728 /* Found it */
729 FoundIndex = i;
730 goto Quickie;
731 }
732 i++;
733 }
734
735 /* Check if we have to grow the list */
736 if (IopBusTypeGuidList->GuidCount)
737 {
738 /* Calculate the new size */
739 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
740 (sizeof(GUID) * IopBusTypeGuidList->GuidCount);
741
742 /* Allocate the new copy */
743 NewList = ExAllocatePool(PagedPool, NewSize);
744
745 /* Now copy them, decrease the size too */
746 NewSize -= sizeof(GUID);
747 RtlCopyMemory(NewList, IopBusTypeGuidList, NewSize);
748
749 /* Free the old list */
750 ExFreePool(IopBusTypeGuidList);
751
752 /* Use the new buffer */
753 IopBusTypeGuidList = NewList;
754 }
755
756 /* Copy the new GUID */
757 RtlCopyMemory(&IopBusTypeGuidList->Guids[IopBusTypeGuidList->GuidCount],
758 BusTypeGuid,
759 sizeof(GUID));
760
761 /* The new entry is the index */
762 FoundIndex = (USHORT)IopBusTypeGuidList->GuidCount;
763 IopBusTypeGuidList->GuidCount++;
764
765 Quickie:
766 ExReleaseFastMutex(&IopBusTypeGuidList->Lock);
767 return FoundIndex;
768 }
769
770 /*
771 * DESCRIPTION
772 * Creates a device node
773 *
774 * ARGUMENTS
775 * ParentNode = Pointer to parent device node
776 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
777 * to have the root device node create one
778 * (eg. for legacy drivers)
779 * DeviceNode = Pointer to storage for created device node
780 *
781 * RETURN VALUE
782 * Status
783 */
784 NTSTATUS
785 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
786 PDEVICE_OBJECT PhysicalDeviceObject,
787 PDEVICE_NODE *DeviceNode)
788 {
789 PDEVICE_NODE Node;
790 NTSTATUS Status;
791 KIRQL OldIrql;
792
793 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p\n",
794 ParentNode, PhysicalDeviceObject);
795
796 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
797 if (!Node)
798 {
799 return STATUS_INSUFFICIENT_RESOURCES;
800 }
801
802 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
803
804 if (!PhysicalDeviceObject)
805 {
806 Status = PnpRootCreateDevice(&PhysicalDeviceObject);
807 if (!NT_SUCCESS(Status))
808 {
809 ExFreePool(Node);
810 return Status;
811 }
812
813 /* This is for drivers passed on the command line to ntoskrnl.exe */
814 IopDeviceNodeSetFlag(Node, DNF_STARTED);
815 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
816 }
817
818 Node->PhysicalDeviceObject = PhysicalDeviceObject;
819
820 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
821
822 if (ParentNode)
823 {
824 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
825 Node->Parent = ParentNode;
826 Node->NextSibling = ParentNode->Child;
827 if (ParentNode->Child != NULL)
828 {
829 ParentNode->Child->PrevSibling = Node;
830 }
831 ParentNode->Child = Node;
832 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
833 Node->Level = ParentNode->Level + 1;
834 }
835
836 *DeviceNode = Node;
837
838 return STATUS_SUCCESS;
839 }
840
841 NTSTATUS
842 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
843 {
844 KIRQL OldIrql;
845
846 /* All children must be deleted before a parent is deleted */
847 ASSERT(!DeviceNode->Child);
848
849 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
850
851 ASSERT(DeviceNode->PhysicalDeviceObject);
852
853 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
854
855 /* Unlink from parent if it exists */
856
857 if ((DeviceNode->Parent) && (DeviceNode->Parent->Child == DeviceNode))
858 {
859 DeviceNode->Parent->Child = DeviceNode->NextSibling;
860 }
861
862 /* Unlink from sibling list */
863
864 if (DeviceNode->PrevSibling)
865 {
866 DeviceNode->PrevSibling->NextSibling = DeviceNode->NextSibling;
867 }
868
869 if (DeviceNode->NextSibling)
870 {
871 DeviceNode->NextSibling->PrevSibling = DeviceNode->PrevSibling;
872 }
873
874 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
875
876 RtlFreeUnicodeString(&DeviceNode->InstancePath);
877
878 RtlFreeUnicodeString(&DeviceNode->ServiceName);
879
880 if (DeviceNode->ResourceList)
881 {
882 ExFreePool(DeviceNode->ResourceList);
883 }
884
885 if (DeviceNode->ResourceListTranslated)
886 {
887 ExFreePool(DeviceNode->ResourceListTranslated);
888 }
889
890 if (DeviceNode->ResourceRequirements)
891 {
892 ExFreePool(DeviceNode->ResourceRequirements);
893 }
894
895 if (DeviceNode->BootResources)
896 {
897 ExFreePool(DeviceNode->BootResources);
898 }
899
900 ExFreePool(DeviceNode);
901
902 return STATUS_SUCCESS;
903 }
904
905 NTSTATUS
906 IopInitiatePnpIrp(PDEVICE_OBJECT DeviceObject,
907 PIO_STATUS_BLOCK IoStatusBlock,
908 ULONG MinorFunction,
909 PIO_STACK_LOCATION Stack OPTIONAL)
910 {
911 PDEVICE_OBJECT TopDeviceObject;
912 PIO_STACK_LOCATION IrpSp;
913 NTSTATUS Status;
914 KEVENT Event;
915 PIRP Irp;
916
917 /* Always call the top of the device stack */
918 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
919
920 KeInitializeEvent(
921 &Event,
922 NotificationEvent,
923 FALSE);
924
925 Irp = IoBuildSynchronousFsdRequest(
926 IRP_MJ_PNP,
927 TopDeviceObject,
928 NULL,
929 0,
930 NULL,
931 &Event,
932 IoStatusBlock);
933
934 /* PNP IRPs are always initialized with a status code of
935 STATUS_NOT_IMPLEMENTED */
936 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
937 Irp->IoStatus.Information = 0;
938
939 IrpSp = IoGetNextIrpStackLocation(Irp);
940 IrpSp->MinorFunction = (UCHAR)MinorFunction;
941
942 if (Stack)
943 {
944 RtlCopyMemory(&IrpSp->Parameters,
945 &Stack->Parameters,
946 sizeof(Stack->Parameters));
947 }
948
949 Status = IoCallDriver(TopDeviceObject, Irp);
950 if (Status == STATUS_PENDING)
951 {
952 KeWaitForSingleObject(&Event,
953 Executive,
954 KernelMode,
955 FALSE,
956 NULL);
957 Status = IoStatusBlock->Status;
958 }
959
960 ObDereferenceObject(TopDeviceObject);
961
962 return Status;
963 }
964
965
966 NTSTATUS
967 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
968 {
969 PDEVICE_NODE ParentDeviceNode;
970 PDEVICE_NODE ChildDeviceNode;
971 NTSTATUS Status;
972
973 /* Copy context data so we don't overwrite it in subsequent calls to this function */
974 ParentDeviceNode = Context->DeviceNode;
975
976 /* Call the action routine */
977 Status = (Context->Action)(ParentDeviceNode, Context->Context);
978 if (!NT_SUCCESS(Status))
979 {
980 return Status;
981 }
982
983 /* Traversal of all children nodes */
984 for (ChildDeviceNode = ParentDeviceNode->Child;
985 ChildDeviceNode != NULL;
986 ChildDeviceNode = ChildDeviceNode->NextSibling)
987 {
988 /* Pass the current device node to the action routine */
989 Context->DeviceNode = ChildDeviceNode;
990
991 Status = IopTraverseDeviceTreeNode(Context);
992 if (!NT_SUCCESS(Status))
993 {
994 return Status;
995 }
996 }
997
998 return Status;
999 }
1000
1001
1002 NTSTATUS
1003 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
1004 {
1005 NTSTATUS Status;
1006
1007 DPRINT("Context 0x%p\n", Context);
1008
1009 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
1010 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
1011
1012 /* Start from the specified device node */
1013 Context->DeviceNode = Context->FirstDeviceNode;
1014
1015 /* Recursively traverse the device tree */
1016 Status = IopTraverseDeviceTreeNode(Context);
1017 if (Status == STATUS_UNSUCCESSFUL)
1018 {
1019 /* The action routine just wanted to terminate the traversal with status
1020 code STATUS_SUCCESS */
1021 Status = STATUS_SUCCESS;
1022 }
1023
1024 return Status;
1025 }
1026
1027
1028 static
1029 NTSTATUS
1030 IopCreateDeviceKeyPath(PWSTR Path,
1031 PHANDLE Handle)
1032 {
1033 OBJECT_ATTRIBUTES ObjectAttributes;
1034 WCHAR KeyBuffer[MAX_PATH];
1035 UNICODE_STRING KeyName;
1036 HANDLE KeyHandle;
1037 NTSTATUS Status;
1038 PWCHAR Current;
1039 PWCHAR Next;
1040
1041 *Handle = NULL;
1042
1043 if (_wcsnicmp(Path, L"\\Registry\\", 10) != 0)
1044 {
1045 return STATUS_INVALID_PARAMETER;
1046 }
1047
1048 wcsncpy (KeyBuffer, Path, MAX_PATH-1);
1049
1050 /* Skip \\Registry\\ */
1051 Current = KeyBuffer;
1052 Current = wcschr (Current, L'\\') + 1;
1053 Current = wcschr (Current, L'\\') + 1;
1054
1055 while (TRUE)
1056 {
1057 Next = wcschr (Current, L'\\');
1058 if (Next == NULL)
1059 {
1060 /* The end */
1061 }
1062 else
1063 {
1064 *Next = 0;
1065 }
1066
1067 RtlInitUnicodeString (&KeyName, KeyBuffer);
1068 InitializeObjectAttributes (&ObjectAttributes,
1069 &KeyName,
1070 OBJ_CASE_INSENSITIVE,
1071 NULL,
1072 NULL);
1073
1074 DPRINT("Create '%S'\n", KeyName.Buffer);
1075
1076 Status = ZwCreateKey (&KeyHandle,
1077 KEY_ALL_ACCESS,
1078 &ObjectAttributes,
1079 0,
1080 NULL,
1081 0,
1082 NULL);
1083 if (!NT_SUCCESS (Status))
1084 {
1085 DPRINT ("ZwCreateKey() failed with status %x\n", Status);
1086 return Status;
1087 }
1088
1089 if (Next == NULL)
1090 {
1091 *Handle = KeyHandle;
1092 return STATUS_SUCCESS;
1093 }
1094 else
1095 {
1096 ZwClose (KeyHandle);
1097 *Next = L'\\';
1098 }
1099
1100 Current = Next + 1;
1101 }
1102
1103 return STATUS_UNSUCCESSFUL;
1104 }
1105
1106
1107 static
1108 NTSTATUS
1109 IopSetDeviceInstanceData(HANDLE InstanceKey,
1110 PDEVICE_NODE DeviceNode)
1111 {
1112 OBJECT_ATTRIBUTES ObjectAttributes;
1113 UNICODE_STRING KeyName;
1114 HANDLE LogConfKey;
1115 ULONG ResCount;
1116 ULONG ListSize, ResultLength;
1117 NTSTATUS Status;
1118
1119 DPRINT("IopSetDeviceInstanceData() called\n");
1120
1121 /* Create the 'LogConf' key */
1122 RtlInitUnicodeString(&KeyName, L"LogConf");
1123 InitializeObjectAttributes(&ObjectAttributes,
1124 &KeyName,
1125 OBJ_CASE_INSENSITIVE,
1126 InstanceKey,
1127 NULL);
1128 Status = ZwCreateKey(&LogConfKey,
1129 KEY_ALL_ACCESS,
1130 &ObjectAttributes,
1131 0,
1132 NULL,
1133 0,
1134 NULL);
1135 if (NT_SUCCESS(Status))
1136 {
1137 /* Set 'BootConfig' value */
1138 if (DeviceNode->BootResources != NULL)
1139 {
1140 ResCount = DeviceNode->BootResources->Count;
1141 if (ResCount != 0)
1142 {
1143 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1144
1145 RtlInitUnicodeString(&KeyName, L"BootConfig");
1146 Status = ZwSetValueKey(LogConfKey,
1147 &KeyName,
1148 0,
1149 REG_RESOURCE_LIST,
1150 &DeviceNode->BootResources,
1151 ListSize);
1152 }
1153 }
1154
1155 /* Set 'BasicConfigVector' value */
1156 if (DeviceNode->ResourceRequirements != NULL &&
1157 DeviceNode->ResourceRequirements->ListSize != 0)
1158 {
1159 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1160 Status = ZwSetValueKey(LogConfKey,
1161 &KeyName,
1162 0,
1163 REG_RESOURCE_REQUIREMENTS_LIST,
1164 DeviceNode->ResourceRequirements,
1165 DeviceNode->ResourceRequirements->ListSize);
1166 }
1167
1168 ZwClose(LogConfKey);
1169 }
1170
1171 /* Set the 'ConfigFlags' value */
1172 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1173 Status = ZwQueryValueKey(InstanceKey,
1174 &KeyName,
1175 KeyValueBasicInformation,
1176 NULL,
1177 0,
1178 &ResultLength);
1179 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1180 {
1181 /* Write the default value */
1182 ULONG DefaultConfigFlags = 0;
1183 Status = ZwSetValueKey(InstanceKey,
1184 &KeyName,
1185 0,
1186 REG_DWORD,
1187 &DefaultConfigFlags,
1188 sizeof(DefaultConfigFlags));
1189 }
1190
1191 #if 0
1192 if (DeviceNode->PhysicalDeviceObject != NULL)
1193 {
1194 /* Create the 'Control' key */
1195 RtlInitUnicodeString(&KeyName,
1196 L"Control");
1197 InitializeObjectAttributes(&ObjectAttributes,
1198 &KeyName,
1199 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
1200 InstanceKey,
1201 NULL);
1202 Status = ZwCreateKey(&LogConfKey,
1203 KEY_ALL_ACCESS,
1204 &ObjectAttributes,
1205 0,
1206 NULL,
1207 REG_OPTION_VOLATILE,
1208 NULL);
1209 if (NT_SUCCESS(Status))
1210 {
1211 ULONG Reference = (ULONG)DeviceNode->PhysicalDeviceObject;
1212 RtlInitUnicodeString(&KeyName,
1213 L"DeviceReference");
1214 Status = ZwSetValueKey(LogConfKey,
1215 &KeyName,
1216 0,
1217 REG_DWORD,
1218 &Reference,
1219 sizeof(PVOID));
1220
1221 ZwClose(LogConfKey);
1222 }
1223 }
1224 #endif
1225
1226 DPRINT("IopSetDeviceInstanceData() done\n");
1227
1228 return STATUS_SUCCESS;
1229 }
1230
1231
1232 static NTSTATUS
1233 IopAssignDeviceResources(
1234 IN PDEVICE_NODE DeviceNode,
1235 OUT ULONG *pRequiredSize)
1236 {
1237 PIO_RESOURCE_LIST ResourceList;
1238 PIO_RESOURCE_DESCRIPTOR ResourceDescriptor;
1239 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw;
1240 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1241 ULONG NumberOfResources = 0;
1242 ULONG Size;
1243 ULONG i, j;
1244 NTSTATUS Status;
1245
1246 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1247 {
1248 /* No resource needed for this device */
1249 DeviceNode->ResourceList = NULL;
1250 return STATUS_SUCCESS;
1251 }
1252
1253 /* Fill DeviceNode->ResourceList
1254 * FIXME: the PnP arbiter should go there!
1255 * Actually, use the BootResources if provided, else the resource list #0
1256 */
1257
1258 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1259
1260 if (DeviceNode->BootResources)
1261 {
1262 /* Browse the boot resources to know if we have some custom structures */
1263 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1264 for (i = 0; i < DeviceNode->BootResources->Count; i++)
1265 {
1266 pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
1267 if (pPartialResourceList->Version != 1 || pPartialResourceList->Revision != 1)
1268 {
1269 Status = STATUS_REVISION_MISMATCH;
1270 goto ByeBye;
1271 }
1272 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1273 + pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1274 for (j = 0; j < pPartialResourceList->Count; j++)
1275 {
1276 if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
1277 Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
1278 }
1279 }
1280
1281 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1282 if (!DeviceNode->ResourceList)
1283 {
1284 Status = STATUS_NO_MEMORY;
1285 goto ByeBye;
1286 }
1287 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
1288
1289 *pRequiredSize = Size;
1290 return STATUS_SUCCESS;
1291 }
1292
1293 /* Ok, here, we have to use the device requirement list */
1294 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1295
1296 ResourceList = &DeviceNode->ResourceRequirements->List[0];
1297 if (ResourceList->Version != 1 || ResourceList->Revision != 1)
1298 {
1299 Status = STATUS_REVISION_MISMATCH;
1300 goto ByeBye;
1301 }
1302
1303 Size = sizeof(CM_RESOURCE_LIST) + ResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1304 *pRequiredSize = Size;
1305 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1306 if (!DeviceNode->ResourceList)
1307 {
1308 Status = STATUS_NO_MEMORY;
1309 goto ByeBye;
1310 }
1311
1312 DeviceNode->ResourceList->Count = 1;
1313 DeviceNode->ResourceList->List[0].InterfaceType = DeviceNode->ResourceRequirements->InterfaceType;
1314 DeviceNode->ResourceList->List[0].BusNumber = DeviceNode->ResourceRequirements->BusNumber;
1315 DeviceNode->ResourceList->List[0].PartialResourceList.Version = 1;
1316 DeviceNode->ResourceList->List[0].PartialResourceList.Revision = 1;
1317
1318 for (i = 0; i < ResourceList->Count; i++)
1319 {
1320 ResourceDescriptor = &ResourceList->Descriptors[i];
1321
1322 if (ResourceDescriptor->Option == 0 || ResourceDescriptor->Option == IO_RESOURCE_PREFERRED)
1323 {
1324 DescriptorRaw = &DeviceNode->ResourceList->List[0].PartialResourceList.PartialDescriptors[NumberOfResources];
1325 NumberOfResources++;
1326
1327 /* Copy ResourceDescriptor to DescriptorRaw and DescriptorTranslated */
1328 DescriptorRaw->Type = ResourceDescriptor->Type;
1329 DescriptorRaw->ShareDisposition = ResourceDescriptor->ShareDisposition;
1330 DescriptorRaw->Flags = ResourceDescriptor->Flags;
1331 switch (ResourceDescriptor->Type)
1332 {
1333 case CmResourceTypePort:
1334 {
1335 DescriptorRaw->u.Port.Start = ResourceDescriptor->u.Port.MinimumAddress;
1336 DescriptorRaw->u.Port.Length = ResourceDescriptor->u.Port.Length;
1337 break;
1338 }
1339 case CmResourceTypeInterrupt:
1340 {
1341 INTERFACE_TYPE BusType;
1342 ULONG SlotNumber;
1343 ULONG ret;
1344 UCHAR Irq;
1345
1346 DescriptorRaw->u.Interrupt.Level = 0;
1347 DescriptorRaw->u.Interrupt.Vector = ResourceDescriptor->u.Interrupt.MinimumVector;
1348 /* FIXME: HACK: if we have a PCI device, we try
1349 * to keep the IRQ assigned by the BIOS */
1350 if (NT_SUCCESS(IoGetDeviceProperty(
1351 DeviceNode->PhysicalDeviceObject,
1352 DevicePropertyLegacyBusType,
1353 sizeof(INTERFACE_TYPE),
1354 &BusType,
1355 &ret)) && BusType == PCIBus)
1356 {
1357 /* We have a PCI bus */
1358 if (NT_SUCCESS(IoGetDeviceProperty(
1359 DeviceNode->PhysicalDeviceObject,
1360 DevicePropertyAddress,
1361 sizeof(ULONG),
1362 &SlotNumber,
1363 &ret)) && SlotNumber > 0)
1364 {
1365 /* We have a good slot number */
1366 ret = HalGetBusDataByOffset(PCIConfiguration,
1367 DeviceNode->ResourceRequirements->BusNumber,
1368 SlotNumber,
1369 &Irq,
1370 0x3c /* PCI_INTERRUPT_LINE */,
1371 sizeof(UCHAR));
1372 if (ret != 0 && ret != 2
1373 && ResourceDescriptor->u.Interrupt.MinimumVector <= Irq
1374 && ResourceDescriptor->u.Interrupt.MaximumVector >= Irq)
1375 {
1376 /* The device already has an assigned IRQ */
1377 DescriptorRaw->u.Interrupt.Vector = Irq;
1378 }
1379 else
1380 {
1381 DPRINT1("Trying to assign IRQ 0x%lx to %wZ\n",
1382 DescriptorRaw->u.Interrupt.Vector,
1383 &DeviceNode->InstancePath);
1384 Irq = (UCHAR)DescriptorRaw->u.Interrupt.Vector;
1385 ret = HalSetBusDataByOffset(PCIConfiguration,
1386 DeviceNode->ResourceRequirements->BusNumber,
1387 SlotNumber,
1388 &Irq,
1389 0x3c /* PCI_INTERRUPT_LINE */,
1390 sizeof(UCHAR));
1391 if (ret == 0 || ret == 2)
1392 KEBUGCHECK(0);
1393 }
1394 }
1395 }
1396 break;
1397 }
1398 case CmResourceTypeMemory:
1399 {
1400 DescriptorRaw->u.Memory.Start = ResourceDescriptor->u.Memory.MinimumAddress;
1401 DescriptorRaw->u.Memory.Length = ResourceDescriptor->u.Memory.Length;
1402 break;
1403 }
1404 case CmResourceTypeDma:
1405 {
1406 DescriptorRaw->u.Dma.Channel = ResourceDescriptor->u.Dma.MinimumChannel;
1407 DescriptorRaw->u.Dma.Port = 0; /* FIXME */
1408 DescriptorRaw->u.Dma.Reserved1 = 0;
1409 break;
1410 }
1411 case CmResourceTypeBusNumber:
1412 {
1413 DescriptorRaw->u.BusNumber.Start = ResourceDescriptor->u.BusNumber.MinBusNumber;
1414 DescriptorRaw->u.BusNumber.Length = ResourceDescriptor->u.BusNumber.Length;
1415 DescriptorRaw->u.BusNumber.Reserved = ResourceDescriptor->u.BusNumber.Reserved;
1416 break;
1417 }
1418 /*CmResourceTypeDevicePrivate:
1419 case CmResourceTypePcCardConfig:
1420 case CmResourceTypeMfCardConfig:
1421 {
1422 RtlCopyMemory(
1423 &DescriptorRaw->u.DevicePrivate,
1424 &ResourceDescriptor->u.DevicePrivate,
1425 sizeof(ResourceDescriptor->u.DevicePrivate));
1426 RtlCopyMemory(
1427 &DescriptorTranslated->u.DevicePrivate,
1428 &ResourceDescriptor->u.DevicePrivate,
1429 sizeof(ResourceDescriptor->u.DevicePrivate));
1430 break;
1431 }*/
1432 default:
1433 DPRINT1("IopAssignDeviceResources(): unknown resource descriptor type 0x%x\n", ResourceDescriptor->Type);
1434 NumberOfResources--;
1435 }
1436 }
1437
1438 }
1439
1440 DeviceNode->ResourceList->List[0].PartialResourceList.Count = NumberOfResources;
1441
1442 return STATUS_SUCCESS;
1443
1444 ByeBye:
1445 if (DeviceNode->ResourceList)
1446 {
1447 ExFreePool(DeviceNode->ResourceList);
1448 DeviceNode->ResourceList = NULL;
1449 }
1450 return Status;
1451 }
1452
1453
1454 static NTSTATUS
1455 IopTranslateDeviceResources(
1456 IN PDEVICE_NODE DeviceNode,
1457 IN ULONG RequiredSize)
1458 {
1459 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1460 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1461 ULONG i, j;
1462 NTSTATUS Status;
1463
1464 if (!DeviceNode->ResourceList)
1465 {
1466 DeviceNode->ResourceListTranslated = NULL;
1467 return STATUS_SUCCESS;
1468 }
1469
1470 /* That's easy to translate a resource list. Just copy the
1471 * untranslated one and change few fields in the copy
1472 */
1473 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
1474 if (!DeviceNode->ResourceListTranslated)
1475 {
1476 Status =STATUS_NO_MEMORY;
1477 goto cleanup;
1478 }
1479 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
1480
1481 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1482 {
1483 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1484 for (j = 0; j < pPartialResourceList->Count; j++)
1485 {
1486 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
1487 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
1488 switch (DescriptorRaw->Type)
1489 {
1490 case CmResourceTypePort:
1491 {
1492 ULONG AddressSpace = 0; /* IO space */
1493 if (!HalTranslateBusAddress(
1494 DeviceNode->ResourceList->List[i].InterfaceType,
1495 DeviceNode->ResourceList->List[i].BusNumber,
1496 DescriptorRaw->u.Port.Start,
1497 &AddressSpace,
1498 &DescriptorTranslated->u.Port.Start))
1499 {
1500 Status = STATUS_UNSUCCESSFUL;
1501 goto cleanup;
1502 }
1503 break;
1504 }
1505 case CmResourceTypeInterrupt:
1506 {
1507 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1508 DeviceNode->ResourceList->List[i].InterfaceType,
1509 DeviceNode->ResourceList->List[i].BusNumber,
1510 DescriptorRaw->u.Interrupt.Level,
1511 DescriptorRaw->u.Interrupt.Vector,
1512 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1513 &DescriptorRaw->u.Interrupt.Affinity);
1514 break;
1515 }
1516 case CmResourceTypeMemory:
1517 {
1518 ULONG AddressSpace = 1; /* Memory space */
1519 if (!HalTranslateBusAddress(
1520 DeviceNode->ResourceList->List[i].InterfaceType,
1521 DeviceNode->ResourceList->List[i].BusNumber,
1522 DescriptorRaw->u.Memory.Start,
1523 &AddressSpace,
1524 &DescriptorTranslated->u.Memory.Start))
1525 {
1526 Status = STATUS_UNSUCCESSFUL;
1527 goto cleanup;
1528 }
1529 }
1530
1531 case CmResourceTypeDma:
1532 case CmResourceTypeBusNumber:
1533 case CmResourceTypeDeviceSpecific:
1534 /* Nothing to do */
1535 break;
1536 default:
1537 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1538 Status = STATUS_NOT_IMPLEMENTED;
1539 goto cleanup;
1540 }
1541 }
1542 }
1543 return STATUS_SUCCESS;
1544
1545 cleanup:
1546 /* Yes! Also delete ResourceList because ResourceList and
1547 * ResourceListTranslated should be a pair! */
1548 ExFreePool(DeviceNode->ResourceList);
1549 DeviceNode->ResourceList = NULL;
1550 if (DeviceNode->ResourceListTranslated)
1551 {
1552 ExFreePool(DeviceNode->ResourceListTranslated);
1553 DeviceNode->ResourceList = NULL;
1554 }
1555 return Status;
1556 }
1557
1558
1559 /*
1560 * IopGetParentIdPrefix
1561 *
1562 * Retrieve (or create) a string which identifies a device.
1563 *
1564 * Parameters
1565 * DeviceNode
1566 * Pointer to device node.
1567 * ParentIdPrefix
1568 * Pointer to the string where is returned the parent node identifier
1569 *
1570 * Remarks
1571 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
1572 * valid and its Buffer field is NULL-terminated. The caller needs to
1573 * to free the string with RtlFreeUnicodeString when it is no longer
1574 * needed.
1575 */
1576
1577 NTSTATUS
1578 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
1579 PUNICODE_STRING ParentIdPrefix)
1580 {
1581 ULONG KeyNameBufferLength;
1582 PWSTR KeyNameBuffer = NULL;
1583 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
1584 UNICODE_STRING KeyName;
1585 UNICODE_STRING KeyValue;
1586 UNICODE_STRING ValueName;
1587 OBJECT_ATTRIBUTES ObjectAttributes;
1588 HANDLE hKey = NULL;
1589 ULONG crc32;
1590 NTSTATUS Status;
1591
1592 /* HACK: As long as some devices have a NULL device
1593 * instance path, the following test is required :(
1594 */
1595 if (DeviceNode->Parent->InstancePath.Length == 0)
1596 return STATUS_UNSUCCESSFUL;
1597
1598 /* 1. Try to retrieve ParentIdPrefix from registry */
1599 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
1600 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
1601 if (!ParentIdPrefixInformation)
1602 {
1603 Status = STATUS_INSUFFICIENT_RESOURCES;
1604 goto cleanup;
1605 }
1606 KeyNameBuffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
1607 if (!KeyNameBuffer)
1608 {
1609 Status = STATUS_INSUFFICIENT_RESOURCES;
1610 goto cleanup;
1611 }
1612 wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1613 wcscat(KeyNameBuffer, DeviceNode->Parent->InstancePath.Buffer);
1614 RtlInitUnicodeString(&KeyName, KeyNameBuffer);
1615 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
1616 Status = ZwOpenKey(&hKey, KEY_QUERY_VALUE | KEY_SET_VALUE, &ObjectAttributes);
1617 if (!NT_SUCCESS(Status))
1618 goto cleanup;
1619 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
1620 Status = ZwQueryValueKey(
1621 hKey, &ValueName,
1622 KeyValuePartialInformation, ParentIdPrefixInformation,
1623 KeyNameBufferLength, &KeyNameBufferLength);
1624 if (NT_SUCCESS(Status))
1625 {
1626 if (ParentIdPrefixInformation->Type != REG_SZ)
1627 Status = STATUS_UNSUCCESSFUL;
1628 else
1629 {
1630 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1631 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1632 }
1633 goto cleanup;
1634 }
1635 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
1636 {
1637 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
1638 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
1639 goto cleanup;
1640 }
1641
1642 /* 2. Create the ParentIdPrefix value */
1643 crc32 = RtlComputeCrc32(0,
1644 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
1645 DeviceNode->Parent->InstancePath.Length);
1646
1647 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
1648 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
1649
1650 /* 3. Try to write the ParentIdPrefix to registry */
1651 Status = ZwSetValueKey(hKey,
1652 &ValueName,
1653 0,
1654 REG_SZ,
1655 (PVOID)KeyValue.Buffer,
1656 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
1657
1658 cleanup:
1659 if (NT_SUCCESS(Status))
1660 {
1661 /* Duplicate the string to return it */
1662 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
1663 }
1664 ExFreePool(ParentIdPrefixInformation);
1665 ExFreePool(KeyNameBuffer);
1666 if (hKey != NULL)
1667 ZwClose(hKey);
1668 return Status;
1669 }
1670
1671
1672 /*
1673 * IopActionInterrogateDeviceStack
1674 *
1675 * Retrieve information for all (direct) child nodes of a parent node.
1676 *
1677 * Parameters
1678 * DeviceNode
1679 * Pointer to device node.
1680 * Context
1681 * Pointer to parent node to retrieve child node information for.
1682 *
1683 * Remarks
1684 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
1685 * when we reach a device node which is not a direct child of the device
1686 * node for which we retrieve information of child nodes for. Any errors
1687 * that occur is logged instead so that all child services have a chance
1688 * of being interrogated.
1689 */
1690
1691 NTSTATUS
1692 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
1693 PVOID Context)
1694 {
1695 IO_STATUS_BLOCK IoStatusBlock;
1696 PDEVICE_NODE ParentDeviceNode;
1697 WCHAR InstancePath[MAX_PATH];
1698 IO_STACK_LOCATION Stack;
1699 NTSTATUS Status;
1700 PWSTR KeyBuffer;
1701 PWSTR Ptr;
1702 USHORT Length;
1703 USHORT TotalLength;
1704 ULONG RequiredLength;
1705 LCID LocaleId;
1706 HANDLE InstanceKey = NULL;
1707 UNICODE_STRING ValueName;
1708 UNICODE_STRING ParentIdPrefix = { 0 };
1709 DEVICE_CAPABILITIES DeviceCapabilities;
1710
1711 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
1712 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
1713
1714 ParentDeviceNode = (PDEVICE_NODE)Context;
1715
1716 /*
1717 * We are called for the parent too, but we don't need to do special
1718 * handling for this node
1719 */
1720
1721 if (DeviceNode == ParentDeviceNode)
1722 {
1723 DPRINT("Success\n");
1724 return STATUS_SUCCESS;
1725 }
1726
1727 /*
1728 * Make sure this device node is a direct child of the parent device node
1729 * that is given as an argument
1730 */
1731
1732 if (DeviceNode->Parent != ParentDeviceNode)
1733 {
1734 /* Stop the traversal immediately and indicate successful operation */
1735 DPRINT("Stop\n");
1736 return STATUS_UNSUCCESSFUL;
1737 }
1738
1739 /* Get Locale ID */
1740 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
1741 if (!NT_SUCCESS(Status))
1742 {
1743 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
1744 return Status;
1745 }
1746
1747 /*
1748 * FIXME: For critical errors, cleanup and disable device, but always
1749 * return STATUS_SUCCESS.
1750 */
1751
1752 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
1753
1754 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
1755 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1756 &IoStatusBlock,
1757 IRP_MN_QUERY_ID,
1758 &Stack);
1759 if (NT_SUCCESS(Status))
1760 {
1761 /* Copy the device id string */
1762 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
1763
1764 /*
1765 * FIXME: Check for valid characters, if there is invalid characters
1766 * then bugcheck.
1767 */
1768 }
1769 else
1770 {
1771 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1772 }
1773
1774 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
1775
1776 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
1777 if (!NT_SUCCESS(Status))
1778 {
1779 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
1780 }
1781
1782 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
1783
1784 if (!DeviceCapabilities.UniqueID)
1785 {
1786 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
1787 DPRINT("Instance ID is not unique\n");
1788 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
1789 if (!NT_SUCCESS(Status))
1790 {
1791 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
1792 }
1793 }
1794
1795 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
1796
1797 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
1798 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1799 &IoStatusBlock,
1800 IRP_MN_QUERY_ID,
1801 &Stack);
1802 if (NT_SUCCESS(Status))
1803 {
1804 /* Append the instance id string */
1805 wcscat(InstancePath, L"\\");
1806 if (ParentIdPrefix.Length > 0)
1807 {
1808 /* Add information from parent bus device to InstancePath */
1809 wcscat(InstancePath, ParentIdPrefix.Buffer);
1810 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
1811 wcscat(InstancePath, L"&");
1812 }
1813 if (IoStatusBlock.Information)
1814 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
1815
1816 /*
1817 * FIXME: Check for valid characters, if there is invalid characters
1818 * then bugcheck
1819 */
1820 }
1821 else
1822 {
1823 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1824 }
1825 RtlFreeUnicodeString(&ParentIdPrefix);
1826
1827 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
1828 {
1829 DPRINT("No resources\n");
1830 /* FIXME: Cleanup and disable device */
1831 }
1832
1833 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
1834
1835 /*
1836 * Create registry key for the instance id, if it doesn't exist yet
1837 */
1838 KeyBuffer = ExAllocatePool(
1839 PagedPool,
1840 (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
1841 wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
1842 wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
1843 Status = IopCreateDeviceKeyPath(KeyBuffer, &InstanceKey);
1844 ExFreePool(KeyBuffer);
1845 if (!NT_SUCCESS(Status))
1846 {
1847 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
1848 }
1849
1850
1851 {
1852 /* Set 'Capabilities' value */
1853 RtlInitUnicodeString(&ValueName, L"Capabilities");
1854 Status = ZwSetValueKey(InstanceKey,
1855 &ValueName,
1856 0,
1857 REG_DWORD,
1858 (PVOID)&DeviceNode->CapabilityFlags,
1859 sizeof(ULONG));
1860
1861 /* Set 'UINumber' value */
1862 if (DeviceCapabilities.UINumber != (ULONG)-1)
1863 {
1864 RtlInitUnicodeString(&ValueName, L"UINumber");
1865 Status = ZwSetValueKey(InstanceKey,
1866 &ValueName,
1867 0,
1868 REG_DWORD,
1869 &DeviceCapabilities.UINumber,
1870 sizeof(ULONG));
1871 }
1872 }
1873
1874 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
1875
1876 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
1877 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
1878 &IoStatusBlock,
1879 IRP_MN_QUERY_ID,
1880 &Stack);
1881 if (NT_SUCCESS(Status))
1882 {
1883 /*
1884 * FIXME: Check for valid characters, if there is invalid characters
1885 * then bugcheck.
1886 */
1887 TotalLength = 0;
1888 Ptr = (PWSTR)IoStatusBlock.Information;
1889 DPRINT("Hardware IDs:\n");
1890 while (*Ptr)
1891 {
1892 DPRINT(" %S\n", Ptr);
1893 Length = wcslen(Ptr) + 1;
1894
1895 Ptr += Length;
1896 TotalLength += Length;
1897 }
1898 DPRINT("TotalLength: %hu\n", TotalLength);
1899 DPRINT("\n");
1900
1901 RtlInitUnicodeString(&ValueName, L"HardwareID");
1902 Status = ZwSetValueKey(InstanceKey,
1903 &ValueName,
1904 0,
1905 REG_MULTI_SZ,
1906 (PVOID)IoStatusBlock.Information,
1907 (TotalLength + 1) * sizeof(WCHAR));
1908 if (!NT_SUCCESS(Status))
1909 {
1910 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
1911 }
1912 }
1913 else
1914 {
1915 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1916 }
1917
1918 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
1919
1920 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
1921 Status = IopInitiatePnpIrp(
1922 DeviceNode->PhysicalDeviceObject,
1923 &IoStatusBlock,
1924 IRP_MN_QUERY_ID,
1925 &Stack);
1926 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
1927 {
1928 /*
1929 * FIXME: Check for valid characters, if there is invalid characters
1930 * then bugcheck.
1931 */
1932 TotalLength = 0;
1933 Ptr = (PWSTR)IoStatusBlock.Information;
1934 DPRINT("Compatible IDs:\n");
1935 while (*Ptr)
1936 {
1937 DPRINT(" %S\n", Ptr);
1938 Length = wcslen(Ptr) + 1;
1939
1940 Ptr += Length;
1941 TotalLength += Length;
1942 }
1943 DPRINT("TotalLength: %hu\n", TotalLength);
1944 DPRINT("\n");
1945
1946 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
1947 Status = ZwSetValueKey(InstanceKey,
1948 &ValueName,
1949 0,
1950 REG_MULTI_SZ,
1951 (PVOID)IoStatusBlock.Information,
1952 (TotalLength + 1) * sizeof(WCHAR));
1953 if (!NT_SUCCESS(Status))
1954 {
1955 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
1956 }
1957 }
1958 else
1959 {
1960 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
1961 }
1962
1963
1964 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
1965
1966 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
1967 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
1968 Status = IopInitiatePnpIrp(
1969 DeviceNode->PhysicalDeviceObject,
1970 &IoStatusBlock,
1971 IRP_MN_QUERY_DEVICE_TEXT,
1972 &Stack);
1973 /* This key is mandatory, so even if the Irp fails, we still write it */
1974 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
1975 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
1976 {
1977 if (NT_SUCCESS(Status) &&
1978 IoStatusBlock.Information &&
1979 (*(PWSTR)IoStatusBlock.Information != 0))
1980 {
1981 /* This key is overriden when a driver is installed. Don't write the
1982 * new description if another one already exists */
1983 Status = ZwSetValueKey(InstanceKey,
1984 &ValueName,
1985 0,
1986 REG_SZ,
1987 (PVOID)IoStatusBlock.Information,
1988 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
1989 }
1990 else
1991 {
1992 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
1993 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
1994
1995 Status = ZwSetValueKey(InstanceKey,
1996 &ValueName,
1997 0,
1998 REG_SZ,
1999 DeviceDesc.Buffer,
2000 DeviceDesc.MaximumLength);
2001
2002 if (!NT_SUCCESS(Status))
2003 {
2004 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2005 }
2006
2007 }
2008 }
2009
2010 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2011
2012 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2013 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2014 Status = IopInitiatePnpIrp(
2015 DeviceNode->PhysicalDeviceObject,
2016 &IoStatusBlock,
2017 IRP_MN_QUERY_DEVICE_TEXT,
2018 &Stack);
2019 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2020 {
2021 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2022 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2023 Status = ZwSetValueKey(InstanceKey,
2024 &ValueName,
2025 0,
2026 REG_SZ,
2027 (PVOID)IoStatusBlock.Information,
2028 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2029 if (!NT_SUCCESS(Status))
2030 {
2031 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2032 }
2033 }
2034 else
2035 {
2036 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2037 }
2038
2039 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2040
2041 Status = IopInitiatePnpIrp(
2042 DeviceNode->PhysicalDeviceObject,
2043 &IoStatusBlock,
2044 IRP_MN_QUERY_BUS_INFORMATION,
2045 NULL);
2046 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2047 {
2048 PPNP_BUS_INFORMATION BusInformation =
2049 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2050
2051 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2052 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2053 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2054 ExFreePool(BusInformation);
2055 }
2056 else
2057 {
2058 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2059
2060 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2061 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2062 DeviceNode->ChildBusTypeIndex = -1;
2063 }
2064
2065 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2066
2067 Status = IopInitiatePnpIrp(
2068 DeviceNode->PhysicalDeviceObject,
2069 &IoStatusBlock,
2070 IRP_MN_QUERY_RESOURCES,
2071 NULL);
2072 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2073 {
2074 DeviceNode->BootResources =
2075 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2076 DeviceNode->Flags |= DNF_HAS_BOOT_CONFIG;
2077 }
2078 else
2079 {
2080 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2081 DeviceNode->BootResources = NULL;
2082 }
2083
2084 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2085
2086 Status = IopInitiatePnpIrp(
2087 DeviceNode->PhysicalDeviceObject,
2088 &IoStatusBlock,
2089 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2090 NULL);
2091 if (NT_SUCCESS(Status))
2092 {
2093 DeviceNode->ResourceRequirements =
2094 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2095 if (IoStatusBlock.Information)
2096 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
2097 else
2098 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
2099 }
2100 else
2101 {
2102 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2103 DeviceNode->ResourceRequirements = NULL;
2104 }
2105
2106
2107 if (InstanceKey != NULL)
2108 {
2109 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2110 }
2111
2112 ZwClose(InstanceKey);
2113
2114 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
2115 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
2116 if (NT_SUCCESS(Status))
2117 {
2118 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
2119 if (NT_SUCCESS(Status))
2120 {
2121 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
2122 }
2123 else
2124 {
2125 DPRINT("IopTranslateDeviceResources() failed (Status 0x08lx)\n", Status);
2126 }
2127 }
2128 else
2129 {
2130 DPRINT("IopAssignDeviceResources() failed (Status 0x08lx)\n", Status);
2131 }
2132 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
2133
2134 DeviceNode->Flags |= DNF_PROCESSED;
2135
2136 /* Report the device to the user-mode pnp manager */
2137 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2138 &DeviceNode->InstancePath);
2139
2140 return STATUS_SUCCESS;
2141 }
2142
2143 /*
2144 * IopActionConfigureChildServices
2145 *
2146 * Retrieve configuration for all (direct) child nodes of a parent node.
2147 *
2148 * Parameters
2149 * DeviceNode
2150 * Pointer to device node.
2151 * Context
2152 * Pointer to parent node to retrieve child node configuration for.
2153 *
2154 * Remarks
2155 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2156 * when we reach a device node which is not a direct child of the device
2157 * node for which we configure child services for. Any errors that occur is
2158 * logged instead so that all child services have a chance of beeing
2159 * configured.
2160 */
2161
2162 NTSTATUS
2163 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2164 PVOID Context)
2165 {
2166 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2167 PDEVICE_NODE ParentDeviceNode;
2168 PUNICODE_STRING Service;
2169 UNICODE_STRING ClassGUID;
2170 UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
2171 NTSTATUS Status;
2172
2173 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2174
2175 ParentDeviceNode = (PDEVICE_NODE)Context;
2176
2177 /*
2178 * We are called for the parent too, but we don't need to do special
2179 * handling for this node
2180 */
2181 if (DeviceNode == ParentDeviceNode)
2182 {
2183 DPRINT("Success\n");
2184 return STATUS_SUCCESS;
2185 }
2186
2187 /*
2188 * Make sure this device node is a direct child of the parent device node
2189 * that is given as an argument
2190 */
2191 if (DeviceNode->Parent != ParentDeviceNode)
2192 {
2193 /* Stop the traversal immediately and indicate successful operation */
2194 DPRINT("Stop\n");
2195 return STATUS_UNSUCCESSFUL;
2196 }
2197
2198 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2199 {
2200 WCHAR RegKeyBuffer[MAX_PATH];
2201 UNICODE_STRING RegKey;
2202
2203 RegKey.Length = 0;
2204 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2205 RegKey.Buffer = RegKeyBuffer;
2206
2207 /*
2208 * Retrieve configuration from Enum key
2209 */
2210
2211 Service = &DeviceNode->ServiceName;
2212
2213 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2214 RtlInitUnicodeString(Service, NULL);
2215 RtlInitUnicodeString(&ClassGUID, NULL);
2216
2217 QueryTable[0].Name = L"Service";
2218 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2219 QueryTable[0].EntryContext = Service;
2220
2221 QueryTable[1].Name = L"ClassGUID";
2222 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2223 QueryTable[1].EntryContext = &ClassGUID;
2224 QueryTable[1].DefaultType = REG_SZ;
2225 QueryTable[1].DefaultData = &NullString;
2226 QueryTable[1].DefaultLength = 0;
2227
2228 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2229 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2230
2231 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2232 RegKey.Buffer, QueryTable, NULL, NULL);
2233
2234 if (!NT_SUCCESS(Status))
2235 {
2236 DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
2237 /* FIXME: Log the error */
2238 CPRINT("Could not retrieve configuration for device %S (Status %x)\n",
2239 DeviceNode->InstancePath.Buffer, Status);
2240 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2241 return STATUS_SUCCESS;
2242 }
2243
2244 if (Service->Buffer == NULL)
2245 {
2246 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2247
2248 if (ClassGUID.Length != 0)
2249 {
2250 /* Device has a ClassGUID value, but no Service value.
2251 * Suppose it is using the NULL driver, so state the
2252 * device is started */
2253 DPRINT("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2254 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2255 DeviceNode->Flags |= DN_STARTED;
2256 }
2257 return STATUS_SUCCESS;
2258 }
2259
2260 DPRINT("Got Service %S\n", Service->Buffer);
2261 }
2262
2263 return STATUS_SUCCESS;
2264 }
2265
2266 /*
2267 * IopActionInitChildServices
2268 *
2269 * Initialize the service for all (direct) child nodes of a parent node
2270 *
2271 * Parameters
2272 * DeviceNode
2273 * Pointer to device node.
2274 * Context
2275 * Pointer to parent node to initialize child node services for.
2276 * BootDrivers
2277 * Load only driver marked as boot start.
2278 *
2279 * Remarks
2280 * If the driver image for a service is not loaded and initialized
2281 * it is done here too. We only return a status code indicating an
2282 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2283 * not a direct child of the device node for which we initialize
2284 * child services for. Any errors that occur is logged instead so
2285 * that all child services have a chance of being initialized.
2286 */
2287
2288 NTSTATUS
2289 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2290 PVOID Context,
2291 BOOLEAN BootDrivers)
2292 {
2293 PDEVICE_NODE ParentDeviceNode;
2294 NTSTATUS Status;
2295
2296 DPRINT("IopActionInitChildServices(%p, %p, %d)\n", DeviceNode, Context,
2297 BootDrivers);
2298
2299 ParentDeviceNode = (PDEVICE_NODE)Context;
2300
2301 /*
2302 * We are called for the parent too, but we don't need to do special
2303 * handling for this node
2304 */
2305 if (DeviceNode == ParentDeviceNode)
2306 {
2307 DPRINT("Success\n");
2308 return STATUS_SUCCESS;
2309 }
2310
2311 /*
2312 * Make sure this device node is a direct child of the parent device node
2313 * that is given as an argument
2314 */
2315 #if 0
2316 if (DeviceNode->Parent != ParentDeviceNode)
2317 {
2318 /*
2319 * Stop the traversal immediately and indicate unsuccessful operation
2320 */
2321 DPRINT("Stop\n");
2322 return STATUS_UNSUCCESSFUL;
2323 }
2324 #endif
2325
2326 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED) &&
2327 !IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) &&
2328 !IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED))
2329 {
2330 PLDR_DATA_TABLE_ENTRY ModuleObject;
2331 PDRIVER_OBJECT DriverObject;
2332
2333 /* FIXME: Remove this once the bug is fixed */
2334 if (DeviceNode->ServiceName.Buffer == NULL)
2335 DPRINT1("Weird DeviceNode %p having ServiceName->Buffer==NULL. Probable stack corruption or memory overwrite.\n", DeviceNode);
2336
2337 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2338 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2339 {
2340 if (Status != STATUS_IMAGE_ALREADY_LOADED)
2341 {
2342 DeviceNode->Flags |= DN_DRIVER_LOADED;
2343 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2344 &DeviceNode->ServiceName, FALSE, &DriverObject);
2345 }
2346 else
2347 {
2348 /* get existing DriverObject pointer */
2349 Status = IopGetDriverObject(
2350 &DriverObject,
2351 &DeviceNode->ServiceName,
2352 FALSE);
2353 }
2354 if (NT_SUCCESS(Status))
2355 {
2356 /* Attach lower level filter drivers. */
2357 IopAttachFilterDrivers(DeviceNode, TRUE);
2358 /* Initialize the function driver for the device node */
2359 Status = IopInitializeDevice(DeviceNode, DriverObject);
2360 if (NT_SUCCESS(Status))
2361 {
2362 /* Attach upper level filter drivers. */
2363 IopAttachFilterDrivers(DeviceNode, FALSE);
2364 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2365
2366 Status = IopStartDevice(DeviceNode);
2367 }
2368 }
2369 }
2370 else
2371 {
2372 /*
2373 * Don't disable when trying to load only boot drivers
2374 */
2375 if (!BootDrivers)
2376 {
2377 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2378 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2379 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2380 CPRINT("Initialization of service %S failed (Status %x)\n",
2381 DeviceNode->ServiceName.Buffer, Status);
2382 }
2383 }
2384 } else
2385 {
2386 DPRINT("Service %S is disabled or already initialized\n",
2387 DeviceNode->ServiceName.Buffer);
2388 }
2389
2390 return STATUS_SUCCESS;
2391 }
2392
2393 /*
2394 * IopActionInitAllServices
2395 *
2396 * Initialize the service for all (direct) child nodes of a parent node. This
2397 * function just calls IopActionInitChildServices with BootDrivers = FALSE.
2398 */
2399
2400 NTSTATUS
2401 IopActionInitAllServices(PDEVICE_NODE DeviceNode,
2402 PVOID Context)
2403 {
2404 return IopActionInitChildServices(DeviceNode, Context, FALSE);
2405 }
2406
2407 /*
2408 * IopActionInitBootServices
2409 *
2410 * Initialize the boot start services for all (direct) child nodes of a
2411 * parent node. This function just calls IopActionInitChildServices with
2412 * BootDrivers = TRUE.
2413 */
2414 NTSTATUS
2415 IopActionInitBootServices(PDEVICE_NODE DeviceNode,
2416 PVOID Context)
2417 {
2418 return IopActionInitChildServices(DeviceNode, Context, TRUE);
2419 }
2420
2421 /*
2422 * IopInitializePnpServices
2423 *
2424 * Initialize services for discovered children
2425 *
2426 * Parameters
2427 * DeviceNode
2428 * Top device node to start initializing services.
2429 *
2430 * BootDrivers
2431 * When set to TRUE, only drivers marked as boot start will
2432 * be loaded. Otherwise, all drivers will be loaded.
2433 *
2434 * Return Value
2435 * Status
2436 */
2437 NTSTATUS
2438 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode,
2439 IN BOOLEAN BootDrivers)
2440 {
2441 DEVICETREE_TRAVERSE_CONTEXT Context;
2442
2443 DPRINT("IopInitializePnpServices(%p, %d)\n", DeviceNode, BootDrivers);
2444
2445 if (BootDrivers)
2446 {
2447 IopInitDeviceTreeTraverseContext(
2448 &Context,
2449 DeviceNode,
2450 IopActionInitBootServices,
2451 DeviceNode);
2452 }
2453 else
2454 {
2455 IopInitDeviceTreeTraverseContext(
2456 &Context,
2457 DeviceNode,
2458 IopActionInitAllServices,
2459 DeviceNode);
2460 }
2461
2462 return IopTraverseDeviceTree(&Context);
2463 }
2464
2465 /* Invalidate device list enumerated by a device node.
2466 * The call can be make synchronous by defining the Event field
2467 * of the INVALIDATE_DEVICE_RELATION_DATA structure
2468 */
2469 static VOID NTAPI
2470 IopInvalidateDeviceRelations(
2471 IN PDEVICE_OBJECT DeviceObject,
2472 IN PVOID InvalidateContext) /* PINVALIDATE_DEVICE_RELATION_DATA */
2473 {
2474 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
2475 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2476 PKEVENT Event = Data->Event;
2477 DEVICETREE_TRAVERSE_CONTEXT Context;
2478 PDEVICE_RELATIONS DeviceRelations;
2479 IO_STATUS_BLOCK IoStatusBlock;
2480 PDEVICE_NODE ChildDeviceNode;
2481 IO_STACK_LOCATION Stack;
2482 BOOLEAN BootDrivers;
2483 OBJECT_ATTRIBUTES ObjectAttributes;
2484 UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
2485 HANDLE Handle;
2486 NTSTATUS Status;
2487 ULONG i;
2488
2489 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2490
2491 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2492
2493 Stack.Parameters.QueryDeviceRelations.Type = Data->Type;
2494
2495 Status = IopInitiatePnpIrp(
2496 DeviceObject,
2497 &IoStatusBlock,
2498 IRP_MN_QUERY_DEVICE_RELATIONS,
2499 &Stack);
2500 if (!NT_SUCCESS(Status))
2501 {
2502 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2503 goto cleanup;
2504 }
2505
2506 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2507
2508 if (!DeviceRelations || DeviceRelations->Count <= 0)
2509 {
2510 DPRINT("No PDOs\n");
2511 if (DeviceRelations)
2512 {
2513 ExFreePool(DeviceRelations);
2514 }
2515 Status = STATUS_SUCCESS;
2516 goto cleanup;
2517 }
2518
2519 DPRINT("Got %d PDOs\n", DeviceRelations->Count);
2520
2521 /*
2522 * Create device nodes for all discovered devices
2523 */
2524 for (i = 0; i < DeviceRelations->Count; i++)
2525 {
2526 Status = IopCreateDeviceNode(
2527 DeviceNode,
2528 DeviceRelations->Objects[i],
2529 &ChildDeviceNode);
2530 DeviceNode->Flags |= DNF_ENUMERATED;
2531 if (!NT_SUCCESS(Status))
2532 {
2533 DPRINT("No resources\n");
2534 for (i = 0; i < DeviceRelations->Count; i++)
2535 ObDereferenceObject(DeviceRelations->Objects[i]);
2536 ExFreePool(DeviceRelations);
2537 Status = STATUS_NO_MEMORY;
2538 goto cleanup;
2539 }
2540 }
2541 ExFreePool(DeviceRelations);
2542
2543 /*
2544 * Retrieve information about all discovered children from the bus driver
2545 */
2546 IopInitDeviceTreeTraverseContext(
2547 &Context,
2548 DeviceNode,
2549 IopActionInterrogateDeviceStack,
2550 DeviceNode);
2551
2552 Status = IopTraverseDeviceTree(&Context);
2553 if (!NT_SUCCESS(Status))
2554 {
2555 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2556 goto cleanup;
2557 }
2558
2559 /*
2560 * Retrieve configuration from the registry for discovered children
2561 */
2562 IopInitDeviceTreeTraverseContext(
2563 &Context,
2564 DeviceNode,
2565 IopActionConfigureChildServices,
2566 DeviceNode);
2567
2568 Status = IopTraverseDeviceTree(&Context);
2569 if (!NT_SUCCESS(Status))
2570 {
2571 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2572 goto cleanup;
2573 }
2574
2575 /*
2576 * Get the state of the system boot. If the \\SystemRoot link isn't
2577 * created yet, we will assume that it's possible to load only boot
2578 * drivers.
2579 */
2580 InitializeObjectAttributes(
2581 &ObjectAttributes,
2582 &LinkName,
2583 0,
2584 NULL,
2585 NULL);
2586 Status = ZwOpenFile(
2587 &Handle,
2588 FILE_ALL_ACCESS,
2589 &ObjectAttributes,
2590 &IoStatusBlock,
2591 0,
2592 0);
2593 if (NT_SUCCESS(Status))
2594 {
2595 BootDrivers = FALSE;
2596 ZwClose(Handle);
2597 }
2598 else
2599 BootDrivers = TRUE;
2600
2601 /*
2602 * Initialize services for discovered children. Only boot drivers will
2603 * be loaded from boot driver!
2604 */
2605 Status = IopInitializePnpServices(DeviceNode, BootDrivers);
2606 if (!NT_SUCCESS(Status))
2607 {
2608 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2609 goto cleanup;
2610 }
2611
2612 DPRINT("IopInvalidateDeviceRelations() finished\n");
2613 Status = STATUS_SUCCESS;
2614
2615 cleanup:
2616 IoFreeWorkItem(Data->WorkItem);
2617 if (Event)
2618 {
2619 Data->Status = Status;
2620 KeSetEvent(Event, 0, FALSE);
2621 }
2622 else
2623 ExFreePool(Data);
2624 }
2625
2626 static NTSTATUS INIT_FUNCTION
2627 IopEnumerateDetectedDevices(
2628 IN HANDLE hBaseKey,
2629 IN PUNICODE_STRING RelativePath,
2630 IN HANDLE hRootKey,
2631 IN BOOLEAN EnumerateSubKeys,
2632 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2633 IN ULONG ParentBootResourcesLength)
2634 {
2635 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
2636 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
2637 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
2638 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
2639 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
2640 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
2641 OBJECT_ATTRIBUTES ObjectAttributes;
2642 HANDLE hDevicesKey = NULL;
2643 HANDLE hDeviceKey = NULL;
2644 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
2645 UNICODE_STRING Level2NameU;
2646 WCHAR Level2Name[5];
2647 ULONG IndexDevice = 0;
2648 ULONG IndexSubKey;
2649 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
2650 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
2651 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
2652 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
2653 UNICODE_STRING DeviceName, ValueName;
2654 ULONG RequiredSize;
2655 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
2656 ULONG BootResourcesLength;
2657 NTSTATUS Status;
2658
2659 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI BIOS");
2660 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
2661 static ULONG DeviceIndexPci = 0;
2662 /*const UNICODE_STRING IdentifierAcpi = RTL_CONSTANT_STRING(L"ACPI BIOS");
2663 UNICODE_STRING HardwareIdAcpi = RTL_CONSTANT_STRING(L"*PNP0C08\0");
2664 static ULONG DeviceIndexAcpi = 0;*/
2665 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
2666 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
2667 static ULONG DeviceIndexSerial = 0;
2668 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
2669 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
2670 static ULONG DeviceIndexKeyboard = 0;
2671 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
2672 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
2673 static ULONG DeviceIndexMouse = 0;
2674 PUNICODE_STRING pHardwareId;
2675 ULONG DeviceIndex = 0;
2676
2677 InitializeObjectAttributes(&ObjectAttributes, RelativePath, OBJ_KERNEL_HANDLE, hBaseKey, NULL);
2678 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
2679 if (!NT_SUCCESS(Status))
2680 {
2681 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2682 goto cleanup;
2683 }
2684
2685 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2686 if (!pDeviceInformation)
2687 {
2688 DPRINT("ExAllocatePool() failed\n");
2689 Status = STATUS_NO_MEMORY;
2690 goto cleanup;
2691 }
2692
2693 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2694 if (!pValueInformation)
2695 {
2696 DPRINT("ExAllocatePool() failed\n");
2697 Status = STATUS_NO_MEMORY;
2698 goto cleanup;
2699 }
2700
2701 while (TRUE)
2702 {
2703 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2704 if (Status == STATUS_NO_MORE_ENTRIES)
2705 break;
2706 else if (Status == STATUS_BUFFER_OVERFLOW)
2707 {
2708 ExFreePool(pDeviceInformation);
2709 DeviceInfoLength = RequiredSize;
2710 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2711 if (!pDeviceInformation)
2712 {
2713 DPRINT("ExAllocatePool() failed\n");
2714 Status = STATUS_NO_MEMORY;
2715 goto cleanup;
2716 }
2717 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2718 }
2719 if (!NT_SUCCESS(Status))
2720 {
2721 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2722 goto cleanup;
2723 }
2724 IndexDevice++;
2725
2726 /* Open device key */
2727 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2728 DeviceName.Buffer = pDeviceInformation->Name;
2729 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
2730 Status = ZwOpenKey(
2731 &hDeviceKey,
2732 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0),
2733 &ObjectAttributes);
2734 if (!NT_SUCCESS(Status))
2735 {
2736 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
2737 goto cleanup;
2738 }
2739
2740 /* Read boot resources, and add then to parent ones */
2741 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2742 if (Status == STATUS_BUFFER_OVERFLOW)
2743 {
2744 ExFreePool(pValueInformation);
2745 ValueInfoLength = RequiredSize;
2746 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2747 if (!pValueInformation)
2748 {
2749 DPRINT("ExAllocatePool() failed\n");
2750 ZwDeleteKey(hLevel2Key);
2751 Status = STATUS_NO_MEMORY;
2752 goto cleanup;
2753 }
2754 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2755 }
2756 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2757 {
2758 BootResources = ParentBootResources;
2759 BootResourcesLength = ParentBootResourcesLength;
2760 }
2761 else if (!NT_SUCCESS(Status))
2762 {
2763 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2764 goto nextdevice;
2765 }
2766 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
2767 {
2768 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
2769 goto nextdevice;
2770 }
2771 else if (((PCM_FULL_RESOURCE_DESCRIPTOR)pValueInformation->Data)->PartialResourceList.Count == 0)
2772 {
2773 BootResources = ParentBootResources;
2774 BootResourcesLength = ParentBootResourcesLength;
2775 }
2776 else
2777 {
2778 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
2779
2780 /* Concatenate current resources and parent ones */
2781 if (ParentBootResourcesLength == 0)
2782 BootResourcesLength = pValueInformation->DataLength;
2783 else
2784 BootResourcesLength = ParentBootResourcesLength
2785 + pValueInformation->DataLength
2786 - Header;
2787 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
2788 if (!BootResources)
2789 {
2790 DPRINT("ExAllocatePool() failed\n");
2791 goto nextdevice;
2792 }
2793 if (ParentBootResourcesLength == 0)
2794 {
2795 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2796 }
2797 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
2798 {
2799 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
2800 RtlCopyMemory(
2801 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
2802 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2803 ParentBootResourcesLength - Header);
2804 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2805 }
2806 else
2807 {
2808 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
2809 RtlCopyMemory(
2810 (PVOID)((ULONG_PTR)BootResources + Header),
2811 (PVOID)((ULONG_PTR)ParentBootResources + Header),
2812 ParentBootResourcesLength - Header);
2813 RtlCopyMemory(
2814 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
2815 pValueInformation->Data + Header,
2816 pValueInformation->DataLength - Header);
2817 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
2818 }
2819 }
2820
2821 if (EnumerateSubKeys)
2822 {
2823 IndexSubKey = 0;
2824 while (TRUE)
2825 {
2826 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2827 if (Status == STATUS_NO_MORE_ENTRIES)
2828 break;
2829 else if (Status == STATUS_BUFFER_OVERFLOW)
2830 {
2831 ExFreePool(pDeviceInformation);
2832 DeviceInfoLength = RequiredSize;
2833 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
2834 if (!pDeviceInformation)
2835 {
2836 DPRINT("ExAllocatePool() failed\n");
2837 Status = STATUS_NO_MEMORY;
2838 goto cleanup;
2839 }
2840 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
2841 }
2842 if (!NT_SUCCESS(Status))
2843 {
2844 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
2845 goto cleanup;
2846 }
2847 IndexSubKey++;
2848 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
2849 DeviceName.Buffer = pDeviceInformation->Name;
2850
2851 Status = IopEnumerateDetectedDevices(
2852 hDeviceKey,
2853 &DeviceName,
2854 hRootKey,
2855 TRUE,
2856 BootResources,
2857 BootResourcesLength);
2858 if (!NT_SUCCESS(Status))
2859 goto cleanup;
2860 }
2861 }
2862
2863 /* Read identifier */
2864 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2865 if (Status == STATUS_BUFFER_OVERFLOW)
2866 {
2867 ExFreePool(pValueInformation);
2868 ValueInfoLength = RequiredSize;
2869 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
2870 if (!pValueInformation)
2871 {
2872 DPRINT("ExAllocatePool() failed\n");
2873 Status = STATUS_NO_MEMORY;
2874 goto cleanup;
2875 }
2876 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
2877 }
2878 if (!NT_SUCCESS(Status))
2879 {
2880 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2881 {
2882 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
2883 goto nextdevice;
2884 }
2885 }
2886 else if (pValueInformation->Type != REG_SZ)
2887 {
2888 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
2889 goto nextdevice;
2890 }
2891 else
2892 {
2893 /* Assign hardware id to this device */
2894 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
2895 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
2896 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
2897 ValueName.Length -= sizeof(WCHAR);
2898 }
2899
2900 if (RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
2901 {
2902 pHardwareId = &HardwareIdSerial;
2903 DeviceIndex = DeviceIndexSerial++;
2904 }
2905 else if (RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
2906 {
2907 pHardwareId = &HardwareIdKeyboard;
2908 DeviceIndex = DeviceIndexKeyboard++;
2909 }
2910 else if (RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
2911 {
2912 pHardwareId = &HardwareIdMouse;
2913 DeviceIndex = DeviceIndexMouse++;
2914 }
2915 else if (NT_SUCCESS(Status))
2916 {
2917 /* Try to also match the device identifier */
2918 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
2919 {
2920 pHardwareId = &HardwareIdPci;
2921 DeviceIndex = DeviceIndexPci++;
2922 }
2923 /*else if (RtlCompareUnicodeString(&ValueName, &IdentifierAcpi, FALSE) == 0)
2924 {
2925 pHardwareId = &HardwareIdAcpi;
2926 DeviceIndex = DeviceIndexAcpi++;
2927 }*/
2928 else
2929 {
2930 /* Unknown device */
2931 DPRINT("Unknown device '%wZ'\n", &ValueName);
2932 goto nextdevice;
2933 }
2934 }
2935 else
2936 {
2937 /* Unknown key path */
2938 DPRINT("Unknown key path %wZ\n", RelativePath);
2939 goto nextdevice;
2940 }
2941
2942 /* Add the detected device to Root key */
2943 InitializeObjectAttributes(&ObjectAttributes, pHardwareId, OBJ_KERNEL_HANDLE, hRootKey, NULL);
2944 Status = ZwCreateKey(
2945 &hLevel1Key,
2946 KEY_CREATE_SUB_KEY,
2947 &ObjectAttributes,
2948 0,
2949 NULL,
2950 REG_OPTION_NON_VOLATILE,
2951 NULL);
2952 if (!NT_SUCCESS(Status))
2953 {
2954 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2955 goto nextdevice;
2956 }
2957 swprintf(Level2Name, L"%04lu", DeviceIndex);
2958 RtlInitUnicodeString(&Level2NameU, Level2Name);
2959 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
2960 Status = ZwCreateKey(
2961 &hLevel2Key,
2962 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
2963 &ObjectAttributes,
2964 0,
2965 NULL,
2966 REG_OPTION_NON_VOLATILE,
2967 NULL);
2968 ZwClose(hLevel1Key);
2969 if (!NT_SUCCESS(Status))
2970 {
2971 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
2972 goto nextdevice;
2973 }
2974 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, pHardwareId);
2975 Status = ZwSetValueKey(hLevel2Key, &DeviceDescU, 0, REG_SZ, ValueName.Buffer, ValueName.MaximumLength);
2976 if (!NT_SUCCESS(Status))
2977 {
2978 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2979 ZwDeleteKey(hLevel2Key);
2980 goto nextdevice;
2981 }
2982 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
2983 if (!NT_SUCCESS(Status))
2984 {
2985 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
2986 ZwDeleteKey(hLevel2Key);
2987 goto nextdevice;
2988 }
2989 if (BootResourcesLength > 0)
2990 {
2991 /* Save boot resources to 'LogConf\BootConfig' */
2992 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
2993 Status = ZwCreateKey(
2994 &hLogConf,
2995 KEY_SET_VALUE,
2996 &ObjectAttributes,
2997 0,
2998 NULL,
2999 REG_OPTION_VOLATILE,
3000 NULL);
3001 if (!NT_SUCCESS(Status))
3002 {
3003 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3004 ZwDeleteKey(hLevel2Key);
3005 goto nextdevice;
3006 }
3007 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_FULL_RESOURCE_DESCRIPTOR, BootResources, BootResourcesLength);
3008 ZwClose(hLogConf);
3009 if (!NT_SUCCESS(Status))
3010 {
3011 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3012 ZwDeleteKey(hLevel2Key);
3013 goto nextdevice;
3014 }
3015 }
3016
3017 nextdevice:
3018 if (BootResources && BootResources != ParentBootResources)
3019 ExFreePool(BootResources);
3020 if (hLevel2Key)
3021 {
3022 ZwClose(hLevel2Key);
3023 hLevel2Key = NULL;
3024 }
3025 if (hDeviceKey)
3026 {
3027 ZwClose(hDeviceKey);
3028 hDeviceKey = NULL;
3029 }
3030 }
3031
3032 Status = STATUS_SUCCESS;
3033
3034 cleanup:
3035 if (hDevicesKey)
3036 ZwClose(hDevicesKey);
3037 if (hDeviceKey)
3038 ZwClose(hDeviceKey);
3039 if (pDeviceInformation)
3040 ExFreePool(pDeviceInformation);
3041 if (pValueInformation)
3042 ExFreePool(pValueInformation);
3043 return Status;
3044 }
3045
3046 static BOOLEAN INIT_FUNCTION
3047 IopIsAcpiComputer(VOID)
3048 {
3049 return FALSE;
3050 #if 0
3051 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3052 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3053 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
3054 OBJECT_ATTRIBUTES ObjectAttributes;
3055 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3056 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3057 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3058 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3059 ULONG RequiredSize;
3060 ULONG IndexDevice = 0;
3061 UNICODE_STRING DeviceName, ValueName;
3062 HANDLE hDevicesKey = NULL;
3063 HANDLE hDeviceKey = NULL;
3064 NTSTATUS Status;
3065 BOOLEAN ret = FALSE;
3066
3067 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
3068 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
3069 if (!NT_SUCCESS(Status))
3070 {
3071 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3072 goto cleanup;
3073 }
3074
3075 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3076 if (!pDeviceInformation)
3077 {
3078 DPRINT("ExAllocatePool() failed\n");
3079 Status = STATUS_NO_MEMORY;
3080 goto cleanup;
3081 }
3082
3083 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3084 if (!pDeviceInformation)
3085 {
3086 DPRINT("ExAllocatePool() failed\n");
3087 Status = STATUS_NO_MEMORY;
3088 goto cleanup;
3089 }
3090
3091 while (TRUE)
3092 {
3093 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3094 if (Status == STATUS_NO_MORE_ENTRIES)
3095 break;
3096 else if (Status == STATUS_BUFFER_OVERFLOW)
3097 {
3098 ExFreePool(pDeviceInformation);
3099 DeviceInfoLength = RequiredSize;
3100 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3101 if (!pDeviceInformation)
3102 {
3103 DPRINT("ExAllocatePool() failed\n");
3104 Status = STATUS_NO_MEMORY;
3105 goto cleanup;
3106 }
3107 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3108 }
3109 if (!NT_SUCCESS(Status))
3110 {
3111 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3112 goto cleanup;
3113 }
3114 IndexDevice++;
3115
3116 /* Open device key */
3117 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
3118 DeviceName.Buffer = pDeviceInformation->Name;
3119 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
3120 Status = ZwOpenKey(
3121 &hDeviceKey,
3122 KEY_QUERY_VALUE,
3123 &ObjectAttributes);
3124 if (!NT_SUCCESS(Status))
3125 {
3126 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3127 goto cleanup;
3128 }
3129
3130 /* Read identifier */
3131 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3132 if (Status == STATUS_BUFFER_OVERFLOW)
3133 {
3134 ExFreePool(pValueInformation);
3135 ValueInfoLength = RequiredSize;
3136 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3137 if (!pValueInformation)
3138 {
3139 DPRINT("ExAllocatePool() failed\n");
3140 Status = STATUS_NO_MEMORY;
3141 goto cleanup;
3142 }
3143 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3144 }
3145 if (!NT_SUCCESS(Status))
3146 {
3147 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3148 goto nextdevice;
3149 }
3150 else if (pValueInformation->Type != REG_SZ)
3151 {
3152 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3153 goto nextdevice;
3154 }
3155
3156 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
3157 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3158 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3159 ValueName.Length -= sizeof(WCHAR);
3160 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
3161 {
3162 DPRINT("Found ACPI BIOS\n");
3163 ret = TRUE;
3164 goto cleanup;
3165 }
3166
3167 nextdevice:
3168 ZwClose(hDeviceKey);
3169 hDeviceKey = NULL;
3170 }
3171
3172 cleanup:
3173 if (pDeviceInformation)
3174 ExFreePool(pDeviceInformation);
3175 if (pValueInformation)
3176 ExFreePool(pValueInformation);
3177 if (hDevicesKey)
3178 ZwClose(hDevicesKey);
3179 if (hDeviceKey)
3180 ZwClose(hDeviceKey);
3181 return ret;
3182 #endif
3183 }
3184
3185 static NTSTATUS INIT_FUNCTION
3186 IopUpdateRootKey(VOID)
3187 {
3188 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum\\Root");
3189 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3190 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
3191 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3192 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
3193 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
3194 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
3195 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
3196 OBJECT_ATTRIBUTES ObjectAttributes;
3197 HANDLE hRoot, hHalAcpiDevice, hHalAcpiId;
3198 NTSTATUS Status;
3199
3200 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE, NULL, NULL);
3201 Status = ZwOpenKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes);
3202 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3203 {
3204 /* We are probably in 1st stage */
3205 return STATUS_SUCCESS;
3206 }
3207 else if (!NT_SUCCESS(Status))
3208 {
3209 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3210 return Status;
3211 }
3212
3213 if (IopIsAcpiComputer())
3214 {
3215 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE, hRoot, NULL);
3216 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3217 ZwClose(hRoot);
3218 if (!NT_SUCCESS(Status))
3219 return Status;
3220 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE, hHalAcpiDevice, NULL);
3221 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3222 ZwClose(hHalAcpiDevice);
3223 if (!NT_SUCCESS(Status))
3224 return Status;
3225 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
3226 if (NT_SUCCESS(Status))
3227 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
3228 ZwClose(hHalAcpiId);
3229 return Status;
3230 }
3231 else
3232 {
3233 Status = IopEnumerateDetectedDevices(
3234 NULL,
3235 &MultiKeyPathU,
3236 hRoot,
3237 TRUE,
3238 NULL,
3239 0);
3240 ZwClose(hRoot);
3241 return Status;
3242 }
3243 }
3244
3245 VOID INIT_FUNCTION
3246 PnpInit(VOID)
3247 {
3248 PDEVICE_OBJECT Pdo;
3249 NTSTATUS Status;
3250
3251 DPRINT("PnpInit()\n");
3252
3253 KeInitializeSpinLock(&IopDeviceTreeLock);
3254
3255 /* Initialize the Bus Type GUID List */
3256 IopBusTypeGuidList = ExAllocatePool(PagedPool, sizeof(IO_BUS_TYPE_GUID_LIST));
3257 RtlZeroMemory(IopBusTypeGuidList, sizeof(IO_BUS_TYPE_GUID_LIST));
3258 ExInitializeFastMutex(&IopBusTypeGuidList->Lock);
3259
3260 /* Initialize PnP-Event notification support */
3261 Status = IopInitPlugPlayEvents();
3262 if (!NT_SUCCESS(Status))
3263 {
3264 CPRINT("IopInitPlugPlayEvents() failed\n");
3265 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3266 }
3267
3268 /*
3269 * Create root device node
3270 */
3271
3272 Status = IopCreateDriverObject(&IopRootDriverObject, NULL, 0, FALSE, NULL, 0);
3273 if (!NT_SUCCESS(Status))
3274 {
3275 CPRINT("IoCreateDriverObject() failed\n");
3276 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3277 }
3278
3279 Status = IoCreateDevice(IopRootDriverObject, 0, NULL, FILE_DEVICE_CONTROLLER,
3280 0, FALSE, &Pdo);
3281 if (!NT_SUCCESS(Status))
3282 {
3283 CPRINT("IoCreateDevice() failed\n");
3284 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3285 }
3286
3287 Status = IopCreateDeviceNode(NULL, Pdo, &IopRootDeviceNode);
3288 if (!NT_SUCCESS(Status))
3289 {
3290 CPRINT("Insufficient resources\n");
3291 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3292 }
3293
3294 if (!RtlCreateUnicodeString(&IopRootDeviceNode->InstancePath,
3295 L"HTREE\\ROOT\\0"))
3296 {
3297 CPRINT("Failed to create the instance path!\n");
3298 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, STATUS_NO_MEMORY, 0, 0, 0);
3299 }
3300
3301 /* Report the device to the user-mode pnp manager */
3302 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
3303 &IopRootDeviceNode->InstancePath);
3304
3305 IopRootDeviceNode->PhysicalDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
3306 PnpRootDriverEntry(IopRootDriverObject, NULL);
3307 IopRootDriverObject->DriverExtension->AddDevice(
3308 IopRootDriverObject,
3309 IopRootDeviceNode->PhysicalDeviceObject);
3310
3311 /* Move information about devices detected by Freeloader to SYSTEM\CurrentControlSet\Root\ */
3312 Status = IopUpdateRootKey();
3313 if (!NT_SUCCESS(Status))
3314 {
3315 CPRINT("IopUpdateRootKey() failed\n");
3316 KEBUGCHECKEX(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
3317 }
3318 }
3319
3320
3321 /* EOF */