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