439795c603a8651f53eb26ed80f61b89e789b8bb
[reactos.git] / reactos / ntoskrnl / io / pnpmgr / pnpmgr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpmgr.c
5 * PURPOSE: Initializes the PnP manager
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2007 Hervé Poussineau (hpoussin@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 //#define ENABLE_ACPI
17
18 /* GLOBALS *******************************************************************/
19
20 PDEVICE_NODE IopRootDeviceNode;
21 KSPIN_LOCK IopDeviceTreeLock;
22 ERESOURCE PpRegistryDeviceResource;
23 KGUARDED_MUTEX PpDeviceReferenceTableLock;
24 RTL_AVL_TABLE PpDeviceReferenceTable;
25
26 extern ULONG ExpInitializationPhase;
27 extern BOOLEAN PnpSystemInit;
28
29 /* DATA **********************************************************************/
30
31 PDRIVER_OBJECT IopRootDriverObject;
32 PIO_BUS_TYPE_GUID_LIST PnpBusTypeGuidList = NULL;
33
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, PnpInit)
36 #pragma alloc_text(INIT, PnpInit2)
37 #endif
38
39 typedef struct _INVALIDATE_DEVICE_RELATION_DATA
40 {
41 PDEVICE_OBJECT DeviceObject;
42 DEVICE_RELATION_TYPE Type;
43 PIO_WORKITEM WorkItem;
44 } INVALIDATE_DEVICE_RELATION_DATA, *PINVALIDATE_DEVICE_RELATION_DATA;
45
46 /* FUNCTIONS *****************************************************************/
47
48 NTSTATUS
49 IopAssignDeviceResources(
50 IN PDEVICE_NODE DeviceNode,
51 OUT ULONG *pRequiredSize);
52
53 NTSTATUS
54 IopTranslateDeviceResources(
55 IN PDEVICE_NODE DeviceNode,
56 IN ULONG RequiredSize);
57
58 NTSTATUS
59 IopUpdateResourceMapForPnPDevice(
60 IN PDEVICE_NODE DeviceNode);
61
62 NTSTATUS
63 NTAPI
64 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
65 IN ULONG CreateOptions,
66 OUT PHANDLE Handle);
67
68 PDEVICE_NODE
69 FASTCALL
70 IopGetDeviceNode(PDEVICE_OBJECT DeviceObject)
71 {
72 return ((PEXTENDED_DEVOBJ_EXTENSION)DeviceObject->DeviceObjectExtension)->DeviceNode;
73 }
74
75 NTSTATUS
76 FASTCALL
77 IopInitializeDevice(PDEVICE_NODE DeviceNode,
78 PDRIVER_OBJECT DriverObject)
79 {
80 PDEVICE_OBJECT Fdo;
81 NTSTATUS Status;
82
83 if (!DriverObject->DriverExtension->AddDevice)
84 return STATUS_SUCCESS;
85
86 /* This is a Plug and Play driver */
87 DPRINT("Plug and Play driver found\n");
88 ASSERT(DeviceNode->PhysicalDeviceObject);
89
90 /* Check if this plug-and-play driver is used as a legacy one for this device node */
91 if (IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
92 {
93 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
94 return STATUS_SUCCESS;
95 }
96
97 DPRINT("Calling %wZ->AddDevice(%wZ)\n",
98 &DriverObject->DriverName,
99 &DeviceNode->InstancePath);
100 Status = DriverObject->DriverExtension->AddDevice(
101 DriverObject, DeviceNode->PhysicalDeviceObject);
102 if (!NT_SUCCESS(Status))
103 {
104 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
105 return Status;
106 }
107
108 /* Check if driver added a FDO above the PDO */
109 Fdo = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject);
110 if (Fdo == DeviceNode->PhysicalDeviceObject)
111 {
112 /* FIXME: What do we do? Unload the driver or just disable the device? */
113 DPRINT1("An FDO was not attached\n");
114 ObDereferenceObject(Fdo);
115 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
116 return STATUS_UNSUCCESSFUL;
117 }
118
119 /* Check if we have a ACPI device (needed for power management) */
120 if (Fdo->DeviceType == FILE_DEVICE_ACPI)
121 {
122 static BOOLEAN SystemPowerDeviceNodeCreated = FALSE;
123
124 /* There can be only one system power device */
125 if (!SystemPowerDeviceNodeCreated)
126 {
127 PopSystemPowerDeviceNode = DeviceNode;
128 ObReferenceObject(PopSystemPowerDeviceNode);
129 SystemPowerDeviceNodeCreated = TRUE;
130 }
131 }
132
133 ObDereferenceObject(Fdo);
134
135 IopDeviceNodeSetFlag(DeviceNode, DNF_ADDED);
136 IopDeviceNodeSetFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
137
138 return STATUS_SUCCESS;
139 }
140
141 NTSTATUS
142 IopStartDevice(
143 PDEVICE_NODE DeviceNode)
144 {
145 IO_STATUS_BLOCK IoStatusBlock;
146 IO_STACK_LOCATION Stack;
147 ULONG RequiredLength;
148 NTSTATUS Status;
149 HANDLE InstanceHandle = INVALID_HANDLE_VALUE, ControlHandle = INVALID_HANDLE_VALUE;
150 UNICODE_STRING KeyName;
151 OBJECT_ATTRIBUTES ObjectAttributes;
152
153 IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
154 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
155 Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
156 Status = IopInitiatePnpIrp(
157 DeviceNode->PhysicalDeviceObject,
158 &IoStatusBlock,
159 IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
160 &Stack);
161 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
162 {
163 DPRINT("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
164 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
165 return Status;
166 }
167 else if (NT_SUCCESS(Status))
168 {
169 DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
170 }
171
172 Status = IopAssignDeviceResources(DeviceNode, &RequiredLength);
173 if (NT_SUCCESS(Status))
174 {
175 Status = IopTranslateDeviceResources(DeviceNode, RequiredLength);
176 if (NT_SUCCESS(Status))
177 {
178 Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
179 if (!NT_SUCCESS(Status))
180 {
181 DPRINT("IopUpdateResourceMap() failed (Status 0x%08lx)\n", Status);
182 }
183 }
184 else
185 {
186 DPRINT("IopTranslateDeviceResources() failed (Status 0x%08lx)\n", Status);
187 }
188 }
189 else
190 {
191 DPRINT("IopAssignDeviceResources() failed (Status 0x%08lx)\n", Status);
192 }
193 IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
194
195 if (!NT_SUCCESS(Status))
196 goto ByeBye;
197
198 DPRINT("Sending IRP_MN_START_DEVICE to driver\n");
199 Stack.Parameters.StartDevice.AllocatedResources = DeviceNode->ResourceList;
200 Stack.Parameters.StartDevice.AllocatedResourcesTranslated = DeviceNode->ResourceListTranslated;
201
202 /*
203 * Windows NT Drivers receive IRP_MN_START_DEVICE in a critical region and
204 * actually _depend_ on this!. This is because NT will lock the Device Node
205 * with an ERESOURCE, which of course requires APCs to be disabled.
206 */
207 KeEnterCriticalRegion();
208
209 Status = IopInitiatePnpIrp(
210 DeviceNode->PhysicalDeviceObject,
211 &IoStatusBlock,
212 IRP_MN_START_DEVICE,
213 &Stack);
214
215 KeLeaveCriticalRegion();
216
217 if (!NT_SUCCESS(Status))
218 {
219 DPRINT1("IRP_MN_START_DEVICE failed for %wZ\n", &DeviceNode->InstancePath);
220 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
221 goto ByeBye;
222 }
223 else
224 {
225 if (IopDeviceNodeHasFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY))
226 {
227 DPRINT("Device needs enumeration, invalidating bus relations\n");
228 /* Invalidate device relations synchronously
229 (otherwise there will be dirty read of DeviceNode) */
230 IopEnumerateDevice(DeviceNode->PhysicalDeviceObject);
231 IopDeviceNodeClearFlag(DeviceNode, DNF_NEED_ENUMERATION_ONLY);
232 }
233 }
234
235 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceHandle);
236 if (!NT_SUCCESS(Status))
237 goto ByeBye;
238
239 RtlInitUnicodeString(&KeyName, L"Control");
240 InitializeObjectAttributes(&ObjectAttributes,
241 &KeyName,
242 OBJ_CASE_INSENSITIVE,
243 InstanceHandle,
244 NULL);
245 Status = ZwCreateKey(&ControlHandle, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
246 if (!NT_SUCCESS(Status))
247 goto ByeBye;
248
249 RtlInitUnicodeString(&KeyName, L"ActiveService");
250 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_SZ, DeviceNode->ServiceName.Buffer, DeviceNode->ServiceName.Length);
251
252 if (NT_SUCCESS(Status) && DeviceNode->ResourceList)
253 {
254 RtlInitUnicodeString(&KeyName, L"AllocConfig");
255 Status = ZwSetValueKey(ControlHandle, &KeyName, 0, REG_RESOURCE_LIST,
256 DeviceNode->ResourceList, CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
257 }
258
259 ByeBye:
260 if (NT_SUCCESS(Status))
261 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
262 else
263 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
264
265 if (ControlHandle != INVALID_HANDLE_VALUE)
266 ZwClose(ControlHandle);
267
268 if (InstanceHandle != INVALID_HANDLE_VALUE)
269 ZwClose(InstanceHandle);
270
271 return Status;
272 }
273
274 NTSTATUS
275 NTAPI
276 IopQueryDeviceCapabilities(PDEVICE_NODE DeviceNode,
277 PDEVICE_CAPABILITIES DeviceCaps)
278 {
279 IO_STATUS_BLOCK StatusBlock;
280 IO_STACK_LOCATION Stack;
281
282 /* Set up the Header */
283 RtlZeroMemory(DeviceCaps, sizeof(DEVICE_CAPABILITIES));
284 DeviceCaps->Size = sizeof(DEVICE_CAPABILITIES);
285 DeviceCaps->Version = 1;
286 DeviceCaps->Address = -1;
287 DeviceCaps->UINumber = -1;
288
289 /* Set up the Stack */
290 RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
291 Stack.Parameters.DeviceCapabilities.Capabilities = DeviceCaps;
292
293 /* Send the IRP */
294 return IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
295 &StatusBlock,
296 IRP_MN_QUERY_CAPABILITIES,
297 &Stack);
298 }
299
300 static VOID NTAPI
301 IopAsynchronousInvalidateDeviceRelations(
302 IN PDEVICE_OBJECT DeviceObject,
303 IN PVOID InvalidateContext)
304 {
305 PINVALIDATE_DEVICE_RELATION_DATA Data = InvalidateContext;
306
307 IoSynchronousInvalidateDeviceRelations(
308 Data->DeviceObject,
309 Data->Type);
310
311 ObDereferenceObject(Data->DeviceObject);
312 IoFreeWorkItem(Data->WorkItem);
313 ExFreePool(Data);
314 }
315
316 NTSTATUS
317 IopGetSystemPowerDeviceObject(PDEVICE_OBJECT *DeviceObject)
318 {
319 KIRQL OldIrql;
320
321 if (PopSystemPowerDeviceNode)
322 {
323 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
324 *DeviceObject = PopSystemPowerDeviceNode->PhysicalDeviceObject;
325 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
326
327 return STATUS_SUCCESS;
328 }
329
330 return STATUS_UNSUCCESSFUL;
331 }
332
333 USHORT
334 NTAPI
335 IopGetBusTypeGuidIndex(LPGUID BusTypeGuid)
336 {
337 USHORT i = 0, FoundIndex = 0xFFFF;
338 ULONG NewSize;
339 PVOID NewList;
340
341 /* Acquire the lock */
342 ExAcquireFastMutex(&PnpBusTypeGuidList->Lock);
343
344 /* Loop all entries */
345 while (i < PnpBusTypeGuidList->GuidCount)
346 {
347 /* Try to find a match */
348 if (RtlCompareMemory(BusTypeGuid,
349 &PnpBusTypeGuidList->Guids[i],
350 sizeof(GUID)) == sizeof(GUID))
351 {
352 /* Found it */
353 FoundIndex = i;
354 goto Quickie;
355 }
356 i++;
357 }
358
359 /* Check if we have to grow the list */
360 if (PnpBusTypeGuidList->GuidCount)
361 {
362 /* Calculate the new size */
363 NewSize = sizeof(IO_BUS_TYPE_GUID_LIST) +
364 (sizeof(GUID) * PnpBusTypeGuidList->GuidCount);
365
366 /* Allocate the new copy */
367 NewList = ExAllocatePool(PagedPool, NewSize);
368
369 if (!NewList) {
370 /* Fail */
371 ExFreePool(PnpBusTypeGuidList);
372 goto Quickie;
373 }
374
375 /* Now copy them, decrease the size too */
376 NewSize -= sizeof(GUID);
377 RtlCopyMemory(NewList, PnpBusTypeGuidList, NewSize);
378
379 /* Free the old list */
380 ExFreePool(PnpBusTypeGuidList);
381
382 /* Use the new buffer */
383 PnpBusTypeGuidList = NewList;
384 }
385
386 /* Copy the new GUID */
387 RtlCopyMemory(&PnpBusTypeGuidList->Guids[PnpBusTypeGuidList->GuidCount],
388 BusTypeGuid,
389 sizeof(GUID));
390
391 /* The new entry is the index */
392 FoundIndex = (USHORT)PnpBusTypeGuidList->GuidCount;
393 PnpBusTypeGuidList->GuidCount++;
394
395 Quickie:
396 ExReleaseFastMutex(&PnpBusTypeGuidList->Lock);
397 return FoundIndex;
398 }
399
400 /*
401 * DESCRIPTION
402 * Creates a device node
403 *
404 * ARGUMENTS
405 * ParentNode = Pointer to parent device node
406 * PhysicalDeviceObject = Pointer to PDO for device object. Pass NULL
407 * to have the root device node create one
408 * (eg. for legacy drivers)
409 * DeviceNode = Pointer to storage for created device node
410 *
411 * RETURN VALUE
412 * Status
413 */
414 NTSTATUS
415 IopCreateDeviceNode(PDEVICE_NODE ParentNode,
416 PDEVICE_OBJECT PhysicalDeviceObject,
417 PUNICODE_STRING ServiceName,
418 PDEVICE_NODE *DeviceNode)
419 {
420 PDEVICE_NODE Node;
421 NTSTATUS Status;
422 KIRQL OldIrql;
423 UNICODE_STRING FullServiceName;
424 UNICODE_STRING LegacyPrefix = RTL_CONSTANT_STRING(L"LEGACY_");
425 UNICODE_STRING UnknownDeviceName = RTL_CONSTANT_STRING(L"UNKNOWN");
426 UNICODE_STRING KeyName, ClassName, ClassGUID;
427 PUNICODE_STRING ServiceName1;
428 ULONG LegacyValue;
429 HANDLE InstanceHandle;
430
431 DPRINT("ParentNode 0x%p PhysicalDeviceObject 0x%p ServiceName %wZ\n",
432 ParentNode, PhysicalDeviceObject, ServiceName);
433
434 Node = (PDEVICE_NODE)ExAllocatePool(NonPagedPool, sizeof(DEVICE_NODE));
435 if (!Node)
436 {
437 return STATUS_INSUFFICIENT_RESOURCES;
438 }
439
440 RtlZeroMemory(Node, sizeof(DEVICE_NODE));
441
442 if (!ServiceName)
443 ServiceName1 = &UnknownDeviceName;
444 else
445 ServiceName1 = ServiceName;
446
447 if (!PhysicalDeviceObject)
448 {
449 FullServiceName.MaximumLength = LegacyPrefix.Length + ServiceName1->Length;
450 FullServiceName.Length = 0;
451 FullServiceName.Buffer = ExAllocatePool(PagedPool, FullServiceName.MaximumLength);
452 if (!FullServiceName.Buffer)
453 {
454 ExFreePool(Node);
455 return STATUS_INSUFFICIENT_RESOURCES;
456 }
457
458 RtlAppendUnicodeStringToString(&FullServiceName, &LegacyPrefix);
459 RtlAppendUnicodeStringToString(&FullServiceName, ServiceName1);
460
461 Status = PnpRootCreateDevice(&FullServiceName, &PhysicalDeviceObject, &Node->InstancePath);
462 if (!NT_SUCCESS(Status))
463 {
464 DPRINT1("PnpRootCreateDevice() failed with status 0x%08X\n", Status);
465 ExFreePool(Node);
466 return Status;
467 }
468
469 /* Create the device key for legacy drivers */
470 Status = IopCreateDeviceKeyPath(&Node->InstancePath, REG_OPTION_VOLATILE, &InstanceHandle);
471 if (!NT_SUCCESS(Status))
472 {
473 ZwClose(InstanceHandle);
474 ExFreePool(Node);
475 ExFreePool(FullServiceName.Buffer);
476 return Status;
477 }
478
479 Node->ServiceName.Buffer = ExAllocatePool(PagedPool, ServiceName1->Length);
480 if (!Node->ServiceName.Buffer)
481 {
482 ZwClose(InstanceHandle);
483 ExFreePool(Node);
484 ExFreePool(FullServiceName.Buffer);
485 return Status;
486 }
487
488 Node->ServiceName.MaximumLength = ServiceName1->Length;
489 Node->ServiceName.Length = 0;
490
491 RtlAppendUnicodeStringToString(&Node->ServiceName, ServiceName1);
492
493 if (ServiceName)
494 {
495 RtlInitUnicodeString(&KeyName, L"Service");
496 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ServiceName->Buffer, ServiceName->Length);
497 }
498
499 if (NT_SUCCESS(Status))
500 {
501 RtlInitUnicodeString(&KeyName, L"Legacy");
502
503 LegacyValue = 1;
504 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_DWORD, &LegacyValue, sizeof(LegacyValue));
505 if (NT_SUCCESS(Status))
506 {
507 RtlInitUnicodeString(&KeyName, L"Class");
508
509 RtlInitUnicodeString(&ClassName, L"LegacyDriver");
510 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassName.Buffer, ClassName.Length);
511 if (NT_SUCCESS(Status))
512 {
513 RtlInitUnicodeString(&KeyName, L"ClassGUID");
514
515 RtlInitUnicodeString(&ClassGUID, L"{8ECC055D-047F-11D1-A537-0000F8753ED1}");
516 Status = ZwSetValueKey(InstanceHandle, &KeyName, 0, REG_SZ, ClassGUID.Buffer, ClassGUID.Length);
517 }
518 }
519 }
520
521 ZwClose(InstanceHandle);
522 ExFreePool(FullServiceName.Buffer);
523
524 if (!NT_SUCCESS(Status))
525 {
526 ExFreePool(Node);
527 return Status;
528 }
529
530 /* This is for drivers passed on the command line to ntoskrnl.exe */
531 IopDeviceNodeSetFlag(Node, DNF_LEGACY_DRIVER);
532 }
533
534 Node->PhysicalDeviceObject = PhysicalDeviceObject;
535
536 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = Node;
537
538 if (ParentNode)
539 {
540 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
541 Node->Parent = ParentNode;
542 Node->Sibling = ParentNode->Child;
543 ParentNode->Child = Node;
544 if (ParentNode->LastChild == NULL)
545 ParentNode->LastChild = Node;
546 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
547 Node->Level = ParentNode->Level + 1;
548 }
549
550 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
551
552 *DeviceNode = Node;
553
554 return STATUS_SUCCESS;
555 }
556
557 NTSTATUS
558 IopFreeDeviceNode(PDEVICE_NODE DeviceNode)
559 {
560 KIRQL OldIrql;
561 PDEVICE_NODE PrevSibling = NULL;
562
563 /* All children must be deleted before a parent is deleted */
564 ASSERT(!DeviceNode->Child);
565
566 KeAcquireSpinLock(&IopDeviceTreeLock, &OldIrql);
567
568 ASSERT(DeviceNode->PhysicalDeviceObject);
569
570 ObDereferenceObject(DeviceNode->PhysicalDeviceObject);
571
572 /* Get previous sibling */
573 if (DeviceNode->Parent && DeviceNode->Parent->Child != DeviceNode)
574 {
575 PrevSibling = DeviceNode->Parent->Child;
576 while (PrevSibling->Sibling != DeviceNode)
577 PrevSibling = PrevSibling->Sibling;
578 }
579
580 /* Unlink from parent if it exists */
581 if (DeviceNode->Parent)
582 {
583 if (DeviceNode->Parent->LastChild == DeviceNode)
584 {
585 DeviceNode->Parent->LastChild = PrevSibling;
586 if (PrevSibling)
587 PrevSibling->Sibling = NULL;
588 }
589 if (DeviceNode->Parent->Child == DeviceNode)
590 DeviceNode->Parent->Child = DeviceNode->Sibling;
591 }
592
593 /* Unlink from sibling list */
594 if (PrevSibling)
595 PrevSibling->Sibling = DeviceNode->Sibling;
596
597 KeReleaseSpinLock(&IopDeviceTreeLock, OldIrql);
598
599 RtlFreeUnicodeString(&DeviceNode->InstancePath);
600
601 RtlFreeUnicodeString(&DeviceNode->ServiceName);
602
603 if (DeviceNode->ResourceList)
604 {
605 ExFreePool(DeviceNode->ResourceList);
606 }
607
608 if (DeviceNode->ResourceListTranslated)
609 {
610 ExFreePool(DeviceNode->ResourceListTranslated);
611 }
612
613 if (DeviceNode->ResourceRequirements)
614 {
615 ExFreePool(DeviceNode->ResourceRequirements);
616 }
617
618 if (DeviceNode->BootResources)
619 {
620 ExFreePool(DeviceNode->BootResources);
621 }
622
623 ExFreePool(DeviceNode);
624
625 return STATUS_SUCCESS;
626 }
627
628 NTSTATUS
629 NTAPI
630 IopSynchronousCall(IN PDEVICE_OBJECT DeviceObject,
631 IN PIO_STACK_LOCATION IoStackLocation,
632 OUT PVOID *Information)
633 {
634 PIRP Irp;
635 PIO_STACK_LOCATION IrpStack;
636 IO_STATUS_BLOCK IoStatusBlock;
637 KEVENT Event;
638 NTSTATUS Status;
639 PDEVICE_OBJECT TopDeviceObject;
640 PAGED_CODE();
641
642 /* Call the top of the device stack */
643 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
644
645 /* Allocate an IRP */
646 Irp = IoAllocateIrp(TopDeviceObject->StackSize, FALSE);
647 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES;
648
649 /* Initialize to failure */
650 Irp->IoStatus.Status = IoStatusBlock.Status = STATUS_NOT_SUPPORTED;
651 Irp->IoStatus.Information = IoStatusBlock.Information = 0;
652
653 /* Initialize the event */
654 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
655
656 /* Set them up */
657 Irp->UserIosb = &IoStatusBlock;
658 Irp->UserEvent = &Event;
659
660 /* Queue the IRP */
661 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
662 IoQueueThreadIrp(Irp);
663
664 /* Copy-in the stack */
665 IrpStack = IoGetNextIrpStackLocation(Irp);
666 *IrpStack = *IoStackLocation;
667
668 /* Call the driver */
669 Status = IoCallDriver(TopDeviceObject, Irp);
670 if (Status == STATUS_PENDING)
671 {
672 /* Wait for it */
673 KeWaitForSingleObject(&Event,
674 Executive,
675 KernelMode,
676 FALSE,
677 NULL);
678 Status = IoStatusBlock.Status;
679 }
680
681 /* Return the information */
682 *Information = (PVOID)IoStatusBlock.Information;
683 return Status;
684 }
685
686 NTSTATUS
687 NTAPI
688 IopInitiatePnpIrp(IN PDEVICE_OBJECT DeviceObject,
689 IN OUT PIO_STATUS_BLOCK IoStatusBlock,
690 IN ULONG MinorFunction,
691 IN PIO_STACK_LOCATION Stack OPTIONAL)
692 {
693 IO_STACK_LOCATION IoStackLocation;
694
695 /* Fill out the stack information */
696 RtlZeroMemory(&IoStackLocation, sizeof(IO_STACK_LOCATION));
697 IoStackLocation.MajorFunction = IRP_MJ_PNP;
698 IoStackLocation.MinorFunction = MinorFunction;
699 if (Stack)
700 {
701 /* Copy the rest */
702 RtlCopyMemory(&IoStackLocation.Parameters,
703 &Stack->Parameters,
704 sizeof(Stack->Parameters));
705 }
706
707 /* Do the PnP call */
708 IoStatusBlock->Status = IopSynchronousCall(DeviceObject,
709 &IoStackLocation,
710 (PVOID)&IoStatusBlock->Information);
711 return IoStatusBlock->Status;
712 }
713
714 NTSTATUS
715 IopTraverseDeviceTreeNode(PDEVICETREE_TRAVERSE_CONTEXT Context)
716 {
717 PDEVICE_NODE ParentDeviceNode;
718 PDEVICE_NODE ChildDeviceNode;
719 NTSTATUS Status;
720
721 /* Copy context data so we don't overwrite it in subsequent calls to this function */
722 ParentDeviceNode = Context->DeviceNode;
723
724 /* Call the action routine */
725 Status = (Context->Action)(ParentDeviceNode, Context->Context);
726 if (!NT_SUCCESS(Status))
727 {
728 return Status;
729 }
730
731 /* Traversal of all children nodes */
732 for (ChildDeviceNode = ParentDeviceNode->Child;
733 ChildDeviceNode != NULL;
734 ChildDeviceNode = ChildDeviceNode->Sibling)
735 {
736 /* Pass the current device node to the action routine */
737 Context->DeviceNode = ChildDeviceNode;
738
739 Status = IopTraverseDeviceTreeNode(Context);
740 if (!NT_SUCCESS(Status))
741 {
742 return Status;
743 }
744 }
745
746 return Status;
747 }
748
749
750 NTSTATUS
751 IopTraverseDeviceTree(PDEVICETREE_TRAVERSE_CONTEXT Context)
752 {
753 NTSTATUS Status;
754
755 DPRINT("Context 0x%p\n", Context);
756
757 DPRINT("IopTraverseDeviceTree(DeviceNode 0x%p FirstDeviceNode 0x%p Action %x Context 0x%p)\n",
758 Context->DeviceNode, Context->FirstDeviceNode, Context->Action, Context->Context);
759
760 /* Start from the specified device node */
761 Context->DeviceNode = Context->FirstDeviceNode;
762
763 /* Recursively traverse the device tree */
764 Status = IopTraverseDeviceTreeNode(Context);
765 if (Status == STATUS_UNSUCCESSFUL)
766 {
767 /* The action routine just wanted to terminate the traversal with status
768 code STATUS_SUCCESS */
769 Status = STATUS_SUCCESS;
770 }
771
772 return Status;
773 }
774
775
776 /*
777 * IopCreateDeviceKeyPath
778 *
779 * Creates a registry key
780 *
781 * Parameters
782 * RegistryPath
783 * Name of the key to be created.
784 * Handle
785 * Handle to the newly created key
786 *
787 * Remarks
788 * This method can create nested trees, so parent of RegistryPath can
789 * be not existant, and will be created if needed.
790 */
791 NTSTATUS
792 NTAPI
793 IopCreateDeviceKeyPath(IN PCUNICODE_STRING RegistryPath,
794 IN ULONG CreateOptions,
795 OUT PHANDLE Handle)
796 {
797 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(ENUM_ROOT);
798 HANDLE hParent = NULL, hKey;
799 OBJECT_ATTRIBUTES ObjectAttributes;
800 UNICODE_STRING KeyName;
801 LPCWSTR Current, Last;
802 ULONG dwLength;
803 NTSTATUS Status;
804
805 /* Assume failure */
806 *Handle = NULL;
807
808 /* Open root key for device instances */
809 Status = IopOpenRegistryKeyEx(&hParent, NULL, &EnumU, KEY_CREATE_SUB_KEY);
810 if (!NT_SUCCESS(Status))
811 {
812 DPRINT1("ZwOpenKey('%wZ') failed with status 0x%08lx\n", &EnumU, Status);
813 return Status;
814 }
815
816 Current = KeyName.Buffer = RegistryPath->Buffer;
817 Last = &RegistryPath->Buffer[RegistryPath->Length / sizeof(WCHAR)];
818
819 /* Go up to the end of the string */
820 while (Current <= Last)
821 {
822 if (Current != Last && *Current != '\\')
823 {
824 /* Not the end of the string and not a separator */
825 Current++;
826 continue;
827 }
828
829 /* Prepare relative key name */
830 dwLength = (ULONG_PTR)Current - (ULONG_PTR)KeyName.Buffer;
831 KeyName.MaximumLength = KeyName.Length = dwLength;
832 DPRINT("Create '%wZ'\n", &KeyName);
833
834 /* Open key */
835 InitializeObjectAttributes(&ObjectAttributes,
836 &KeyName,
837 OBJ_CASE_INSENSITIVE,
838 hParent,
839 NULL);
840 Status = ZwCreateKey(&hKey,
841 Current == Last ? KEY_ALL_ACCESS : KEY_CREATE_SUB_KEY,
842 &ObjectAttributes,
843 0,
844 NULL,
845 CreateOptions,
846 NULL);
847
848 /* Close parent key handle, we don't need it anymore */
849 if (hParent)
850 ZwClose(hParent);
851
852 /* Key opening/creating failed? */
853 if (!NT_SUCCESS(Status))
854 {
855 DPRINT1("ZwCreateKey('%wZ') failed with status 0x%08lx\n", &KeyName, Status);
856 return Status;
857 }
858
859 /* Check if it is the end of the string */
860 if (Current == Last)
861 {
862 /* Yes, return success */
863 *Handle = hKey;
864 return STATUS_SUCCESS;
865 }
866
867 /* Start with this new parent key */
868 hParent = hKey;
869 Current++;
870 KeyName.Buffer = (LPWSTR)Current;
871 }
872
873 return STATUS_UNSUCCESSFUL;
874 }
875
876 NTSTATUS
877 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
878 {
879 NTSTATUS Status;
880 ULONG Disposition;
881 HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
882 UNICODE_STRING KeyName;
883 OBJECT_ATTRIBUTES ObjectAttributes;
884
885 RtlInitUnicodeString(&KeyName,
886 L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
887 InitializeObjectAttributes(&ObjectAttributes,
888 &KeyName,
889 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
890 0,
891 NULL);
892 Status = ZwCreateKey(&ResourceMapKey,
893 KEY_ALL_ACCESS,
894 &ObjectAttributes,
895 0,
896 NULL,
897 REG_OPTION_VOLATILE,
898 &Disposition);
899 if (!NT_SUCCESS(Status))
900 return Status;
901
902 RtlInitUnicodeString(&KeyName, Level1Key);
903 InitializeObjectAttributes(&ObjectAttributes,
904 &KeyName,
905 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
906 ResourceMapKey,
907 NULL);
908 Status = ZwCreateKey(&PnpMgrLevel1,
909 KEY_ALL_ACCESS,
910 &ObjectAttributes,
911 0,
912 NULL,
913 REG_OPTION_VOLATILE,
914 &Disposition);
915 ZwClose(ResourceMapKey);
916 if (!NT_SUCCESS(Status))
917 return Status;
918
919 RtlInitUnicodeString(&KeyName, Level2Key);
920 InitializeObjectAttributes(&ObjectAttributes,
921 &KeyName,
922 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
923 PnpMgrLevel1,
924 NULL);
925 Status = ZwCreateKey(&PnpMgrLevel2,
926 KEY_ALL_ACCESS,
927 &ObjectAttributes,
928 0,
929 NULL,
930 REG_OPTION_VOLATILE,
931 &Disposition);
932 ZwClose(PnpMgrLevel1);
933 if (!NT_SUCCESS(Status))
934 return Status;
935
936 if (DeviceNode->ResourceList)
937 {
938 WCHAR NameBuff[256];
939 UNICODE_STRING NameU;
940 UNICODE_STRING Suffix;
941 ULONG OldLength;
942
943 ASSERT(DeviceNode->ResourceListTranslated);
944
945 NameU.Buffer = NameBuff;
946 NameU.Length = 0;
947 NameU.MaximumLength = 256 * sizeof(WCHAR);
948
949 Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
950 DevicePropertyPhysicalDeviceObjectName,
951 NameU.MaximumLength,
952 NameU.Buffer,
953 &OldLength);
954 ASSERT(Status == STATUS_SUCCESS);
955
956 NameU.Length = (USHORT)OldLength;
957
958 RtlInitUnicodeString(&Suffix, L".Raw");
959 RtlAppendUnicodeStringToString(&NameU, &Suffix);
960
961 Status = ZwSetValueKey(PnpMgrLevel2,
962 &NameU,
963 0,
964 REG_RESOURCE_LIST,
965 DeviceNode->ResourceList,
966 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceList));
967 if (!NT_SUCCESS(Status))
968 {
969 ZwClose(PnpMgrLevel2);
970 return Status;
971 }
972
973 /* "Remove" the suffix by setting the length back to what it used to be */
974 NameU.Length = (USHORT)OldLength;
975
976 RtlInitUnicodeString(&Suffix, L".Translated");
977 RtlAppendUnicodeStringToString(&NameU, &Suffix);
978
979 Status = ZwSetValueKey(PnpMgrLevel2,
980 &NameU,
981 0,
982 REG_RESOURCE_LIST,
983 DeviceNode->ResourceListTranslated,
984 CM_RESOURCE_LIST_SIZE(DeviceNode->ResourceListTranslated));
985 ZwClose(PnpMgrLevel2);
986 if (!NT_SUCCESS(Status))
987 return Status;
988 }
989 else
990 {
991 ZwClose(PnpMgrLevel2);
992 }
993
994 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
995
996 return STATUS_SUCCESS;
997 }
998
999 NTSTATUS
1000 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
1001 {
1002 return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
1003 }
1004
1005 NTSTATUS
1006 IopSetDeviceInstanceData(HANDLE InstanceKey,
1007 PDEVICE_NODE DeviceNode)
1008 {
1009 OBJECT_ATTRIBUTES ObjectAttributes;
1010 UNICODE_STRING KeyName;
1011 HANDLE LogConfKey;
1012 ULONG ResCount;
1013 ULONG ListSize, ResultLength;
1014 NTSTATUS Status;
1015 HANDLE ControlHandle;
1016
1017 DPRINT("IopSetDeviceInstanceData() called\n");
1018
1019 /* Create the 'LogConf' key */
1020 RtlInitUnicodeString(&KeyName, L"LogConf");
1021 InitializeObjectAttributes(&ObjectAttributes,
1022 &KeyName,
1023 OBJ_CASE_INSENSITIVE,
1024 InstanceKey,
1025 NULL);
1026 Status = ZwCreateKey(&LogConfKey,
1027 KEY_ALL_ACCESS,
1028 &ObjectAttributes,
1029 0,
1030 NULL,
1031 0,
1032 NULL);
1033 if (NT_SUCCESS(Status))
1034 {
1035 /* Set 'BootConfig' value */
1036 if (DeviceNode->BootResources != NULL)
1037 {
1038 ResCount = DeviceNode->BootResources->Count;
1039 if (ResCount != 0)
1040 {
1041 ListSize = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
1042
1043 RtlInitUnicodeString(&KeyName, L"BootConfig");
1044 Status = ZwSetValueKey(LogConfKey,
1045 &KeyName,
1046 0,
1047 REG_RESOURCE_LIST,
1048 DeviceNode->BootResources,
1049 ListSize);
1050 }
1051 }
1052
1053 /* Set 'BasicConfigVector' value */
1054 if (DeviceNode->ResourceRequirements != NULL &&
1055 DeviceNode->ResourceRequirements->ListSize != 0)
1056 {
1057 RtlInitUnicodeString(&KeyName, L"BasicConfigVector");
1058 Status = ZwSetValueKey(LogConfKey,
1059 &KeyName,
1060 0,
1061 REG_RESOURCE_REQUIREMENTS_LIST,
1062 DeviceNode->ResourceRequirements,
1063 DeviceNode->ResourceRequirements->ListSize);
1064 }
1065
1066 ZwClose(LogConfKey);
1067 }
1068
1069 /* Set the 'ConfigFlags' value */
1070 RtlInitUnicodeString(&KeyName, L"ConfigFlags");
1071 Status = ZwQueryValueKey(InstanceKey,
1072 &KeyName,
1073 KeyValueBasicInformation,
1074 NULL,
1075 0,
1076 &ResultLength);
1077 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1078 {
1079 /* Write the default value */
1080 ULONG DefaultConfigFlags = 0;
1081 Status = ZwSetValueKey(InstanceKey,
1082 &KeyName,
1083 0,
1084 REG_DWORD,
1085 &DefaultConfigFlags,
1086 sizeof(DefaultConfigFlags));
1087 }
1088
1089 /* Create the 'Control' key */
1090 RtlInitUnicodeString(&KeyName, L"Control");
1091 InitializeObjectAttributes(&ObjectAttributes,
1092 &KeyName,
1093 OBJ_CASE_INSENSITIVE,
1094 InstanceKey,
1095 NULL);
1096 Status = ZwCreateKey(&ControlHandle, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
1097
1098 if (NT_SUCCESS(Status))
1099 ZwClose(ControlHandle);
1100
1101 DPRINT("IopSetDeviceInstanceData() done\n");
1102
1103 return Status;
1104 }
1105
1106 BOOLEAN
1107 IopCheckResourceDescriptor(
1108 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
1109 IN PCM_RESOURCE_LIST ResourceList,
1110 IN BOOLEAN Silent,
1111 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1112 {
1113 ULONG i, ii;
1114 BOOLEAN Result = FALSE;
1115
1116 if (ResDesc->ShareDisposition == CmResourceShareShared)
1117 return FALSE;
1118
1119 for (i = 0; i < ResourceList->Count; i++)
1120 {
1121 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
1122 for (ii = 0; ii < ResList->Count; ii++)
1123 {
1124 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
1125
1126 /* We don't care about shared resources */
1127 if (ResDesc->ShareDisposition == CmResourceShareShared &&
1128 ResDesc2->ShareDisposition == CmResourceShareShared)
1129 continue;
1130
1131 /* Make sure we're comparing the same types */
1132 if (ResDesc->Type != ResDesc2->Type)
1133 continue;
1134
1135 switch (ResDesc->Type)
1136 {
1137 case CmResourceTypeMemory:
1138 if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
1139 ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
1140 ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
1141 ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
1142 ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
1143 {
1144 if (!Silent)
1145 {
1146 DPRINT1("Resource conflict: Memory (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1147 ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
1148 ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
1149 ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
1150 }
1151
1152 Result = TRUE;
1153
1154 goto ByeBye;
1155 }
1156 break;
1157
1158 case CmResourceTypePort:
1159 if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
1160 ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
1161 ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
1162 ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
1163 ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
1164 {
1165 if (!Silent)
1166 {
1167 DPRINT1("Resource conflict: Port (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1168 ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
1169 ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
1170 ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
1171 }
1172
1173 Result = TRUE;
1174
1175 goto ByeBye;
1176 }
1177 break;
1178
1179 case CmResourceTypeInterrupt:
1180 if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
1181 {
1182 if (!Silent)
1183 {
1184 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
1185 ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
1186 ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
1187 }
1188
1189 Result = TRUE;
1190
1191 goto ByeBye;
1192 }
1193 break;
1194
1195 case CmResourceTypeBusNumber:
1196 if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
1197 ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
1198 ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
1199 ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
1200 ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
1201 {
1202 if (!Silent)
1203 {
1204 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
1205 ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
1206 ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
1207 ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
1208 }
1209
1210 Result = TRUE;
1211
1212 goto ByeBye;
1213 }
1214 break;
1215
1216 case CmResourceTypeDma:
1217 if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
1218 {
1219 if (!Silent)
1220 {
1221 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
1222 ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
1223 ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
1224 }
1225
1226 Result = TRUE;
1227
1228 goto ByeBye;
1229 }
1230 break;
1231 }
1232 }
1233 }
1234
1235 ByeBye:
1236
1237 if (Result && ConflictingDescriptor)
1238 {
1239 RtlCopyMemory(ConflictingDescriptor,
1240 ResDesc,
1241 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
1242 }
1243
1244 return Result;
1245 }
1246
1247
1248 BOOLEAN
1249 IopCheckForResourceConflict(
1250 IN PCM_RESOURCE_LIST ResourceList1,
1251 IN PCM_RESOURCE_LIST ResourceList2,
1252 IN BOOLEAN Silent,
1253 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1254 {
1255 ULONG i, ii;
1256 BOOLEAN Result = FALSE;
1257
1258 for (i = 0; i < ResourceList1->Count; i++)
1259 {
1260 PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
1261 for (ii = 0; ii < ResList->Count; ii++)
1262 {
1263 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1264
1265 Result = IopCheckResourceDescriptor(ResDesc,
1266 ResourceList2,
1267 Silent,
1268 ConflictingDescriptor);
1269 if (Result) goto ByeBye;
1270 }
1271 }
1272
1273
1274 ByeBye:
1275
1276 return Result;
1277 }
1278
1279 NTSTATUS
1280 IopDetectResourceConflict(
1281 IN PCM_RESOURCE_LIST ResourceList,
1282 IN BOOLEAN Silent,
1283 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1284 {
1285 OBJECT_ATTRIBUTES ObjectAttributes;
1286 UNICODE_STRING KeyName;
1287 HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
1288 ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1289 PKEY_BASIC_INFORMATION KeyInformation;
1290 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1291 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1292 ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1293 NTSTATUS Status;
1294
1295 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1296 InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
1297 Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1298 if (!NT_SUCCESS(Status))
1299 {
1300 /* The key is missing which means we are the first device */
1301 return STATUS_SUCCESS;
1302 }
1303
1304 while (TRUE)
1305 {
1306 Status = ZwEnumerateKey(ResourceMapKey,
1307 ChildKeyIndex1,
1308 KeyBasicInformation,
1309 NULL,
1310 0,
1311 &RequiredLength);
1312 if (Status == STATUS_NO_MORE_ENTRIES)
1313 break;
1314 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1315 {
1316 KeyInformationLength = RequiredLength;
1317 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1318 if (!KeyInformation)
1319 {
1320 Status = STATUS_INSUFFICIENT_RESOURCES;
1321 goto cleanup;
1322 }
1323
1324 Status = ZwEnumerateKey(ResourceMapKey,
1325 ChildKeyIndex1,
1326 KeyBasicInformation,
1327 KeyInformation,
1328 KeyInformationLength,
1329 &RequiredLength);
1330 }
1331 else
1332 goto cleanup;
1333 ChildKeyIndex1++;
1334 if (!NT_SUCCESS(Status))
1335 goto cleanup;
1336
1337 KeyName.Buffer = KeyInformation->Name;
1338 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1339 InitializeObjectAttributes(&ObjectAttributes,
1340 &KeyName,
1341 OBJ_CASE_INSENSITIVE,
1342 ResourceMapKey,
1343 NULL);
1344 Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1345 ExFreePool(KeyInformation);
1346 if (!NT_SUCCESS(Status))
1347 goto cleanup;
1348
1349 while (TRUE)
1350 {
1351 Status = ZwEnumerateKey(ChildKey2,
1352 ChildKeyIndex2,
1353 KeyBasicInformation,
1354 NULL,
1355 0,
1356 &RequiredLength);
1357 if (Status == STATUS_NO_MORE_ENTRIES)
1358 break;
1359 else if (Status == STATUS_BUFFER_TOO_SMALL)
1360 {
1361 KeyInformationLength = RequiredLength;
1362 KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1363 if (!KeyInformation)
1364 {
1365 Status = STATUS_INSUFFICIENT_RESOURCES;
1366 goto cleanup;
1367 }
1368
1369 Status = ZwEnumerateKey(ChildKey2,
1370 ChildKeyIndex2,
1371 KeyBasicInformation,
1372 KeyInformation,
1373 KeyInformationLength,
1374 &RequiredLength);
1375 }
1376 else
1377 goto cleanup;
1378 ChildKeyIndex2++;
1379 if (!NT_SUCCESS(Status))
1380 goto cleanup;
1381
1382 KeyName.Buffer = KeyInformation->Name;
1383 KeyName.MaximumLength = KeyName.Length = KeyInformation->NameLength;
1384 InitializeObjectAttributes(&ObjectAttributes,
1385 &KeyName,
1386 OBJ_CASE_INSENSITIVE,
1387 ChildKey2,
1388 NULL);
1389 Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1390 ExFreePool(KeyInformation);
1391 if (!NT_SUCCESS(Status))
1392 goto cleanup;
1393
1394 while (TRUE)
1395 {
1396 Status = ZwEnumerateValueKey(ChildKey3,
1397 ChildKeyIndex3,
1398 KeyValuePartialInformation,
1399 NULL,
1400 0,
1401 &RequiredLength);
1402 if (Status == STATUS_NO_MORE_ENTRIES)
1403 break;
1404 else if (Status == STATUS_BUFFER_TOO_SMALL)
1405 {
1406 KeyValueInformationLength = RequiredLength;
1407 KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1408 if (!KeyValueInformation)
1409 {
1410 Status = STATUS_INSUFFICIENT_RESOURCES;
1411 goto cleanup;
1412 }
1413
1414 Status = ZwEnumerateValueKey(ChildKey3,
1415 ChildKeyIndex3,
1416 KeyValuePartialInformation,
1417 KeyValueInformation,
1418 KeyValueInformationLength,
1419 &RequiredLength);
1420 }
1421 else
1422 goto cleanup;
1423 if (!NT_SUCCESS(Status))
1424 goto cleanup;
1425
1426 Status = ZwEnumerateValueKey(ChildKey3,
1427 ChildKeyIndex3,
1428 KeyValueBasicInformation,
1429 NULL,
1430 0,
1431 &RequiredLength);
1432 if (Status == STATUS_BUFFER_TOO_SMALL)
1433 {
1434 KeyNameInformationLength = RequiredLength;
1435 KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1436 if (!KeyNameInformation)
1437 {
1438 Status = STATUS_INSUFFICIENT_RESOURCES;
1439 goto cleanup;
1440 }
1441
1442 Status = ZwEnumerateValueKey(ChildKey3,
1443 ChildKeyIndex3,
1444 KeyValueBasicInformation,
1445 KeyNameInformation,
1446 KeyNameInformationLength,
1447 &RequiredLength);
1448 }
1449 else
1450 goto cleanup;
1451
1452 ChildKeyIndex3++;
1453
1454 if (!NT_SUCCESS(Status))
1455 goto cleanup;
1456
1457 KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1458
1459 /* Skip translated entries */
1460 if (wcsstr(KeyNameInformation->Name, L".Translated"))
1461 {
1462 ExFreePool(KeyNameInformation);
1463 continue;
1464 }
1465
1466 ExFreePool(KeyNameInformation);
1467
1468 if (IopCheckForResourceConflict(ResourceList,
1469 (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1470 Silent,
1471 ConflictingDescriptor))
1472 {
1473 ExFreePool(KeyValueInformation);
1474 Status = STATUS_CONFLICTING_ADDRESSES;
1475 goto cleanup;
1476 }
1477
1478 ExFreePool(KeyValueInformation);
1479 }
1480 }
1481 }
1482
1483 cleanup:
1484 if (ResourceMapKey != INVALID_HANDLE_VALUE)
1485 ZwClose(ResourceMapKey);
1486 if (ChildKey2 != INVALID_HANDLE_VALUE)
1487 ZwClose(ChildKey2);
1488 if (ChildKey3 != INVALID_HANDLE_VALUE)
1489 ZwClose(ChildKey3);
1490
1491 if (Status == STATUS_NO_MORE_ENTRIES)
1492 Status = STATUS_SUCCESS;
1493
1494 return Status;
1495 }
1496
1497 BOOLEAN
1498 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1499 {
1500 CM_RESOURCE_LIST CmList;
1501 NTSTATUS Status;
1502
1503 CmList.Count = 1;
1504 CmList.List[0].InterfaceType = InterfaceTypeUndefined;
1505 CmList.List[0].BusNumber = 0;
1506 CmList.List[0].PartialResourceList.Version = 1;
1507 CmList.List[0].PartialResourceList.Revision = 1;
1508 CmList.List[0].PartialResourceList.Count = 1;
1509 CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
1510
1511 Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
1512 if (Status == STATUS_CONFLICTING_ADDRESSES)
1513 return TRUE;
1514
1515 return FALSE;
1516 }
1517
1518 BOOLEAN
1519 IopFindBusNumberResource(
1520 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1521 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1522 {
1523 ULONG Start;
1524 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1525
1526 ASSERT(IoDesc->Type == CmDesc->Type);
1527 ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
1528
1529 for (Start = IoDesc->u.BusNumber.MinBusNumber;
1530 Start < IoDesc->u.BusNumber.MaxBusNumber;
1531 Start++)
1532 {
1533 CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
1534 CmDesc->u.BusNumber.Start = Start;
1535
1536 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1537 {
1538 Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
1539 }
1540 else
1541 {
1542 return TRUE;
1543 }
1544 }
1545
1546 return FALSE;
1547 }
1548
1549 BOOLEAN
1550 IopFindMemoryResource(
1551 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1552 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1553 {
1554 ULONGLONG Start;
1555 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1556
1557 ASSERT(IoDesc->Type == CmDesc->Type);
1558 ASSERT(IoDesc->Type == CmResourceTypeMemory);
1559
1560 for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
1561 Start < IoDesc->u.Memory.MaximumAddress.QuadPart;
1562 Start++)
1563 {
1564 CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
1565 CmDesc->u.Memory.Start.QuadPart = Start;
1566
1567 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1568 {
1569 Start += ConflictingDesc.u.Memory.Start.QuadPart + ConflictingDesc.u.Memory.Length;
1570 }
1571 else
1572 {
1573 return TRUE;
1574 }
1575 }
1576
1577 return FALSE;
1578 }
1579
1580 BOOLEAN
1581 IopFindPortResource(
1582 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1583 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1584 {
1585 ULONGLONG Start;
1586 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
1587
1588 ASSERT(IoDesc->Type == CmDesc->Type);
1589 ASSERT(IoDesc->Type == CmResourceTypePort);
1590
1591 for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
1592 Start < IoDesc->u.Port.MaximumAddress.QuadPart;
1593 Start++)
1594 {
1595 CmDesc->u.Port.Length = IoDesc->u.Port.Length;
1596 CmDesc->u.Port.Start.QuadPart = Start;
1597
1598 if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
1599 {
1600 Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
1601 }
1602 else
1603 {
1604 return TRUE;
1605 }
1606 }
1607
1608 return FALSE;
1609 }
1610
1611 BOOLEAN
1612 IopFindDmaResource(
1613 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1614 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1615 {
1616 ULONG Channel;
1617
1618 ASSERT(IoDesc->Type == CmDesc->Type);
1619 ASSERT(IoDesc->Type == CmResourceTypeDma);
1620
1621 for (Channel = IoDesc->u.Dma.MinimumChannel;
1622 Channel < IoDesc->u.Dma.MaximumChannel;
1623 Channel++)
1624 {
1625 CmDesc->u.Dma.Channel = Channel;
1626 CmDesc->u.Dma.Port = 0;
1627
1628 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1629 return TRUE;
1630 }
1631
1632 return FALSE;
1633 }
1634
1635 BOOLEAN
1636 IopFindInterruptResource(
1637 IN PIO_RESOURCE_DESCRIPTOR IoDesc,
1638 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
1639 {
1640 ULONG Vector;
1641
1642 ASSERT(IoDesc->Type == CmDesc->Type);
1643 ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
1644
1645 for (Vector = IoDesc->u.Interrupt.MinimumVector;
1646 Vector < IoDesc->u.Interrupt.MaximumVector;
1647 Vector++)
1648 {
1649 CmDesc->u.Interrupt.Vector = Vector;
1650 CmDesc->u.Interrupt.Level = Vector;
1651 CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
1652
1653 if (!IopCheckDescriptorForConflict(CmDesc, NULL))
1654 return TRUE;
1655 }
1656
1657 return FALSE;
1658 }
1659
1660 NTSTATUS
1661 IopCreateResourceListFromRequirements(
1662 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
1663 OUT PCM_RESOURCE_LIST *ResourceList)
1664 {
1665 ULONG i, ii, Size;
1666 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc;
1667
1668 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1669 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1670 {
1671 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1672 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
1673 + ResList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1674 }
1675
1676 *ResourceList = ExAllocatePool(PagedPool, Size);
1677 if (!*ResourceList)
1678 return STATUS_INSUFFICIENT_RESOURCES;
1679
1680 (*ResourceList)->Count = 1;
1681 (*ResourceList)->List[0].BusNumber = RequirementsList->BusNumber;
1682 (*ResourceList)->List[0].InterfaceType = RequirementsList->InterfaceType;
1683 (*ResourceList)->List[0].PartialResourceList.Version = 1;
1684 (*ResourceList)->List[0].PartialResourceList.Revision = 1;
1685 (*ResourceList)->List[0].PartialResourceList.Count = 0;
1686
1687 ResDesc = &(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[0];
1688
1689 for (i = 0; i < RequirementsList->AlternativeLists; i++)
1690 {
1691 PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
1692 for (ii = 0; ii < ResList->Count; ii++)
1693 {
1694 PIO_RESOURCE_DESCRIPTOR ReqDesc = &ResList->Descriptors[ii];
1695
1696 /* FIXME: Handle alternate ranges */
1697 if (ReqDesc->Option == IO_RESOURCE_ALTERNATIVE)
1698 continue;
1699
1700 ResDesc->Type = ReqDesc->Type;
1701 ResDesc->Flags = ReqDesc->Flags;
1702 ResDesc->ShareDisposition = ReqDesc->ShareDisposition;
1703
1704 switch (ReqDesc->Type)
1705 {
1706 case CmResourceTypeInterrupt:
1707 if (!IopFindInterruptResource(ReqDesc, ResDesc))
1708 {
1709 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
1710 ReqDesc->u.Interrupt.MinimumVector, ReqDesc->u.Interrupt.MaximumVector);
1711
1712 if (ReqDesc->Option == 0)
1713 {
1714 ExFreePool(*ResourceList);
1715 return STATUS_CONFLICTING_ADDRESSES;
1716 }
1717 }
1718 break;
1719
1720 case CmResourceTypePort:
1721 if (!IopFindPortResource(ReqDesc, ResDesc))
1722 {
1723 DPRINT1("Failed to find an available port resource (0x%x to 0x%x length: 0x%x)\n",
1724 ReqDesc->u.Port.MinimumAddress.QuadPart, ReqDesc->u.Port.MaximumAddress.QuadPart,
1725 ReqDesc->u.Port.Length);
1726
1727 if (ReqDesc->Option == 0)
1728 {
1729 ExFreePool(*ResourceList);
1730 return STATUS_CONFLICTING_ADDRESSES;
1731 }
1732 }
1733 break;
1734
1735 case CmResourceTypeMemory:
1736 if (!IopFindMemoryResource(ReqDesc, ResDesc))
1737 {
1738 DPRINT1("Failed to find an available memory resource (0x%x to 0x%x length: 0x%x)\n",
1739 ReqDesc->u.Memory.MinimumAddress.QuadPart, ReqDesc->u.Memory.MaximumAddress.QuadPart,
1740 ReqDesc->u.Memory.Length);
1741
1742 if (ReqDesc->Option == 0)
1743 {
1744 ExFreePool(*ResourceList);
1745 return STATUS_CONFLICTING_ADDRESSES;
1746 }
1747 }
1748 break;
1749
1750 case CmResourceTypeBusNumber:
1751 if (!IopFindBusNumberResource(ReqDesc, ResDesc))
1752 {
1753 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
1754 ReqDesc->u.BusNumber.MinBusNumber, ReqDesc->u.BusNumber.MaxBusNumber,
1755 ReqDesc->u.BusNumber.Length);
1756
1757 if (ReqDesc->Option == 0)
1758 {
1759 ExFreePool(*ResourceList);
1760 return STATUS_CONFLICTING_ADDRESSES;
1761 }
1762 }
1763 break;
1764
1765 case CmResourceTypeDma:
1766 if (!IopFindDmaResource(ReqDesc, ResDesc))
1767 {
1768 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
1769 ReqDesc->u.Dma.MinimumChannel, ReqDesc->u.Dma.MaximumChannel);
1770
1771 if (ReqDesc->Option == 0)
1772 {
1773 ExFreePool(*ResourceList);
1774 return STATUS_CONFLICTING_ADDRESSES;
1775 }
1776 }
1777 break;
1778
1779 default:
1780 DPRINT1("Unsupported resource type: %x\n", ReqDesc->Type);
1781 break;
1782 }
1783
1784 (*ResourceList)->List[0].PartialResourceList.Count++;
1785 ResDesc++;
1786 }
1787 }
1788
1789 return STATUS_SUCCESS;
1790 }
1791
1792 NTSTATUS
1793 IopAssignDeviceResources(
1794 IN PDEVICE_NODE DeviceNode,
1795 OUT ULONG *pRequiredSize)
1796 {
1797 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1798 ULONG Size;
1799 ULONG i;
1800 ULONG j;
1801 NTSTATUS Status;
1802
1803 if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1804 {
1805 /* No resource needed for this device */
1806 DeviceNode->ResourceList = NULL;
1807 *pRequiredSize = 0;
1808 return STATUS_SUCCESS;
1809 }
1810
1811 /* Fill DeviceNode->ResourceList
1812 * FIXME: the PnP arbiter should go there!
1813 * Actually, use the BootResources if provided, else the resource requirements
1814 */
1815
1816 if (DeviceNode->BootResources)
1817 {
1818 /* Browse the boot resources to know if we have some custom structures */
1819 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1820 for (i = 0; i < DeviceNode->BootResources->Count; i++)
1821 {
1822 pPartialResourceList = &DeviceNode->BootResources->List[i].PartialResourceList;
1823 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors) +
1824 pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1825 for (j = 0; j < pPartialResourceList->Count; j++)
1826 {
1827 if (pPartialResourceList->PartialDescriptors[j].Type == CmResourceTypeDeviceSpecific)
1828 Size += pPartialResourceList->PartialDescriptors[j].u.DeviceSpecificData.DataSize;
1829 }
1830 }
1831
1832 DeviceNode->ResourceList = ExAllocatePool(PagedPool, Size);
1833 if (!DeviceNode->ResourceList)
1834 {
1835 Status = STATUS_NO_MEMORY;
1836 goto ByeBye;
1837 }
1838 RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, Size);
1839
1840 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1841 if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
1842 {
1843 if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
1844 {
1845 DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
1846 }
1847
1848 *pRequiredSize = Size;
1849 return STATUS_SUCCESS;
1850 }
1851 else
1852 {
1853 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1854 ExFreePool(DeviceNode->ResourceList);
1855 }
1856 }
1857
1858 Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
1859 &DeviceNode->ResourceList);
1860 if (!NT_SUCCESS(Status))
1861 goto ByeBye;
1862
1863 Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
1864 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1865 {
1866 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1867 Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors) +
1868 pPartialResourceList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
1869 }
1870
1871 Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1872 if (!NT_SUCCESS(Status))
1873 goto ByeBye;
1874
1875 *pRequiredSize = Size;
1876 return STATUS_SUCCESS;
1877
1878 ByeBye:
1879 if (DeviceNode->ResourceList)
1880 {
1881 ExFreePool(DeviceNode->ResourceList);
1882 DeviceNode->ResourceList = NULL;
1883 }
1884 *pRequiredSize = 0;
1885 return Status;
1886 }
1887
1888
1889 NTSTATUS
1890 IopTranslateDeviceResources(
1891 IN PDEVICE_NODE DeviceNode,
1892 IN ULONG RequiredSize)
1893 {
1894 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
1895 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
1896 ULONG i, j;
1897 NTSTATUS Status;
1898
1899 if (!DeviceNode->ResourceList)
1900 {
1901 DeviceNode->ResourceListTranslated = NULL;
1902 return STATUS_SUCCESS;
1903 }
1904
1905 /* That's easy to translate a resource list. Just copy the
1906 * untranslated one and change few fields in the copy
1907 */
1908 DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, RequiredSize);
1909 if (!DeviceNode->ResourceListTranslated)
1910 {
1911 Status =STATUS_NO_MEMORY;
1912 goto cleanup;
1913 }
1914 RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, RequiredSize);
1915
1916 for (i = 0; i < DeviceNode->ResourceList->Count; i++)
1917 {
1918 pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
1919 for (j = 0; j < pPartialResourceList->Count; j++)
1920 {
1921 DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
1922 DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
1923 switch (DescriptorRaw->Type)
1924 {
1925 case CmResourceTypePort:
1926 {
1927 ULONG AddressSpace = 1; /* IO space */
1928 if (!HalTranslateBusAddress(
1929 DeviceNode->ResourceList->List[i].InterfaceType,
1930 DeviceNode->ResourceList->List[i].BusNumber,
1931 DescriptorRaw->u.Port.Start,
1932 &AddressSpace,
1933 &DescriptorTranslated->u.Port.Start))
1934 {
1935 Status = STATUS_UNSUCCESSFUL;
1936 goto cleanup;
1937 }
1938 break;
1939 }
1940 case CmResourceTypeInterrupt:
1941 {
1942 DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1943 DeviceNode->ResourceList->List[i].InterfaceType,
1944 DeviceNode->ResourceList->List[i].BusNumber,
1945 DescriptorRaw->u.Interrupt.Level,
1946 DescriptorRaw->u.Interrupt.Vector,
1947 (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
1948 &DescriptorRaw->u.Interrupt.Affinity);
1949 break;
1950 }
1951 case CmResourceTypeMemory:
1952 {
1953 ULONG AddressSpace = 0; /* Memory space */
1954 if (!HalTranslateBusAddress(
1955 DeviceNode->ResourceList->List[i].InterfaceType,
1956 DeviceNode->ResourceList->List[i].BusNumber,
1957 DescriptorRaw->u.Memory.Start,
1958 &AddressSpace,
1959 &DescriptorTranslated->u.Memory.Start))
1960 {
1961 Status = STATUS_UNSUCCESSFUL;
1962 goto cleanup;
1963 }
1964 }
1965
1966 case CmResourceTypeDma:
1967 case CmResourceTypeBusNumber:
1968 case CmResourceTypeDeviceSpecific:
1969 /* Nothing to do */
1970 break;
1971 default:
1972 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1973 Status = STATUS_NOT_IMPLEMENTED;
1974 goto cleanup;
1975 }
1976 }
1977 }
1978 return STATUS_SUCCESS;
1979
1980 cleanup:
1981 /* Yes! Also delete ResourceList because ResourceList and
1982 * ResourceListTranslated should be a pair! */
1983 ExFreePool(DeviceNode->ResourceList);
1984 DeviceNode->ResourceList = NULL;
1985 if (DeviceNode->ResourceListTranslated)
1986 {
1987 ExFreePool(DeviceNode->ResourceListTranslated);
1988 DeviceNode->ResourceList = NULL;
1989 }
1990 return Status;
1991 }
1992
1993
1994 /*
1995 * IopGetParentIdPrefix
1996 *
1997 * Retrieve (or create) a string which identifies a device.
1998 *
1999 * Parameters
2000 * DeviceNode
2001 * Pointer to device node.
2002 * ParentIdPrefix
2003 * Pointer to the string where is returned the parent node identifier
2004 *
2005 * Remarks
2006 * If the return code is STATUS_SUCCESS, the ParentIdPrefix string is
2007 * valid and its Buffer field is NULL-terminated. The caller needs to
2008 * to free the string with RtlFreeUnicodeString when it is no longer
2009 * needed.
2010 */
2011
2012 NTSTATUS
2013 IopGetParentIdPrefix(PDEVICE_NODE DeviceNode,
2014 PUNICODE_STRING ParentIdPrefix)
2015 {
2016 ULONG KeyNameBufferLength;
2017 PKEY_VALUE_PARTIAL_INFORMATION ParentIdPrefixInformation = NULL;
2018 UNICODE_STRING KeyName;
2019 UNICODE_STRING KeyValue;
2020 UNICODE_STRING ValueName;
2021 HANDLE hKey = NULL;
2022 ULONG crc32;
2023 NTSTATUS Status;
2024
2025 /* HACK: As long as some devices have a NULL device
2026 * instance path, the following test is required :(
2027 */
2028 if (DeviceNode->Parent->InstancePath.Length == 0)
2029 {
2030 DPRINT1("Parent of %wZ has NULL Instance path, please report!\n",
2031 &DeviceNode->InstancePath);
2032 return STATUS_UNSUCCESSFUL;
2033 }
2034
2035 /* 1. Try to retrieve ParentIdPrefix from registry */
2036 KeyNameBufferLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + MAX_PATH * sizeof(WCHAR);
2037 ParentIdPrefixInformation = ExAllocatePool(PagedPool, KeyNameBufferLength + sizeof(WCHAR));
2038 if (!ParentIdPrefixInformation)
2039 {
2040 Status = STATUS_INSUFFICIENT_RESOURCES;
2041 goto cleanup;
2042 }
2043
2044
2045 KeyName.Buffer = ExAllocatePool(PagedPool, (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length);
2046 if (!KeyName.Buffer)
2047 {
2048 Status = STATUS_INSUFFICIENT_RESOURCES;
2049 goto cleanup;
2050 }
2051 KeyName.Length = 0;
2052 KeyName.MaximumLength = (49 * sizeof(WCHAR)) + DeviceNode->Parent->InstancePath.Length;
2053
2054 RtlAppendUnicodeToString(&KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2055 RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->Parent->InstancePath);
2056
2057 Status = IopOpenRegistryKeyEx(&hKey, NULL, &KeyName, KEY_QUERY_VALUE | KEY_SET_VALUE);
2058 if (!NT_SUCCESS(Status))
2059 goto cleanup;
2060 RtlInitUnicodeString(&ValueName, L"ParentIdPrefix");
2061 Status = ZwQueryValueKey(
2062 hKey, &ValueName,
2063 KeyValuePartialInformation, ParentIdPrefixInformation,
2064 KeyNameBufferLength, &KeyNameBufferLength);
2065 if (NT_SUCCESS(Status))
2066 {
2067 if (ParentIdPrefixInformation->Type != REG_SZ)
2068 Status = STATUS_UNSUCCESSFUL;
2069 else
2070 {
2071 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2072 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2073 }
2074 goto cleanup;
2075 }
2076 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
2077 {
2078 KeyValue.Length = KeyValue.MaximumLength = (USHORT)ParentIdPrefixInformation->DataLength;
2079 KeyValue.Buffer = (PWSTR)ParentIdPrefixInformation->Data;
2080 goto cleanup;
2081 }
2082
2083 /* 2. Create the ParentIdPrefix value */
2084 crc32 = RtlComputeCrc32(0,
2085 (PUCHAR)DeviceNode->Parent->InstancePath.Buffer,
2086 DeviceNode->Parent->InstancePath.Length);
2087
2088 swprintf((PWSTR)ParentIdPrefixInformation->Data, L"%lx&%lx", DeviceNode->Parent->Level, crc32);
2089 RtlInitUnicodeString(&KeyValue, (PWSTR)ParentIdPrefixInformation->Data);
2090
2091 /* 3. Try to write the ParentIdPrefix to registry */
2092 Status = ZwSetValueKey(hKey,
2093 &ValueName,
2094 0,
2095 REG_SZ,
2096 (PVOID)KeyValue.Buffer,
2097 (wcslen(KeyValue.Buffer) + 1) * sizeof(WCHAR));
2098
2099 cleanup:
2100 if (NT_SUCCESS(Status))
2101 {
2102 /* Duplicate the string to return it */
2103 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &KeyValue, ParentIdPrefix);
2104 }
2105 ExFreePool(ParentIdPrefixInformation);
2106 RtlFreeUnicodeString(&KeyName);
2107 if (hKey != NULL)
2108 ZwClose(hKey);
2109 return Status;
2110 }
2111
2112
2113 /*
2114 * IopActionInterrogateDeviceStack
2115 *
2116 * Retrieve information for all (direct) child nodes of a parent node.
2117 *
2118 * Parameters
2119 * DeviceNode
2120 * Pointer to device node.
2121 * Context
2122 * Pointer to parent node to retrieve child node information for.
2123 *
2124 * Remarks
2125 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2126 * when we reach a device node which is not a direct child of the device
2127 * node for which we retrieve information of child nodes for. Any errors
2128 * that occur is logged instead so that all child services have a chance
2129 * of being interrogated.
2130 */
2131
2132 NTSTATUS
2133 IopActionInterrogateDeviceStack(PDEVICE_NODE DeviceNode,
2134 PVOID Context)
2135 {
2136 IO_STATUS_BLOCK IoStatusBlock;
2137 PDEVICE_NODE ParentDeviceNode;
2138 WCHAR InstancePath[MAX_PATH];
2139 IO_STACK_LOCATION Stack;
2140 NTSTATUS Status;
2141 PWSTR Ptr;
2142 USHORT Length;
2143 USHORT TotalLength;
2144 ULONG RequiredLength;
2145 LCID LocaleId;
2146 HANDLE InstanceKey = NULL;
2147 UNICODE_STRING ValueName;
2148 UNICODE_STRING ParentIdPrefix = { 0, 0, NULL };
2149 DEVICE_CAPABILITIES DeviceCapabilities;
2150
2151 DPRINT("IopActionInterrogateDeviceStack(%p, %p)\n", DeviceNode, Context);
2152 DPRINT("PDO 0x%p\n", DeviceNode->PhysicalDeviceObject);
2153
2154 ParentDeviceNode = (PDEVICE_NODE)Context;
2155
2156 /*
2157 * We are called for the parent too, but we don't need to do special
2158 * handling for this node
2159 */
2160
2161 if (DeviceNode == ParentDeviceNode)
2162 {
2163 DPRINT("Success\n");
2164 return STATUS_SUCCESS;
2165 }
2166
2167 /*
2168 * Make sure this device node is a direct child of the parent device node
2169 * that is given as an argument
2170 */
2171
2172 if (DeviceNode->Parent != ParentDeviceNode)
2173 {
2174 /* Stop the traversal immediately and indicate successful operation */
2175 DPRINT("Stop\n");
2176 return STATUS_UNSUCCESSFUL;
2177 }
2178
2179 /* Get Locale ID */
2180 Status = ZwQueryDefaultLocale(FALSE, &LocaleId);
2181 if (!NT_SUCCESS(Status))
2182 {
2183 DPRINT("ZwQueryDefaultLocale() failed with status 0x%lx\n", Status);
2184 return Status;
2185 }
2186
2187 /*
2188 * FIXME: For critical errors, cleanup and disable device, but always
2189 * return STATUS_SUCCESS.
2190 */
2191
2192 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryDeviceID to device stack\n");
2193
2194 Stack.Parameters.QueryId.IdType = BusQueryDeviceID;
2195 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2196 &IoStatusBlock,
2197 IRP_MN_QUERY_ID,
2198 &Stack);
2199 if (NT_SUCCESS(Status))
2200 {
2201 /* Copy the device id string */
2202 wcscpy(InstancePath, (PWSTR)IoStatusBlock.Information);
2203
2204 /*
2205 * FIXME: Check for valid characters, if there is invalid characters
2206 * then bugcheck.
2207 */
2208 }
2209 else
2210 {
2211 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2212 }
2213
2214 DPRINT("Sending IRP_MN_QUERY_CAPABILITIES to device stack\n");
2215
2216 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCapabilities);
2217 if (!NT_SUCCESS(Status))
2218 {
2219 DPRINT("IopInitiatePnpIrp() failed (Status 0x%08lx)\n", Status);
2220 }
2221
2222 DeviceNode->CapabilityFlags = *(PULONG)((ULONG_PTR)&DeviceCapabilities + 4);
2223
2224 if (!DeviceCapabilities.UniqueID)
2225 {
2226 /* Device has not a unique ID. We need to prepend parent bus unique identifier */
2227 DPRINT("Instance ID is not unique\n");
2228 Status = IopGetParentIdPrefix(DeviceNode, &ParentIdPrefix);
2229 if (!NT_SUCCESS(Status))
2230 {
2231 DPRINT("IopGetParentIdPrefix() failed (Status 0x%08lx)\n", Status);
2232 }
2233 }
2234
2235 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryInstanceID to device stack\n");
2236
2237 Stack.Parameters.QueryId.IdType = BusQueryInstanceID;
2238 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2239 &IoStatusBlock,
2240 IRP_MN_QUERY_ID,
2241 &Stack);
2242 if (NT_SUCCESS(Status))
2243 {
2244 /* Append the instance id string */
2245 wcscat(InstancePath, L"\\");
2246 if (ParentIdPrefix.Length > 0)
2247 {
2248 /* Add information from parent bus device to InstancePath */
2249 wcscat(InstancePath, ParentIdPrefix.Buffer);
2250 if (IoStatusBlock.Information && *(PWSTR)IoStatusBlock.Information)
2251 wcscat(InstancePath, L"&");
2252 }
2253 if (IoStatusBlock.Information)
2254 wcscat(InstancePath, (PWSTR)IoStatusBlock.Information);
2255
2256 /*
2257 * FIXME: Check for valid characters, if there is invalid characters
2258 * then bugcheck
2259 */
2260 }
2261 else
2262 {
2263 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2264 }
2265 RtlFreeUnicodeString(&ParentIdPrefix);
2266
2267 if (!RtlCreateUnicodeString(&DeviceNode->InstancePath, InstancePath))
2268 {
2269 DPRINT("No resources\n");
2270 /* FIXME: Cleanup and disable device */
2271 }
2272
2273 DPRINT("InstancePath is %S\n", DeviceNode->InstancePath.Buffer);
2274
2275 /*
2276 * Create registry key for the instance id, if it doesn't exist yet
2277 */
2278 Status = IopCreateDeviceKeyPath(&DeviceNode->InstancePath, 0, &InstanceKey);
2279 if (!NT_SUCCESS(Status))
2280 {
2281 DPRINT1("Failed to create the instance key! (Status %lx)\n", Status);
2282 }
2283
2284 {
2285 /* Set 'Capabilities' value */
2286 RtlInitUnicodeString(&ValueName, L"Capabilities");
2287 Status = ZwSetValueKey(InstanceKey,
2288 &ValueName,
2289 0,
2290 REG_DWORD,
2291 (PVOID)&DeviceNode->CapabilityFlags,
2292 sizeof(ULONG));
2293
2294 /* Set 'UINumber' value */
2295 if (DeviceCapabilities.UINumber != MAXULONG)
2296 {
2297 RtlInitUnicodeString(&ValueName, L"UINumber");
2298 Status = ZwSetValueKey(InstanceKey,
2299 &ValueName,
2300 0,
2301 REG_DWORD,
2302 &DeviceCapabilities.UINumber,
2303 sizeof(ULONG));
2304 }
2305 }
2306
2307 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryHardwareIDs to device stack\n");
2308
2309 Stack.Parameters.QueryId.IdType = BusQueryHardwareIDs;
2310 Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
2311 &IoStatusBlock,
2312 IRP_MN_QUERY_ID,
2313 &Stack);
2314 if (NT_SUCCESS(Status))
2315 {
2316 /*
2317 * FIXME: Check for valid characters, if there is invalid characters
2318 * then bugcheck.
2319 */
2320 TotalLength = 0;
2321 Ptr = (PWSTR)IoStatusBlock.Information;
2322 DPRINT("Hardware IDs:\n");
2323 while (*Ptr)
2324 {
2325 DPRINT(" %S\n", Ptr);
2326 Length = wcslen(Ptr) + 1;
2327
2328 Ptr += Length;
2329 TotalLength += Length;
2330 }
2331 DPRINT("TotalLength: %hu\n", TotalLength);
2332 DPRINT("\n");
2333
2334 RtlInitUnicodeString(&ValueName, L"HardwareID");
2335 Status = ZwSetValueKey(InstanceKey,
2336 &ValueName,
2337 0,
2338 REG_MULTI_SZ,
2339 (PVOID)IoStatusBlock.Information,
2340 (TotalLength + 1) * sizeof(WCHAR));
2341 if (!NT_SUCCESS(Status))
2342 {
2343 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2344 }
2345 }
2346 else
2347 {
2348 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2349 }
2350
2351 DPRINT("Sending IRP_MN_QUERY_ID.BusQueryCompatibleIDs to device stack\n");
2352
2353 Stack.Parameters.QueryId.IdType = BusQueryCompatibleIDs;
2354 Status = IopInitiatePnpIrp(
2355 DeviceNode->PhysicalDeviceObject,
2356 &IoStatusBlock,
2357 IRP_MN_QUERY_ID,
2358 &Stack);
2359 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2360 {
2361 /*
2362 * FIXME: Check for valid characters, if there is invalid characters
2363 * then bugcheck.
2364 */
2365 TotalLength = 0;
2366 Ptr = (PWSTR)IoStatusBlock.Information;
2367 DPRINT("Compatible IDs:\n");
2368 while (*Ptr)
2369 {
2370 DPRINT(" %S\n", Ptr);
2371 Length = wcslen(Ptr) + 1;
2372
2373 Ptr += Length;
2374 TotalLength += Length;
2375 }
2376 DPRINT("TotalLength: %hu\n", TotalLength);
2377 DPRINT("\n");
2378
2379 RtlInitUnicodeString(&ValueName, L"CompatibleIDs");
2380 Status = ZwSetValueKey(InstanceKey,
2381 &ValueName,
2382 0,
2383 REG_MULTI_SZ,
2384 (PVOID)IoStatusBlock.Information,
2385 (TotalLength + 1) * sizeof(WCHAR));
2386 if (!NT_SUCCESS(Status))
2387 {
2388 DPRINT1("ZwSetValueKey() failed (Status %lx) or no Compatible ID returned\n", Status);
2389 }
2390 }
2391 else
2392 {
2393 DPRINT("IopInitiatePnpIrp() failed (Status %x)\n", Status);
2394 }
2395
2396 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextDescription to device stack\n");
2397
2398 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextDescription;
2399 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2400 Status = IopInitiatePnpIrp(
2401 DeviceNode->PhysicalDeviceObject,
2402 &IoStatusBlock,
2403 IRP_MN_QUERY_DEVICE_TEXT,
2404 &Stack);
2405 /* This key is mandatory, so even if the Irp fails, we still write it */
2406 RtlInitUnicodeString(&ValueName, L"DeviceDesc");
2407 if (ZwQueryValueKey(InstanceKey, &ValueName, KeyValueBasicInformation, NULL, 0, &RequiredLength) == STATUS_OBJECT_NAME_NOT_FOUND)
2408 {
2409 if (NT_SUCCESS(Status) &&
2410 IoStatusBlock.Information &&
2411 (*(PWSTR)IoStatusBlock.Information != 0))
2412 {
2413 /* This key is overriden when a driver is installed. Don't write the
2414 * new description if another one already exists */
2415 Status = ZwSetValueKey(InstanceKey,
2416 &ValueName,
2417 0,
2418 REG_SZ,
2419 (PVOID)IoStatusBlock.Information,
2420 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2421 }
2422 else
2423 {
2424 UNICODE_STRING DeviceDesc = RTL_CONSTANT_STRING(L"Unknown device");
2425 DPRINT("Driver didn't return DeviceDesc (Status 0x%08lx), so place unknown device there\n", Status);
2426
2427 Status = ZwSetValueKey(InstanceKey,
2428 &ValueName,
2429 0,
2430 REG_SZ,
2431 DeviceDesc.Buffer,
2432 DeviceDesc.MaximumLength);
2433
2434 if (!NT_SUCCESS(Status))
2435 {
2436 DPRINT1("ZwSetValueKey() failed (Status 0x%lx)\n", Status);
2437 }
2438
2439 }
2440 }
2441
2442 DPRINT("Sending IRP_MN_QUERY_DEVICE_TEXT.DeviceTextLocation to device stack\n");
2443
2444 Stack.Parameters.QueryDeviceText.DeviceTextType = DeviceTextLocationInformation;
2445 Stack.Parameters.QueryDeviceText.LocaleId = LocaleId;
2446 Status = IopInitiatePnpIrp(
2447 DeviceNode->PhysicalDeviceObject,
2448 &IoStatusBlock,
2449 IRP_MN_QUERY_DEVICE_TEXT,
2450 &Stack);
2451 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2452 {
2453 DPRINT("LocationInformation: %S\n", (PWSTR)IoStatusBlock.Information);
2454 RtlInitUnicodeString(&ValueName, L"LocationInformation");
2455 Status = ZwSetValueKey(InstanceKey,
2456 &ValueName,
2457 0,
2458 REG_SZ,
2459 (PVOID)IoStatusBlock.Information,
2460 (wcslen((PWSTR)IoStatusBlock.Information) + 1) * sizeof(WCHAR));
2461 if (!NT_SUCCESS(Status))
2462 {
2463 DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
2464 }
2465 }
2466 else
2467 {
2468 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2469 }
2470
2471 DPRINT("Sending IRP_MN_QUERY_BUS_INFORMATION to device stack\n");
2472
2473 Status = IopInitiatePnpIrp(
2474 DeviceNode->PhysicalDeviceObject,
2475 &IoStatusBlock,
2476 IRP_MN_QUERY_BUS_INFORMATION,
2477 NULL);
2478 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2479 {
2480 PPNP_BUS_INFORMATION BusInformation =
2481 (PPNP_BUS_INFORMATION)IoStatusBlock.Information;
2482
2483 DeviceNode->ChildBusNumber = BusInformation->BusNumber;
2484 DeviceNode->ChildInterfaceType = BusInformation->LegacyBusType;
2485 DeviceNode->ChildBusTypeIndex = IopGetBusTypeGuidIndex(&BusInformation->BusTypeGuid);
2486 ExFreePool(BusInformation);
2487 }
2488 else
2489 {
2490 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2491
2492 DeviceNode->ChildBusNumber = 0xFFFFFFF0;
2493 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
2494 DeviceNode->ChildBusTypeIndex = -1;
2495 }
2496
2497 DPRINT("Sending IRP_MN_QUERY_RESOURCES to device stack\n");
2498
2499 Status = IopInitiatePnpIrp(
2500 DeviceNode->PhysicalDeviceObject,
2501 &IoStatusBlock,
2502 IRP_MN_QUERY_RESOURCES,
2503 NULL);
2504 if (NT_SUCCESS(Status) && IoStatusBlock.Information)
2505 {
2506 DeviceNode->BootResources =
2507 (PCM_RESOURCE_LIST)IoStatusBlock.Information;
2508 IopDeviceNodeSetFlag(DeviceNode, DNF_HAS_BOOT_CONFIG);
2509 }
2510 else
2511 {
2512 DPRINT("IopInitiatePnpIrp() failed (Status %x) or IoStatusBlock.Information=NULL\n", Status);
2513 DeviceNode->BootResources = NULL;
2514 }
2515
2516 DPRINT("Sending IRP_MN_QUERY_RESOURCE_REQUIREMENTS to device stack\n");
2517
2518 Status = IopInitiatePnpIrp(
2519 DeviceNode->PhysicalDeviceObject,
2520 &IoStatusBlock,
2521 IRP_MN_QUERY_RESOURCE_REQUIREMENTS,
2522 NULL);
2523 if (NT_SUCCESS(Status))
2524 {
2525 DeviceNode->ResourceRequirements =
2526 (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
2527 if (IoStatusBlock.Information)
2528 IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_REPORTED);
2529 else
2530 IopDeviceNodeSetFlag(DeviceNode, DNF_NO_RESOURCE_REQUIRED);
2531 }
2532 else
2533 {
2534 DPRINT("IopInitiatePnpIrp() failed (Status %08lx)\n", Status);
2535 DeviceNode->ResourceRequirements = NULL;
2536 }
2537
2538
2539 if (InstanceKey != NULL)
2540 {
2541 IopSetDeviceInstanceData(InstanceKey, DeviceNode);
2542 }
2543
2544 ZwClose(InstanceKey);
2545
2546 IopDeviceNodeSetFlag(DeviceNode, DNF_PROCESSED);
2547
2548 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_LEGACY_DRIVER))
2549 {
2550 /* Report the device to the user-mode pnp manager */
2551 IopQueueTargetDeviceEvent(&GUID_DEVICE_ENUMERATED,
2552 &DeviceNode->InstancePath);
2553 }
2554
2555 return STATUS_SUCCESS;
2556 }
2557
2558
2559 NTSTATUS
2560 IopEnumerateDevice(
2561 IN PDEVICE_OBJECT DeviceObject)
2562 {
2563 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
2564 DEVICETREE_TRAVERSE_CONTEXT Context;
2565 PDEVICE_RELATIONS DeviceRelations;
2566 PDEVICE_OBJECT ChildDeviceObject;
2567 IO_STATUS_BLOCK IoStatusBlock;
2568 PDEVICE_NODE ChildDeviceNode;
2569 IO_STACK_LOCATION Stack;
2570 NTSTATUS Status;
2571 ULONG i;
2572
2573 DPRINT("DeviceObject 0x%p\n", DeviceObject);
2574
2575 DPRINT("Sending GUID_DEVICE_ARRIVAL\n");
2576
2577 /* Report the device to the user-mode pnp manager */
2578 IopQueueTargetDeviceEvent(&GUID_DEVICE_ARRIVAL,
2579 &DeviceNode->InstancePath);
2580
2581 DPRINT("Sending IRP_MN_QUERY_DEVICE_RELATIONS to device stack\n");
2582
2583 Stack.Parameters.QueryDeviceRelations.Type = BusRelations;
2584
2585 Status = IopInitiatePnpIrp(
2586 DeviceObject,
2587 &IoStatusBlock,
2588 IRP_MN_QUERY_DEVICE_RELATIONS,
2589 &Stack);
2590 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING)
2591 {
2592 DPRINT("IopInitiatePnpIrp() failed with status 0x%08lx\n", Status);
2593 return Status;
2594 }
2595
2596 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
2597
2598 if (!DeviceRelations)
2599 {
2600 DPRINT("No PDOs\n");
2601 return STATUS_UNSUCCESSFUL;
2602 }
2603
2604 DPRINT("Got %u PDOs\n", DeviceRelations->Count);
2605
2606 /*
2607 * Create device nodes for all discovered devices
2608 */
2609 for (i = 0; i < DeviceRelations->Count; i++)
2610 {
2611 ChildDeviceObject = DeviceRelations->Objects[i];
2612 ASSERT((ChildDeviceObject->Flags & DO_DEVICE_INITIALIZING) == 0);
2613
2614 ChildDeviceNode = IopGetDeviceNode(ChildDeviceObject);
2615 if (!ChildDeviceNode)
2616 {
2617 /* One doesn't exist, create it */
2618 Status = IopCreateDeviceNode(
2619 DeviceNode,
2620 ChildDeviceObject,
2621 NULL,
2622 &ChildDeviceNode);
2623 if (NT_SUCCESS(Status))
2624 {
2625 /* Mark the node as enumerated */
2626 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2627
2628 /* Mark the DO as bus enumerated */
2629 ChildDeviceObject->Flags |= DO_BUS_ENUMERATED_DEVICE;
2630 }
2631 else
2632 {
2633 /* Ignore this DO */
2634 DPRINT1("IopCreateDeviceNode() failed with status 0x%08x. Skipping PDO %u\n", Status, i);
2635 ObDereferenceObject(ChildDeviceNode);
2636 }
2637 }
2638 else
2639 {
2640 /* Mark it as enumerated */
2641 ChildDeviceNode->Flags |= DNF_ENUMERATED;
2642 ObDereferenceObject(ChildDeviceObject);
2643 }
2644 }
2645 ExFreePool(DeviceRelations);
2646
2647 /*
2648 * Retrieve information about all discovered children from the bus driver
2649 */
2650 IopInitDeviceTreeTraverseContext(
2651 &Context,
2652 DeviceNode,
2653 IopActionInterrogateDeviceStack,
2654 DeviceNode);
2655
2656 Status = IopTraverseDeviceTree(&Context);
2657 if (!NT_SUCCESS(Status))
2658 {
2659 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2660 return Status;
2661 }
2662
2663 /*
2664 * Retrieve configuration from the registry for discovered children
2665 */
2666 IopInitDeviceTreeTraverseContext(
2667 &Context,
2668 DeviceNode,
2669 IopActionConfigureChildServices,
2670 DeviceNode);
2671
2672 Status = IopTraverseDeviceTree(&Context);
2673 if (!NT_SUCCESS(Status))
2674 {
2675 DPRINT("IopTraverseDeviceTree() failed with status 0x%08lx\n", Status);
2676 return Status;
2677 }
2678
2679 /*
2680 * Initialize services for discovered children.
2681 */
2682 Status = IopInitializePnpServices(DeviceNode);
2683 if (!NT_SUCCESS(Status))
2684 {
2685 DPRINT("IopInitializePnpServices() failed with status 0x%08lx\n", Status);
2686 return Status;
2687 }
2688
2689 DPRINT("IopEnumerateDevice() finished\n");
2690 return STATUS_SUCCESS;
2691 }
2692
2693
2694 /*
2695 * IopActionConfigureChildServices
2696 *
2697 * Retrieve configuration for all (direct) child nodes of a parent node.
2698 *
2699 * Parameters
2700 * DeviceNode
2701 * Pointer to device node.
2702 * Context
2703 * Pointer to parent node to retrieve child node configuration for.
2704 *
2705 * Remarks
2706 * We only return a status code indicating an error (STATUS_UNSUCCESSFUL)
2707 * when we reach a device node which is not a direct child of the device
2708 * node for which we configure child services for. Any errors that occur is
2709 * logged instead so that all child services have a chance of beeing
2710 * configured.
2711 */
2712
2713 NTSTATUS
2714 IopActionConfigureChildServices(PDEVICE_NODE DeviceNode,
2715 PVOID Context)
2716 {
2717 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
2718 PDEVICE_NODE ParentDeviceNode;
2719 PUNICODE_STRING Service;
2720 UNICODE_STRING ClassGUID;
2721 NTSTATUS Status;
2722 DEVICE_CAPABILITIES DeviceCaps;
2723
2724 DPRINT("IopActionConfigureChildServices(%p, %p)\n", DeviceNode, Context);
2725
2726 ParentDeviceNode = (PDEVICE_NODE)Context;
2727
2728 /*
2729 * We are called for the parent too, but we don't need to do special
2730 * handling for this node
2731 */
2732 if (DeviceNode == ParentDeviceNode)
2733 {
2734 DPRINT("Success\n");
2735 return STATUS_SUCCESS;
2736 }
2737
2738 /*
2739 * Make sure this device node is a direct child of the parent device node
2740 * that is given as an argument
2741 */
2742 if (DeviceNode->Parent != ParentDeviceNode)
2743 {
2744 /* Stop the traversal immediately and indicate successful operation */
2745 DPRINT("Stop\n");
2746 return STATUS_UNSUCCESSFUL;
2747 }
2748
2749 if (!IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2750 {
2751 WCHAR RegKeyBuffer[MAX_PATH];
2752 UNICODE_STRING RegKey;
2753
2754 RegKey.Length = 0;
2755 RegKey.MaximumLength = sizeof(RegKeyBuffer);
2756 RegKey.Buffer = RegKeyBuffer;
2757
2758 /*
2759 * Retrieve configuration from Enum key
2760 */
2761
2762 Service = &DeviceNode->ServiceName;
2763
2764 RtlZeroMemory(QueryTable, sizeof(QueryTable));
2765 RtlInitUnicodeString(Service, NULL);
2766 RtlInitUnicodeString(&ClassGUID, NULL);
2767
2768 QueryTable[0].Name = L"Service";
2769 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
2770 QueryTable[0].EntryContext = Service;
2771
2772 QueryTable[1].Name = L"ClassGUID";
2773 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
2774 QueryTable[1].EntryContext = &ClassGUID;
2775 QueryTable[1].DefaultType = REG_SZ;
2776 QueryTable[1].DefaultData = L"";
2777 QueryTable[1].DefaultLength = 0;
2778
2779 RtlAppendUnicodeToString(&RegKey, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
2780 RtlAppendUnicodeStringToString(&RegKey, &DeviceNode->InstancePath);
2781
2782 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
2783 RegKey.Buffer, QueryTable, NULL, NULL);
2784
2785 if (!NT_SUCCESS(Status))
2786 {
2787 /* FIXME: Log the error */
2788 DPRINT("Could not retrieve configuration for device %wZ (Status 0x%08x)\n",
2789 &DeviceNode->InstancePath, Status);
2790 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2791 return STATUS_SUCCESS;
2792 }
2793
2794 if (Service->Buffer == NULL)
2795 {
2796 if (NT_SUCCESS(IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps)) &&
2797 DeviceCaps.RawDeviceOK)
2798 {
2799 DPRINT1("%wZ is using parent bus driver (%wZ)\n", &DeviceNode->InstancePath, &ParentDeviceNode->ServiceName);
2800
2801 DeviceNode->ServiceName.Length = 0;
2802 DeviceNode->ServiceName.MaximumLength = 0;
2803 DeviceNode->ServiceName.Buffer = NULL;
2804 }
2805 else if (ClassGUID.Length != 0)
2806 {
2807 /* Device has a ClassGUID value, but no Service value.
2808 * Suppose it is using the NULL driver, so state the
2809 * device is started */
2810 DPRINT1("%wZ is using NULL driver\n", &DeviceNode->InstancePath);
2811 IopDeviceNodeSetFlag(DeviceNode, DNF_STARTED);
2812 }
2813 else
2814 {
2815 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2816 }
2817 return STATUS_SUCCESS;
2818 }
2819
2820 DPRINT("Got Service %S\n", Service->Buffer);
2821 }
2822
2823 return STATUS_SUCCESS;
2824 }
2825
2826 /*
2827 * IopActionInitChildServices
2828 *
2829 * Initialize the service for all (direct) child nodes of a parent node
2830 *
2831 * Parameters
2832 * DeviceNode
2833 * Pointer to device node.
2834 * Context
2835 * Pointer to parent node to initialize child node services for.
2836 *
2837 * Remarks
2838 * If the driver image for a service is not loaded and initialized
2839 * it is done here too. We only return a status code indicating an
2840 * error (STATUS_UNSUCCESSFUL) when we reach a device node which is
2841 * not a direct child of the device node for which we initialize
2842 * child services for. Any errors that occur is logged instead so
2843 * that all child services have a chance of being initialized.
2844 */
2845
2846 NTSTATUS
2847 IopActionInitChildServices(PDEVICE_NODE DeviceNode,
2848 PVOID Context)
2849 {
2850 PDEVICE_NODE ParentDeviceNode;
2851 NTSTATUS Status;
2852 BOOLEAN BootDrivers = !PnpSystemInit;
2853
2854 DPRINT("IopActionInitChildServices(%p, %p)\n", DeviceNode, Context);
2855
2856 ParentDeviceNode = (PDEVICE_NODE)Context;
2857
2858 /*
2859 * We are called for the parent too, but we don't need to do special
2860 * handling for this node
2861 */
2862 if (DeviceNode == ParentDeviceNode)
2863 {
2864 DPRINT("Success\n");
2865 return STATUS_SUCCESS;
2866 }
2867
2868 /*
2869 * Make sure this device node is a direct child of the parent device node
2870 * that is given as an argument
2871 */
2872 #if 0
2873 if (DeviceNode->Parent != ParentDeviceNode)
2874 {
2875 /*
2876 * Stop the traversal immediately and indicate unsuccessful operation
2877 */
2878 DPRINT("Stop\n");
2879 return STATUS_UNSUCCESSFUL;
2880 }
2881 #endif
2882 if (IopDeviceNodeHasFlag(DeviceNode, DNF_STARTED) ||
2883 IopDeviceNodeHasFlag(DeviceNode, DNF_ADDED) ||
2884 IopDeviceNodeHasFlag(DeviceNode, DNF_DISABLED))
2885 return STATUS_SUCCESS;
2886
2887 if (DeviceNode->ServiceName.Buffer == NULL)
2888 {
2889 /* We don't need to worry about loading the driver because we're
2890 * being driven in raw mode so our parent must be loaded to get here */
2891 Status = IopStartDevice(DeviceNode);
2892 if (!NT_SUCCESS(Status))
2893 {
2894 DPRINT1("IopStartDevice(%wZ) failed with status 0x%08x\n",
2895 &DeviceNode->InstancePath, Status);
2896 }
2897 }
2898 else
2899 {
2900 PLDR_DATA_TABLE_ENTRY ModuleObject;
2901 PDRIVER_OBJECT DriverObject;
2902
2903 /* Get existing DriverObject pointer (in case the driver has
2904 already been loaded and initialized) */
2905 Status = IopGetDriverObject(
2906 &DriverObject,
2907 &DeviceNode->ServiceName,
2908 FALSE);
2909
2910 if (!NT_SUCCESS(Status))
2911 {
2912 /* Driver is not initialized, try to load it */
2913 Status = IopLoadServiceModule(&DeviceNode->ServiceName, &ModuleObject);
2914
2915 if (NT_SUCCESS(Status) || Status == STATUS_IMAGE_ALREADY_LOADED)
2916 {
2917 /* STATUS_IMAGE_ALREADY_LOADED means this driver
2918 was loaded by the bootloader */
2919 if ((Status != STATUS_IMAGE_ALREADY_LOADED) ||
2920 (Status == STATUS_IMAGE_ALREADY_LOADED && !DriverObject))
2921 {
2922 /* Initialize the driver */
2923 Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
2924 &DeviceNode->ServiceName, FALSE, &DriverObject);
2925 }
2926 else
2927 {
2928 Status = STATUS_SUCCESS;
2929 }
2930 }
2931 else
2932 {
2933 DPRINT1("IopLoadServiceModule(%wZ) failed with status 0x%08x\n",
2934 &DeviceNode->ServiceName, Status);
2935 }
2936 }
2937
2938 /* Driver is loaded and initialized at this point */
2939 if (NT_SUCCESS(Status))
2940 {
2941 /* Initialize the device, including all filters */
2942 Status = PipCallDriverAddDevice(DeviceNode, FALSE, DriverObject);
2943 }
2944 else
2945 {
2946 /*
2947 * Don't disable when trying to load only boot drivers
2948 */
2949 if (!BootDrivers)
2950 {
2951 IopDeviceNodeSetFlag(DeviceNode, DNF_DISABLED);
2952 IopDeviceNodeSetFlag(DeviceNode, DNF_START_FAILED);
2953 /* FIXME: Log the error (possibly in IopInitializeDeviceNodeService) */
2954 DPRINT1("Initialization of service %S failed (Status %x)\n",
2955 DeviceNode->ServiceName.Buffer, Status);
2956 }
2957 }
2958 }
2959
2960 return STATUS_SUCCESS;
2961 }
2962
2963 /*
2964 * IopInitializePnpServices
2965 *
2966 * Initialize services for discovered children
2967 *
2968 * Parameters
2969 * DeviceNode
2970 * Top device node to start initializing services.
2971 *
2972 * Return Value
2973 * Status
2974 */
2975 NTSTATUS
2976 IopInitializePnpServices(IN PDEVICE_NODE DeviceNode)
2977 {
2978 DEVICETREE_TRAVERSE_CONTEXT Context;
2979
2980 DPRINT("IopInitializePnpServices(%p)\n", DeviceNode);
2981
2982 IopInitDeviceTreeTraverseContext(
2983 &Context,
2984 DeviceNode,
2985 IopActionInitChildServices,
2986 DeviceNode);
2987
2988 return IopTraverseDeviceTree(&Context);
2989 }
2990
2991 static NTSTATUS INIT_FUNCTION
2992 IopEnumerateDetectedDevices(
2993 IN HANDLE hBaseKey,
2994 IN PUNICODE_STRING RelativePath OPTIONAL,
2995 IN HANDLE hRootKey,
2996 IN BOOLEAN EnumerateSubKeys,
2997 IN PCM_FULL_RESOURCE_DESCRIPTOR ParentBootResources,
2998 IN ULONG ParentBootResourcesLength)
2999 {
3000 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3001 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3002 UNICODE_STRING ConfigurationDataU = RTL_CONSTANT_STRING(L"Configuration Data");
3003 UNICODE_STRING BootConfigU = RTL_CONSTANT_STRING(L"BootConfig");
3004 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3005 OBJECT_ATTRIBUTES ObjectAttributes;
3006 HANDLE hDevicesKey = NULL;
3007 HANDLE hDeviceKey = NULL;
3008 HANDLE hLevel1Key, hLevel2Key = NULL, hLogConf;
3009 UNICODE_STRING Level2NameU;
3010 WCHAR Level2Name[5];
3011 ULONG IndexDevice = 0;
3012 ULONG IndexSubKey;
3013 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3014 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3015 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3016 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3017 UNICODE_STRING DeviceName, ValueName;
3018 ULONG RequiredSize;
3019 PCM_FULL_RESOURCE_DESCRIPTOR BootResources = NULL;
3020 ULONG BootResourcesLength;
3021 NTSTATUS Status;
3022
3023 const UNICODE_STRING IdentifierPci = RTL_CONSTANT_STRING(L"PCI");
3024 UNICODE_STRING HardwareIdPci = RTL_CONSTANT_STRING(L"*PNP0A03\0");
3025 static ULONG DeviceIndexPci = 0;
3026 const UNICODE_STRING IdentifierSerial = RTL_CONSTANT_STRING(L"SerialController");
3027 UNICODE_STRING HardwareIdSerial = RTL_CONSTANT_STRING(L"*PNP0501\0");
3028 static ULONG DeviceIndexSerial = 0;
3029 const UNICODE_STRING IdentifierKeyboard = RTL_CONSTANT_STRING(L"KeyboardController");
3030 UNICODE_STRING HardwareIdKeyboard = RTL_CONSTANT_STRING(L"*PNP0303\0");
3031 static ULONG DeviceIndexKeyboard = 0;
3032 const UNICODE_STRING IdentifierMouse = RTL_CONSTANT_STRING(L"PointerController");
3033 UNICODE_STRING HardwareIdMouse = RTL_CONSTANT_STRING(L"*PNP0F13\0");
3034 static ULONG DeviceIndexMouse = 0;
3035 const UNICODE_STRING IdentifierParallel = RTL_CONSTANT_STRING(L"ParallelController");
3036 UNICODE_STRING HardwareIdParallel = RTL_CONSTANT_STRING(L"*PNP0400\0");
3037 static ULONG DeviceIndexParallel = 0;
3038 const UNICODE_STRING IdentifierFloppy = RTL_CONSTANT_STRING(L"FloppyDiskPeripheral");
3039 UNICODE_STRING HardwareIdFloppy = RTL_CONSTANT_STRING(L"*PNP0700\0");
3040 static ULONG DeviceIndexFloppy = 0;
3041 const UNICODE_STRING IdentifierIsa = RTL_CONSTANT_STRING(L"ISA");
3042 UNICODE_STRING HardwareIdIsa = RTL_CONSTANT_STRING(L"*PNP0A00\0");
3043 static ULONG DeviceIndexIsa = 0;
3044 UNICODE_STRING HardwareIdKey;
3045 PUNICODE_STRING pHardwareId;
3046 ULONG DeviceIndex = 0;
3047 PUCHAR CmResourceList;
3048 ULONG ListCount;
3049
3050 if (RelativePath)
3051 {
3052 Status = IopOpenRegistryKeyEx(&hDevicesKey, hBaseKey, RelativePath, KEY_ENUMERATE_SUB_KEYS);
3053 if (!NT_SUCCESS(Status))
3054 {
3055 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3056 goto cleanup;
3057 }
3058 }
3059 else
3060 hDevicesKey = hBaseKey;
3061
3062 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3063 if (!pDeviceInformation)
3064 {
3065 DPRINT("ExAllocatePool() failed\n");
3066 Status = STATUS_NO_MEMORY;
3067 goto cleanup;
3068 }
3069
3070 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3071 if (!pValueInformation)
3072 {
3073 DPRINT("ExAllocatePool() failed\n");
3074 Status = STATUS_NO_MEMORY;
3075 goto cleanup;
3076 }
3077
3078 while (TRUE)
3079 {
3080 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3081 if (Status == STATUS_NO_MORE_ENTRIES)
3082 break;
3083 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3084 {
3085 ExFreePool(pDeviceInformation);
3086 DeviceInfoLength = RequiredSize;
3087 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3088 if (!pDeviceInformation)
3089 {
3090 DPRINT("ExAllocatePool() failed\n");
3091 Status = STATUS_NO_MEMORY;
3092 goto cleanup;
3093 }
3094 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3095 }
3096 if (!NT_SUCCESS(Status))
3097 {
3098 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3099 goto cleanup;
3100 }
3101 IndexDevice++;
3102
3103 /* Open device key */
3104 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3105 DeviceName.Buffer = pDeviceInformation->Name;
3106
3107 Status = IopOpenRegistryKeyEx(&hDeviceKey, hDevicesKey, &DeviceName,
3108 KEY_QUERY_VALUE + (EnumerateSubKeys ? KEY_ENUMERATE_SUB_KEYS : 0));
3109 if (!NT_SUCCESS(Status))
3110 {
3111 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3112 goto cleanup;
3113 }
3114
3115 /* Read boot resources, and add then to parent ones */
3116 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3117 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3118 {
3119 ExFreePool(pValueInformation);
3120 ValueInfoLength = RequiredSize;
3121 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3122 if (!pValueInformation)
3123 {
3124 DPRINT("ExAllocatePool() failed\n");
3125 ZwDeleteKey(hLevel2Key);
3126 Status = STATUS_NO_MEMORY;
3127 goto cleanup;
3128 }
3129 Status = ZwQueryValueKey(hDeviceKey, &ConfigurationDataU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3130 }
3131 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3132 {
3133 BootResources = ParentBootResources;
3134 BootResourcesLength = ParentBootResourcesLength;
3135 }
3136 else if (!NT_SUCCESS(Status))
3137 {
3138 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3139 goto nextdevice;
3140 }
3141 else if (pValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR)
3142 {
3143 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_FULL_RESOURCE_DESCRIPTOR);
3144 goto nextdevice;
3145 }
3146 else
3147 {
3148 static const ULONG Header = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors);
3149
3150 /* Concatenate current resources and parent ones */
3151 if (ParentBootResourcesLength == 0)
3152 BootResourcesLength = pValueInformation->DataLength;
3153 else
3154 BootResourcesLength = ParentBootResourcesLength
3155 + pValueInformation->DataLength
3156 - Header;
3157 BootResources = ExAllocatePool(PagedPool, BootResourcesLength);
3158 if (!BootResources)
3159 {
3160 DPRINT("ExAllocatePool() failed\n");
3161 goto nextdevice;
3162 }
3163 if (ParentBootResourcesLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3164 {
3165 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3166 }
3167 else if (ParentBootResources->PartialResourceList.PartialDescriptors[ParentBootResources->PartialResourceList.Count - 1].Type == CmResourceTypeDeviceSpecific)
3168 {
3169 RtlCopyMemory(BootResources, pValueInformation->Data, pValueInformation->DataLength);
3170 RtlCopyMemory(
3171 (PVOID)((ULONG_PTR)BootResources + pValueInformation->DataLength),
3172 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3173 ParentBootResourcesLength - Header);
3174 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3175 }
3176 else
3177 {
3178 RtlCopyMemory(BootResources, pValueInformation->Data, Header);
3179 RtlCopyMemory(
3180 (PVOID)((ULONG_PTR)BootResources + Header),
3181 (PVOID)((ULONG_PTR)ParentBootResources + Header),
3182 ParentBootResourcesLength - Header);
3183 RtlCopyMemory(
3184 (PVOID)((ULONG_PTR)BootResources + ParentBootResourcesLength),
3185 pValueInformation->Data + Header,
3186 pValueInformation->DataLength - Header);
3187 BootResources->PartialResourceList.Count += ParentBootResources->PartialResourceList.Count;
3188 }
3189 }
3190
3191 if (EnumerateSubKeys)
3192 {
3193 IndexSubKey = 0;
3194 while (TRUE)
3195 {
3196 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3197 if (Status == STATUS_NO_MORE_ENTRIES)
3198 break;
3199 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3200 {
3201 ExFreePool(pDeviceInformation);
3202 DeviceInfoLength = RequiredSize;
3203 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3204 if (!pDeviceInformation)
3205 {
3206 DPRINT("ExAllocatePool() failed\n");
3207 Status = STATUS_NO_MEMORY;
3208 goto cleanup;
3209 }
3210 Status = ZwEnumerateKey(hDeviceKey, IndexSubKey, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3211 }
3212 if (!NT_SUCCESS(Status))
3213 {
3214 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3215 goto cleanup;
3216 }
3217 IndexSubKey++;
3218 DeviceName.Length = DeviceName.MaximumLength = (USHORT)pDeviceInformation->NameLength;
3219 DeviceName.Buffer = pDeviceInformation->Name;
3220
3221 Status = IopEnumerateDetectedDevices(
3222 hDeviceKey,
3223 &DeviceName,
3224 hRootKey,
3225 TRUE,
3226 BootResources,
3227 BootResourcesLength);
3228 if (!NT_SUCCESS(Status))
3229 goto cleanup;
3230 }
3231 }
3232
3233 /* Read identifier */
3234 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3235 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3236 {
3237 ExFreePool(pValueInformation);
3238 ValueInfoLength = RequiredSize;
3239 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3240 if (!pValueInformation)
3241 {
3242 DPRINT("ExAllocatePool() failed\n");
3243 Status = STATUS_NO_MEMORY;
3244 goto cleanup;
3245 }
3246 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3247 }
3248 if (!NT_SUCCESS(Status))
3249 {
3250 if (Status != STATUS_OBJECT_NAME_NOT_FOUND)
3251 {
3252 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3253 goto nextdevice;
3254 }
3255 ValueName.Length = ValueName.MaximumLength = 0;
3256 }
3257 else if (pValueInformation->Type != REG_SZ)
3258 {
3259 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3260 goto nextdevice;
3261 }
3262 else
3263 {
3264 /* Assign hardware id to this device */
3265 ValueName.Length = ValueName.MaximumLength = (USHORT)pValueInformation->DataLength;
3266 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3267 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3268 ValueName.Length -= sizeof(WCHAR);
3269 }
3270
3271 if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierSerial, FALSE) == 0)
3272 {
3273 pHardwareId = &HardwareIdSerial;
3274 DeviceIndex = DeviceIndexSerial++;
3275 }
3276 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierKeyboard, FALSE) == 0)
3277 {
3278 pHardwareId = &HardwareIdKeyboard;
3279 DeviceIndex = DeviceIndexKeyboard++;
3280 }
3281 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierMouse, FALSE) == 0)
3282 {
3283 pHardwareId = &HardwareIdMouse;
3284 DeviceIndex = DeviceIndexMouse++;
3285 }
3286 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierParallel, FALSE) == 0)
3287 {
3288 pHardwareId = &HardwareIdParallel;
3289 DeviceIndex = DeviceIndexParallel++;
3290 }
3291 else if (RelativePath && RtlCompareUnicodeString(RelativePath, &IdentifierFloppy, FALSE) == 0)
3292 {
3293 pHardwareId = &HardwareIdFloppy;
3294 DeviceIndex = DeviceIndexFloppy++;
3295 }
3296 else if (NT_SUCCESS(Status))
3297 {
3298 /* Try to also match the device identifier */
3299 if (RtlCompareUnicodeString(&ValueName, &IdentifierPci, FALSE) == 0)
3300 {
3301 pHardwareId = &HardwareIdPci;
3302 DeviceIndex = DeviceIndexPci++;
3303 }
3304 else if (RtlCompareUnicodeString(&ValueName, &IdentifierIsa, FALSE) == 0)
3305 {
3306 pHardwareId = &HardwareIdIsa;
3307 DeviceIndex = DeviceIndexIsa++;
3308 }
3309 else
3310 {
3311 DPRINT("Unknown device '%wZ'\n", &ValueName);
3312 goto nextdevice;
3313 }
3314 }
3315 else
3316 {
3317 /* Unknown key path */
3318 DPRINT("Unknown key path '%wZ'\n", RelativePath);
3319 goto nextdevice;
3320 }
3321
3322 /* Prepare hardware id key (hardware id value without final \0) */
3323 HardwareIdKey = *pHardwareId;
3324 HardwareIdKey.Length -= sizeof(UNICODE_NULL);
3325
3326 /* Add the detected device to Root key */
3327 InitializeObjectAttributes(&ObjectAttributes, &HardwareIdKey, OBJ_KERNEL_HANDLE, hRootKey, NULL);
3328 Status = ZwCreateKey(
3329 &hLevel1Key,
3330 KEY_CREATE_SUB_KEY,
3331 &ObjectAttributes,
3332 0,
3333 NULL,
3334 REG_OPTION_NON_VOLATILE,
3335 NULL);
3336 if (!NT_SUCCESS(Status))
3337 {
3338 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3339 goto nextdevice;
3340 }
3341 swprintf(Level2Name, L"%04lu", DeviceIndex);
3342 RtlInitUnicodeString(&Level2NameU, Level2Name);
3343 InitializeObjectAttributes(&ObjectAttributes, &Level2NameU, OBJ_KERNEL_HANDLE, hLevel1Key, NULL);
3344 Status = ZwCreateKey(
3345 &hLevel2Key,
3346 KEY_SET_VALUE | KEY_CREATE_SUB_KEY,
3347 &ObjectAttributes,
3348 0,
3349 NULL,
3350 REG_OPTION_NON_VOLATILE,
3351 NULL);
3352 ZwClose(hLevel1Key);
3353 if (!NT_SUCCESS(Status))
3354 {
3355 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3356 goto nextdevice;
3357 }
3358 DPRINT("Found %wZ #%lu (%wZ)\n", &ValueName, DeviceIndex, &HardwareIdKey);
3359 Status = ZwSetValueKey(hLevel2Key, &HardwareIDU, 0, REG_MULTI_SZ, pHardwareId->Buffer, pHardwareId->MaximumLength);
3360 if (!NT_SUCCESS(Status))
3361 {
3362 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3363 ZwDeleteKey(hLevel2Key);
3364 goto nextdevice;
3365 }
3366 /* Create 'LogConf' subkey */
3367 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE, hLevel2Key, NULL);
3368 Status = ZwCreateKey(
3369 &hLogConf,
3370 KEY_SET_VALUE,
3371 &ObjectAttributes,
3372 0,
3373 NULL,
3374 REG_OPTION_VOLATILE,
3375 NULL);
3376 if (!NT_SUCCESS(Status))
3377 {
3378 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status);
3379 ZwDeleteKey(hLevel2Key);
3380 goto nextdevice;
3381 }
3382 if (BootResourcesLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
3383 {
3384 CmResourceList = ExAllocatePool(PagedPool, BootResourcesLength + sizeof(ULONG));
3385 if (!CmResourceList)
3386 {
3387 ZwClose(hLogConf);
3388 ZwDeleteKey(hLevel2Key);
3389 goto nextdevice;
3390 }
3391
3392 /* Add the list count (1st member of CM_RESOURCE_LIST) */
3393 ListCount = 1;
3394 RtlCopyMemory(CmResourceList,
3395 &ListCount,
3396 sizeof(ULONG));
3397
3398 /* Now add the actual list (2nd member of CM_RESOURCE_LIST) */
3399 RtlCopyMemory(CmResourceList + sizeof(ULONG),
3400 BootResources,
3401 BootResourcesLength);
3402
3403 /* Save boot resources to 'LogConf\BootConfig' */
3404 Status = ZwSetValueKey(hLogConf, &BootConfigU, 0, REG_RESOURCE_LIST, CmResourceList, BootResourcesLength + sizeof(ULONG));
3405 if (!NT_SUCCESS(Status))
3406 {
3407 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status);
3408 ZwClose(hLogConf);
3409 ZwDeleteKey(hLevel2Key);
3410 goto nextdevice;
3411 }
3412 }
3413 ZwClose(hLogConf);
3414
3415 nextdevice:
3416 if (BootResources && BootResources != ParentBootResources)
3417 {
3418 ExFreePool(BootResources);
3419 BootResources = NULL;
3420 }
3421 if (hLevel2Key)
3422 {
3423 ZwClose(hLevel2Key);
3424 hLevel2Key = NULL;
3425 }
3426 if (hDeviceKey)
3427 {
3428 ZwClose(hDeviceKey);
3429 hDeviceKey = NULL;
3430 }
3431 }
3432
3433 Status = STATUS_SUCCESS;
3434
3435 cleanup:
3436 if (hDevicesKey && hDevicesKey != hBaseKey)
3437 ZwClose(hDevicesKey);
3438 if (hDeviceKey)
3439 ZwClose(hDeviceKey);
3440 if (pDeviceInformation)
3441 ExFreePool(pDeviceInformation);
3442 if (pValueInformation)
3443 ExFreePool(pValueInformation);
3444 return Status;
3445 }
3446
3447 static BOOLEAN INIT_FUNCTION
3448 IopIsAcpiComputer(VOID)
3449 {
3450 #ifndef ENABLE_ACPI
3451 return FALSE;
3452 #else
3453 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3454 UNICODE_STRING IdentifierU = RTL_CONSTANT_STRING(L"Identifier");
3455 UNICODE_STRING AcpiBiosIdentifier = RTL_CONSTANT_STRING(L"ACPI BIOS");
3456 OBJECT_ATTRIBUTES ObjectAttributes;
3457 PKEY_BASIC_INFORMATION pDeviceInformation = NULL;
3458 ULONG DeviceInfoLength = sizeof(KEY_BASIC_INFORMATION) + 50 * sizeof(WCHAR);
3459 PKEY_VALUE_PARTIAL_INFORMATION pValueInformation = NULL;
3460 ULONG ValueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 50 * sizeof(WCHAR);
3461 ULONG RequiredSize;
3462 ULONG IndexDevice = 0;
3463 UNICODE_STRING DeviceName, ValueName;
3464 HANDLE hDevicesKey = NULL;
3465 HANDLE hDeviceKey = NULL;
3466 NTSTATUS Status;
3467 BOOLEAN ret = FALSE;
3468
3469 InitializeObjectAttributes(&ObjectAttributes, &MultiKeyPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3470 Status = ZwOpenKey(&hDevicesKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
3471 if (!NT_SUCCESS(Status))
3472 {
3473 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3474 goto cleanup;
3475 }
3476
3477 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3478 if (!pDeviceInformation)
3479 {
3480 DPRINT("ExAllocatePool() failed\n");
3481 Status = STATUS_NO_MEMORY;
3482 goto cleanup;
3483 }
3484
3485 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3486 if (!pDeviceInformation)
3487 {
3488 DPRINT("ExAllocatePool() failed\n");
3489 Status = STATUS_NO_MEMORY;
3490 goto cleanup;
3491 }
3492
3493 while (TRUE)
3494 {
3495 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3496 if (Status == STATUS_NO_MORE_ENTRIES)
3497 break;
3498 else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3499 {
3500 ExFreePool(pDeviceInformation);
3501 DeviceInfoLength = RequiredSize;
3502 pDeviceInformation = ExAllocatePool(PagedPool, DeviceInfoLength);
3503 if (!pDeviceInformation)
3504 {
3505 DPRINT("ExAllocatePool() failed\n");
3506 Status = STATUS_NO_MEMORY;
3507 goto cleanup;
3508 }
3509 Status = ZwEnumerateKey(hDevicesKey, IndexDevice, KeyBasicInformation, pDeviceInformation, DeviceInfoLength, &RequiredSize);
3510 }
3511 if (!NT_SUCCESS(Status))
3512 {
3513 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status);
3514 goto cleanup;
3515 }
3516 IndexDevice++;
3517
3518 /* Open device key */
3519 DeviceName.Length = DeviceName.MaximumLength = pDeviceInformation->NameLength;
3520 DeviceName.Buffer = pDeviceInformation->Name;
3521 InitializeObjectAttributes(&ObjectAttributes, &DeviceName, OBJ_KERNEL_HANDLE, hDevicesKey, NULL);
3522 Status = ZwOpenKey(
3523 &hDeviceKey,
3524 KEY_QUERY_VALUE,
3525 &ObjectAttributes);
3526 if (!NT_SUCCESS(Status))
3527 {
3528 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3529 goto cleanup;
3530 }
3531
3532 /* Read identifier */
3533 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3534 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
3535 {
3536 ExFreePool(pValueInformation);
3537 ValueInfoLength = RequiredSize;
3538 pValueInformation = ExAllocatePool(PagedPool, ValueInfoLength);
3539 if (!pValueInformation)
3540 {
3541 DPRINT("ExAllocatePool() failed\n");
3542 Status = STATUS_NO_MEMORY;
3543 goto cleanup;
3544 }
3545 Status = ZwQueryValueKey(hDeviceKey, &IdentifierU, KeyValuePartialInformation, pValueInformation, ValueInfoLength, &RequiredSize);
3546 }
3547 if (!NT_SUCCESS(Status))
3548 {
3549 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status);
3550 goto nextdevice;
3551 }
3552 else if (pValueInformation->Type != REG_SZ)
3553 {
3554 DPRINT("Wrong registry type: got 0x%lx, expected 0x%lx\n", pValueInformation->Type, REG_SZ);
3555 goto nextdevice;
3556 }
3557
3558 ValueName.Length = ValueName.MaximumLength = pValueInformation->DataLength;
3559 ValueName.Buffer = (PWCHAR)pValueInformation->Data;
3560 if (ValueName.Length >= sizeof(WCHAR) && ValueName.Buffer[ValueName.Length / sizeof(WCHAR) - 1] == UNICODE_NULL)
3561 ValueName.Length -= sizeof(WCHAR);
3562 if (RtlCompareUnicodeString(&ValueName, &AcpiBiosIdentifier, FALSE) == 0)
3563 {
3564 DPRINT("Found ACPI BIOS\n");
3565 ret = TRUE;
3566 goto cleanup;
3567 }
3568
3569 nextdevice:
3570 ZwClose(hDeviceKey);
3571 hDeviceKey = NULL;
3572 }
3573
3574 cleanup:
3575 if (pDeviceInformation)
3576 ExFreePool(pDeviceInformation);
3577 if (pValueInformation)
3578 ExFreePool(pValueInformation);
3579 if (hDevicesKey)
3580 ZwClose(hDevicesKey);
3581 if (hDeviceKey)
3582 ZwClose(hDeviceKey);
3583 return ret;
3584 #endif
3585 }
3586
3587 NTSTATUS
3588 NTAPI
3589 IopUpdateRootKey(VOID)
3590 {
3591 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Enum");
3592 UNICODE_STRING RootPathU = RTL_CONSTANT_STRING(L"Root");
3593 UNICODE_STRING MultiKeyPathU = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter");
3594 UNICODE_STRING DeviceDescU = RTL_CONSTANT_STRING(L"DeviceDesc");
3595 UNICODE_STRING HardwareIDU = RTL_CONSTANT_STRING(L"HardwareID");
3596 UNICODE_STRING LogConfU = RTL_CONSTANT_STRING(L"LogConf");
3597 UNICODE_STRING HalAcpiDevice = RTL_CONSTANT_STRING(L"ACPI_HAL");
3598 UNICODE_STRING HalAcpiId = RTL_CONSTANT_STRING(L"0000");
3599 UNICODE_STRING HalAcpiDeviceDesc = RTL_CONSTANT_STRING(L"HAL ACPI");
3600 UNICODE_STRING HalAcpiHardwareID = RTL_CONSTANT_STRING(L"*PNP0C08\0");
3601 OBJECT_ATTRIBUTES ObjectAttributes;
3602 HANDLE hEnum, hRoot, hHalAcpiDevice, hHalAcpiId, hLogConf;
3603 NTSTATUS Status;
3604
3605 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
3606 Status = ZwCreateKey(&hEnum, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3607 if (!NT_SUCCESS(Status))
3608 {
3609 DPRINT1("ZwCreateKey() failed with status 0x%08lx\n", Status);
3610 return Status;
3611 }
3612
3613 InitializeObjectAttributes(&ObjectAttributes, &RootPathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hEnum, NULL);
3614 Status = ZwCreateKey(&hRoot, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3615 ZwClose(hEnum);
3616 if (!NT_SUCCESS(Status))
3617 {
3618 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status);
3619 return Status;
3620 }
3621
3622 if (IopIsAcpiComputer())
3623 {
3624 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiDevice, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hRoot, NULL);
3625 Status = ZwCreateKey(&hHalAcpiDevice, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3626 ZwClose(hRoot);
3627 if (!NT_SUCCESS(Status))
3628 return Status;
3629 InitializeObjectAttributes(&ObjectAttributes, &HalAcpiId, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiDevice, NULL);
3630 Status = ZwCreateKey(&hHalAcpiId, KEY_CREATE_SUB_KEY, &ObjectAttributes, 0, NULL, 0, NULL);
3631 ZwClose(hHalAcpiDevice);
3632 if (!NT_SUCCESS(Status))
3633 return Status;
3634 Status = ZwSetValueKey(hHalAcpiId, &DeviceDescU, 0, REG_SZ, HalAcpiDeviceDesc.Buffer, HalAcpiDeviceDesc.MaximumLength);
3635 if (NT_SUCCESS(Status))
3636 Status = ZwSetValueKey(hHalAcpiId, &HardwareIDU, 0, REG_MULTI_SZ, HalAcpiHardwareID.Buffer, HalAcpiHardwareID.MaximumLength);
3637 if (NT_SUCCESS(Status))
3638 {
3639 InitializeObjectAttributes(&ObjectAttributes, &LogConfU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hHalAcpiId, NULL);
3640 Status = ZwCreateKey(&hLogConf, 0, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
3641 if (NT_SUCCESS(Status))
3642 ZwClose(hLogConf);
3643 }
3644 ZwClose(hHalAcpiId);
3645 return Status;
3646 }
3647 else
3648 {
3649 Status = IopOpenRegistryKeyEx(&hEnum, NULL, &MultiKeyPathU, KEY_ENUMERATE_SUB_KEYS);
3650 if (!NT_SUCCESS(Status))
3651 {
3652 /* Nothing to do, don't return with an error status */
3653 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status);
3654 ZwClose(hRoot);
3655 return STATUS_SUCCESS;
3656 }
3657 Status = IopEnumerateDetectedDevices(
3658 hEnum,
3659 NULL,
3660 hRoot,
3661 TRUE,
3662 NULL,
3663 0);
3664 ZwClose(hEnum);
3665 ZwClose(hRoot);
3666 return Status;
3667 }
3668 }
3669
3670 NTSTATUS
3671 NTAPI
3672 IopOpenRegistryKeyEx(PHANDLE KeyHandle,
3673 HANDLE ParentKey,
3674 PUNICODE_STRING Name,
3675 ACCESS_MASK DesiredAccess)
3676 {
3677 OBJECT_ATTRIBUTES ObjectAttributes;
3678 NTSTATUS Status;
3679
3680 PAGED_CODE();
3681
3682 *KeyHandle = NULL;
3683
3684 InitializeObjectAttributes(&ObjectAttributes,
3685 Name,
3686 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3687 ParentKey,
3688 NULL);
3689
3690 Status = ZwOpenKey(KeyHandle, DesiredAccess, &ObjectAttributes);
3691
3692 return Status;
3693 }
3694
3695 NTSTATUS
3696 NTAPI
3697 IopCreateRegistryKeyEx(OUT PHANDLE Handle,
3698 IN HANDLE RootHandle OPTIONAL,
3699 IN PUNICODE_STRING KeyName,
3700 IN ACCESS_MASK DesiredAccess,
3701 IN ULONG CreateOptions,
3702 OUT PULONG Disposition OPTIONAL)
3703 {
3704 OBJECT_ATTRIBUTES ObjectAttributes;
3705 ULONG KeyDisposition, RootHandleIndex = 0, i = 1, NestedCloseLevel = 0, Length;
3706 HANDLE HandleArray[2];
3707 BOOLEAN Recursing = TRUE;
3708 PWCHAR pp, p, p1;
3709 UNICODE_STRING KeyString;
3710 NTSTATUS Status = STATUS_SUCCESS;
3711 PAGED_CODE();
3712
3713 /* P1 is start, pp is end */
3714 p1 = KeyName->Buffer;
3715 pp = (PVOID)((ULONG_PTR)p1 + KeyName->Length);
3716
3717 /* Create the target key */
3718 InitializeObjectAttributes(&ObjectAttributes,
3719 KeyName,
3720 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3721 RootHandle,
3722 NULL);
3723 Status = ZwCreateKey(&HandleArray[i],
3724 DesiredAccess,
3725 &ObjectAttributes,
3726 0,
3727 NULL,
3728 CreateOptions,
3729 &KeyDisposition);
3730
3731 /* Now we check if this failed */
3732 if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) && (RootHandle))
3733 {
3734 /* Target key failed, so we'll need to create its parent. Setup array */
3735 HandleArray[0] = NULL;
3736 HandleArray[1] = RootHandle;
3737
3738 /* Keep recursing for each missing parent */
3739 while (Recursing)
3740 {
3741 /* And if we're deep enough, close the last handle */
3742 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3743
3744 /* We're setup to ping-pong between the two handle array entries */
3745 RootHandleIndex = i;
3746 i = (i + 1) & 1;
3747
3748 /* Clear the one we're attempting to open now */
3749 HandleArray[i] = NULL;
3750
3751 /* Process the parent key name */
3752 for (p = p1; ((p < pp) && (*p != OBJ_NAME_PATH_SEPARATOR)); p++);
3753 Length = (p - p1) * sizeof(WCHAR);
3754
3755 /* Is there a parent name? */
3756 if (Length)
3757 {
3758 /* Build the unicode string for it */
3759 KeyString.Buffer = p1;
3760 KeyString.Length = KeyString.MaximumLength = Length;
3761
3762 /* Now try opening the parent */
3763 InitializeObjectAttributes(&ObjectAttributes,
3764 &KeyString,
3765 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
3766 HandleArray[RootHandleIndex],
3767 NULL);
3768 Status = ZwCreateKey(&HandleArray[i],
3769 DesiredAccess,
3770 &ObjectAttributes,
3771 0,
3772 NULL,
3773 CreateOptions,
3774 &KeyDisposition);
3775 if (NT_SUCCESS(Status))
3776 {
3777 /* It worked, we have one more handle */
3778 NestedCloseLevel++;
3779 }
3780 else
3781 {
3782 /* Parent key creation failed, abandon loop */
3783 Recursing = FALSE;
3784 continue;
3785 }
3786 }
3787 else
3788 {
3789 /* We don't have a parent name, probably corrupted key name */
3790 Status = STATUS_INVALID_PARAMETER;
3791 Recursing = FALSE;
3792 continue;
3793 }
3794
3795 /* Now see if there's more parents to create */
3796 p1 = p + 1;
3797 if ((p == pp) || (p1 == pp))
3798 {
3799 /* We're done, hopefully successfully, so stop */
3800 Recursing = FALSE;
3801 }
3802 }
3803
3804 /* Outer loop check for handle nesting that requires closing the top handle */
3805 if (NestedCloseLevel > 1) ZwClose(HandleArray[RootHandleIndex]);
3806 }
3807
3808 /* Check if we broke out of the loop due to success */
3809 if (NT_SUCCESS(Status))
3810 {
3811 /* Return the target handle (we closed all the parent ones) and disposition */
3812 *Handle = HandleArray[i];
3813 if (Disposition) *Disposition = KeyDisposition;
3814 }
3815
3816 /* Return the success state */
3817 return Status;
3818 }
3819
3820 NTSTATUS
3821 NTAPI
3822 IopGetRegistryValue(IN HANDLE Handle,
3823 IN PWSTR ValueName,
3824 OUT PKEY_VALUE_FULL_INFORMATION *Information)
3825 {
3826 UNICODE_STRING ValueString;
3827 NTSTATUS Status;
3828 PKEY_VALUE_FULL_INFORMATION FullInformation;
3829 ULONG Size;
3830 PAGED_CODE();
3831
3832 RtlInitUnicodeString(&ValueString, ValueName);
3833
3834 Status = ZwQueryValueKey(Handle,
3835 &ValueString,
3836 KeyValueFullInformation,
3837 NULL,
3838 0,
3839 &Size);
3840 if ((Status != STATUS_BUFFER_OVERFLOW) &&
3841 (Status != STATUS_BUFFER_TOO_SMALL))
3842 {
3843 return Status;
3844 }
3845
3846 FullInformation = ExAllocatePool(NonPagedPool, Size);
3847 if (!FullInformation) return STATUS_INSUFFICIENT_RESOURCES;
3848
3849 Status = ZwQueryValueKey(Handle,
3850 &ValueString,
3851 KeyValueFullInformation,
3852 FullInformation,
3853 Size,
3854 &Size);
3855 if (!NT_SUCCESS(Status))
3856 {
3857 ExFreePool(FullInformation);
3858 return Status;
3859 }
3860
3861 *Information = FullInformation;
3862 return STATUS_SUCCESS;
3863 }
3864
3865 RTL_GENERIC_COMPARE_RESULTS
3866 NTAPI
3867 PiCompareInstancePath(IN PRTL_AVL_TABLE Table,
3868 IN PVOID FirstStruct,
3869 IN PVOID SecondStruct)
3870 {
3871 /* FIXME: TODO */
3872 ASSERT(FALSE);
3873 return 0;
3874 }
3875
3876 //
3877 // The allocation function is called by the generic table package whenever
3878 // it needs to allocate memory for the table.
3879 //
3880
3881 PVOID
3882 NTAPI
3883 PiAllocateGenericTableEntry(IN PRTL_AVL_TABLE Table,
3884 IN CLONG ByteSize)
3885 {
3886 /* FIXME: TODO */
3887 ASSERT(FALSE);
3888 return NULL;
3889 }
3890
3891 VOID
3892 NTAPI
3893 PiFreeGenericTableEntry(IN PRTL_AVL_TABLE Table,
3894 IN PVOID Buffer)
3895 {
3896 /* FIXME: TODO */
3897 ASSERT(FALSE);
3898 }
3899
3900 VOID
3901 NTAPI
3902 PpInitializeDeviceReferenceTable(VOID)
3903 {
3904 /* Setup the guarded mutex and AVL table */
3905 KeInitializeGuardedMutex(&PpDeviceReferenceTableLock);
3906 RtlInitializeGenericTableAvl(
3907 &PpDeviceReferenceTable,
3908 (PRTL_AVL_COMPARE_ROUTINE)PiCompareInstancePath,
3909 (PRTL_AVL_ALLOCATE_ROUTINE)PiAllocateGenericTableEntry,
3910 (PRTL_AVL_FREE_ROUTINE)PiFreeGenericTableEntry,
3911 NULL);
3912 }
3913
3914 BOOLEAN
3915 NTAPI
3916 PiInitPhase0(VOID)
3917 {
3918 /* Initialize the resource when accessing device registry data */
3919 ExInitializeResourceLite(&PpRegistryDeviceResource);
3920
3921 /* Setup the device reference AVL table */
3922 PpInitializeDeviceReferenceTable();
3923 return TRUE;
3924 }
3925
3926 BOOLEAN
3927 NTAPI
3928 PpInitSystem(VOID)
3929 {
3930 /* Check the initialization phase */
3931 switch (ExpInitializationPhase)
3932 {
3933 case 0:
3934
3935 /* Do Phase 0 */
3936 return PiInitPhase0();
3937
3938 case 1:
3939
3940 /* Do Phase 1 */
3941 return TRUE;
3942 //return PiInitPhase1();
3943
3944 default:
3945
3946 /* Don't know any other phase! Bugcheck! */
3947 KeBugCheck(UNEXPECTED_INITIALIZATION_CALL);
3948 return FALSE;
3949 }
3950 }
3951
3952 LONG IopNumberDeviceNodes;
3953
3954 PDEVICE_NODE
3955 NTAPI
3956 PipAllocateDeviceNode(IN PDEVICE_OBJECT PhysicalDeviceObject)
3957 {
3958 PDEVICE_NODE DeviceNode;
3959 PAGED_CODE();
3960
3961 /* Allocate it */
3962 DeviceNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(DEVICE_NODE), 'donD');
3963 if (!DeviceNode) return DeviceNode;
3964
3965 /* Statistics */
3966 InterlockedIncrement(&IopNumberDeviceNodes);
3967
3968 /* Set it up */
3969 RtlZeroMemory(DeviceNode, sizeof(DEVICE_NODE));
3970 DeviceNode->InterfaceType = InterfaceTypeUndefined;
3971 DeviceNode->BusNumber = -1;
3972 DeviceNode->ChildInterfaceType = InterfaceTypeUndefined;
3973 DeviceNode->ChildBusNumber = -1;
3974 DeviceNode->ChildBusTypeIndex = -1;
3975 // KeInitializeEvent(&DeviceNode->EnumerationMutex, SynchronizationEvent, TRUE);
3976 InitializeListHead(&DeviceNode->DeviceArbiterList);
3977 InitializeListHead(&DeviceNode->DeviceTranslatorList);
3978 InitializeListHead(&DeviceNode->TargetDeviceNotify);
3979 InitializeListHead(&DeviceNode->DockInfo.ListEntry);
3980 InitializeListHead(&DeviceNode->PendedSetInterfaceState);
3981
3982 /* Check if there is a PDO */
3983 if (PhysicalDeviceObject)
3984 {
3985 /* Link it and remove the init flag */
3986 DeviceNode->PhysicalDeviceObject = PhysicalDeviceObject;
3987 ((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode = DeviceNode;
3988 PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
3989 }
3990
3991 /* Return the node */
3992 return DeviceNode;
3993 }
3994
3995 /* PUBLIC FUNCTIONS **********************************************************/
3996
3997 /*
3998 * @implemented
3999 */
4000 NTSTATUS
4001 NTAPI
4002 IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject,
4003 IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
4004 IN ULONG BufferLength,
4005 OUT PVOID PropertyBuffer,
4006 OUT PULONG ResultLength)
4007 {
4008 PDEVICE_NODE DeviceNode = IopGetDeviceNode(DeviceObject);
4009 DEVICE_CAPABILITIES DeviceCaps;
4010 ULONG Length;
4011 PVOID Data = NULL;
4012 PWSTR Ptr;
4013 NTSTATUS Status;
4014 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
4015 ULONG RequiredLength, ObjectNameInfoLength;
4016
4017 DPRINT("IoGetDeviceProperty(0x%p %d)\n", DeviceObject, DeviceProperty);
4018
4019 *ResultLength = 0;
4020
4021 if (DeviceNode == NULL)
4022 return STATUS_INVALID_DEVICE_REQUEST;
4023
4024 switch (DeviceProperty)
4025 {
4026 case DevicePropertyBusNumber:
4027 Length = sizeof(ULONG);
4028 Data = &DeviceNode->ChildBusNumber;
4029 break;
4030
4031 /* Complete, untested */
4032 case DevicePropertyBusTypeGuid:
4033 /* Sanity check */
4034 if ((DeviceNode->ChildBusTypeIndex != 0xFFFF) &&
4035 (DeviceNode->ChildBusTypeIndex < PnpBusTypeGuidList->GuidCount))
4036 {
4037 /* Return the GUID */
4038 *ResultLength = sizeof(GUID);
4039
4040 /* Check if the buffer given was large enough */
4041 if (BufferLength < *ResultLength)
4042 {
4043 return STATUS_BUFFER_TOO_SMALL;
4044 }
4045
4046 /* Copy the GUID */
4047 RtlCopyMemory(PropertyBuffer,
4048 &(PnpBusTypeGuidList->Guids[DeviceNode->ChildBusTypeIndex]),
4049 sizeof(GUID));
4050 return STATUS_SUCCESS;
4051 }
4052 else
4053 {
4054 return STATUS_OBJECT_NAME_NOT_FOUND;
4055 }
4056 break;
4057
4058 case DevicePropertyLegacyBusType:
4059 Length = sizeof(INTERFACE_TYPE);
4060 Data = &DeviceNode->ChildInterfaceType;
4061 break;
4062
4063 case DevicePropertyAddress:
4064 /* Query the device caps */
4065 Status = IopQueryDeviceCapabilities(DeviceNode, &DeviceCaps);
4066 if (NT_SUCCESS(Status) && (DeviceCaps.Address != MAXULONG))
4067 {
4068 /* Return length */
4069 *ResultLength = sizeof(ULONG);
4070
4071 /* Check if the buffer given was large enough */
4072 if (BufferLength < *ResultLength)
4073 {
4074 return STATUS_BUFFER_TOO_SMALL;
4075 }
4076
4077 /* Return address */
4078 *(PULONG)PropertyBuffer = DeviceCaps.Address;
4079 return STATUS_SUCCESS;
4080 }
4081 else
4082 {
4083 return STATUS_OBJECT_NAME_NOT_FOUND;
4084 }
4085 break;
4086
4087 // case DevicePropertyUINumber:
4088 // if (DeviceNode->CapabilityFlags == NULL)
4089 // return STATUS_INVALID_DEVICE_REQUEST;
4090 // Length = sizeof(ULONG);
4091 // Data = &DeviceNode->CapabilityFlags->UINumber;
4092 // break;
4093
4094 case DevicePropertyClassName:
4095 case DevicePropertyClassGuid:
4096 case DevicePropertyDriverKeyName:
4097 case DevicePropertyManufacturer:
4098 case DevicePropertyFriendlyName:
4099 case DevicePropertyHardwareID:
4100 case DevicePropertyCompatibleIDs:
4101 case DevicePropertyDeviceDescription:
4102 case DevicePropertyLocationInformation:
4103 case DevicePropertyUINumber:
4104 {
4105 LPCWSTR RegistryPropertyName;
4106 UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
4107 UNICODE_STRING ValueName;
4108 KEY_VALUE_PARTIAL_INFORMATION *ValueInformation;
4109 ULONG ValueInformationLength;
4110 HANDLE KeyHandle, EnumRootHandle;
4111 NTSTATUS Status;
4112
4113 switch (DeviceProperty)
4114 {
4115 case DevicePropertyClassName:
4116 RegistryPropertyName = L"Class"; break;
4117 case DevicePropertyClassGuid:
4118 RegistryPropertyName = L"ClassGuid"; break;
4119 case DevicePropertyDriverKeyName:
4120 RegistryPropertyName = L"Driver"; break;
4121 case DevicePropertyManufacturer:
4122 RegistryPropertyName = L"Mfg"; break;
4123 case DevicePropertyFriendlyName:
4124 RegistryPropertyName = L"FriendlyName"; break;
4125 case DevicePropertyHardwareID:
4126 RegistryPropertyName = L"HardwareID"; break;
4127 case DevicePropertyCompatibleIDs:
4128 RegistryPropertyName = L"CompatibleIDs"; break;
4129 case DevicePropertyDeviceDescription:
4130 RegistryPropertyName = L"DeviceDesc"; break;
4131 case DevicePropertyLocationInformation:
4132 RegistryPropertyName = L"LocationInformation"; break;
4133 case DevicePropertyUINumber:
4134 RegistryPropertyName = L"UINumber"; break;
4135 default:
4136 /* Should not happen */
4137 ASSERT(FALSE);
4138 return STATUS_UNSUCCESSFUL;
4139 }
4140
4141 DPRINT("Registry property %S\n", RegistryPropertyName);
4142
4143 /* Open Enum key */
4144 Status = IopOpenRegistryKeyEx(&EnumRootHandle, NULL,
4145 &EnumRoot, KEY_READ);
4146 if (!NT_SUCCESS(Status))
4147 {
4148 DPRINT1("Error opening ENUM_ROOT, Status=0x%08x\n", Status);
4149 return Status;
4150 }
4151
4152 /* Open instance key */
4153 Status = IopOpenRegistryKeyEx(&KeyHandle, EnumRootHandle,
4154 &DeviceNode->InstancePath, KEY_READ);
4155 if (!NT_SUCCESS(Status))
4156 {
4157 DPRINT1("Error opening InstancePath, Status=0x%08x\n", Status);
4158 ZwClose(EnumRootHandle);
4159 return Status;
4160 }
4161
4162 /* Allocate buffer to read as much data as required by the caller */
4163 ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
4164 Data[0]) + BufferLength;
4165 ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
4166 if (!ValueInformation)
4167 {
4168 ZwClose(KeyHandle);
4169 return STATUS_INSUFFICIENT_RESOURCES;
4170 }
4171
4172 /* Read the value */
4173 RtlInitUnicodeString(&ValueName, RegistryPropertyName);
4174 Status = ZwQueryValueKey(KeyHandle, &ValueName,
4175 KeyValuePartialInformation, ValueInformation,
4176 ValueInformationLength,
4177 &ValueInformationLength);
4178 ZwClose(KeyHandle);
4179
4180 /* Return data */
4181 *ResultLength = ValueInformation->DataLength;
4182
4183 if (!NT_SUCCESS(Status))
4184 {
4185 ExFreePool(ValueInformation);
4186 if (Status == STATUS_BUFFER_OVERFLOW)
4187 return STATUS_BUFFER_TOO_SMALL;
4188 DPRINT1("Problem: Status=0x%08x, ResultLength = %d\n", Status, *ResultLength);
4189 return Status;
4190 }
4191
4192 /* FIXME: Verify the value (NULL-terminated, correct format). */
4193 RtlCopyMemory(PropertyBuffer, ValueInformation->Data,
4194 ValueInformation->DataLength);
4195 ExFreePool(ValueInformation);
4196
4197 return STATUS_SUCCESS;
4198 }
4199
4200 case DevicePropertyBootConfiguration:
4201 Length = 0;
4202 if (DeviceNode->BootResources->Count != 0)
4203 {
4204 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
4205 }
4206 Data = DeviceNode->BootResources;
4207 break;
4208
4209 /* FIXME: use a translated boot configuration instead */
4210 case DevicePropertyBootConfigurationTranslated:
4211 Length = 0;
4212 if (DeviceNode->BootResources->Count != 0)
4213 {
4214 Length = CM_RESOURCE_LIST_SIZE(DeviceNode->BootResources);
4215 }
4216 Data = DeviceNode->BootResources;
4217 break;
4218
4219 case DevicePropertyEnumeratorName:
4220 /* A buffer overflow can't happen here, since InstancePath
4221 * always contains the enumerator name followed by \\ */
4222 Ptr = wcschr(DeviceNode->InstancePath.Buffer, L'\\');
4223 ASSERT(Ptr);
4224 Length = (Ptr - DeviceNode->InstancePath.Buffer) * sizeof(WCHAR);
4225 Data = DeviceNode->InstancePath.Buffer;
4226 break;
4227
4228 case DevicePropertyPhysicalDeviceObjectName:
4229 Status = ObQueryNameString(DeviceNode->PhysicalDeviceObject,
4230 NULL,
4231 0,
4232 &RequiredLength);
4233 if (Status == STATUS_SUCCESS)
4234 {
4235 Length = 0;
4236 Data = L"";
4237 }
4238 else if (Status == STATUS_INFO_LENGTH_MISMATCH)
4239 {
4240 ObjectNameInfoLength = RequiredLength;
4241 ObjectNameInfo = ExAllocatePool(PagedPool, ObjectNameInfoLength);
4242 if (!ObjectNameInfo)
4243 return STATUS_INSUFFICIENT_RESOURCES;
4244
4245 Status = ObQueryNameString(DeviceNode->PhysicalDeviceObject,
4246 ObjectNameInfo,
4247 ObjectNameInfoLength,
4248 &RequiredLength);
4249 if (NT_SUCCESS(Status))
4250 {
4251 Length = ObjectNameInfo->Name.Length;
4252 Data = ObjectNameInfo->Name.Buffer;
4253 }
4254 else
4255 return Status;
4256 }
4257 else
4258 return Status;
4259 break;
4260
4261 default:
4262 return STATUS_INVALID_PARAMETER_2;
4263 }
4264
4265 /* Prepare returned values */
4266 *ResultLength = Length;
4267 if (BufferLength < Length)
4268 {
4269 if (ObjectNameInfo != NULL)
4270 ExFreePool(ObjectNameInfo);
4271
4272 return STATUS_BUFFER_TOO_SMALL;
4273 }
4274 RtlCopyMemory(PropertyBuffer, Data, Length);
4275
4276 /* NULL terminate the string (if required) */
4277 if (DeviceProperty == DevicePropertyEnumeratorName ||
4278 DeviceProperty == DevicePropertyPhysicalDeviceObjectName)
4279 ((LPWSTR)PropertyBuffer)[Length / sizeof(WCHAR)] = UNICODE_NULL;
4280
4281 if (ObjectNameInfo != NULL)
4282 ExFreePool(ObjectNameInfo);
4283
4284 return STATUS_SUCCESS;
4285 }
4286
4287 /*
4288 * @unimplemented
4289 */
4290 VOID
4291 NTAPI
4292 IoInvalidateDeviceState(IN PDEVICE_OBJECT PhysicalDeviceObject)
4293 {
4294 UNIMPLEMENTED;
4295 }
4296
4297 /**
4298 * @name IoOpenDeviceRegistryKey
4299 *
4300 * Open a registry key unique for a specified driver or device instance.
4301 *
4302 * @param DeviceObject Device to get the registry key for.
4303 * @param DevInstKeyType Type of the key to return.
4304 * @param DesiredAccess Access mask (eg. KEY_READ | KEY_WRITE).
4305 * @param DevInstRegKey Handle to the opened registry key on
4306 * successful return.
4307 *
4308 * @return Status.
4309 *
4310 * @implemented
4311 */
4312 NTSTATUS
4313 NTAPI
4314 IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject,
4315 IN ULONG DevInstKeyType,
4316 IN ACCESS_MASK DesiredAccess,
4317 OUT PHANDLE DevInstRegKey)
4318 {
4319 static WCHAR RootKeyName[] =
4320 L"\\Registry\\Machine\\System\\CurrentControlSet\\";
4321 static WCHAR ProfileKeyName[] =
4322 L"Hardware Profiles\\Current\\System\\CurrentControlSet\\";
4323 static WCHAR ClassKeyName[] = L"Control\\Class\\";
4324 static WCHAR EnumKeyName[] = L"Enum\\";
4325 static WCHAR DeviceParametersKeyName[] = L"Device Parameters";
4326 ULONG KeyNameLength;
4327 LPWSTR KeyNameBuffer;
4328 UNICODE_STRING KeyName;
4329 ULONG DriverKeyLength;
4330 OBJECT_ATTRIBUTES ObjectAttributes;
4331 PDEVICE_NODE DeviceNode = NULL;
4332 NTSTATUS Status;
4333
4334 DPRINT("IoOpenDeviceRegistryKey() called\n");
4335
4336 if ((DevInstKeyType & (PLUGPLAY_REGKEY_DEVICE | PLUGPLAY_REGKEY_DRIVER)) == 0)
4337 {
4338 DPRINT1("IoOpenDeviceRegistryKey(): got wrong params, exiting... \n");
4339 return STATUS_INVALID_PARAMETER;
4340 }
4341
4342 /*
4343 * Calculate the length of the base key name. This is the full
4344 * name for driver key or the name excluding "Device Parameters"
4345 * subkey for device key.
4346 */
4347
4348 KeyNameLength = sizeof(RootKeyName);
4349 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4350 KeyNameLength += sizeof(ProfileKeyName) - sizeof(UNICODE_NULL);
4351 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4352 {
4353 KeyNameLength += sizeof(ClassKeyName) - sizeof(UNICODE_NULL);
4354 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4355 0, NULL, &DriverKeyLength);
4356 if (Status != STATUS_BUFFER_TOO_SMALL)
4357 return Status;
4358 KeyNameLength += DriverKeyLength;
4359 }
4360 else
4361 {
4362 DeviceNode = IopGetDeviceNode(DeviceObject);
4363 KeyNameLength += sizeof(EnumKeyName) - sizeof(UNICODE_NULL) +
4364 DeviceNode->InstancePath.Length;
4365 }
4366
4367 /*
4368 * Now allocate the buffer for the key name...
4369 */
4370
4371 KeyNameBuffer = ExAllocatePool(PagedPool, KeyNameLength);
4372 if (KeyNameBuffer == NULL)
4373 return STATUS_INSUFFICIENT_RESOURCES;
4374
4375 KeyName.Length = 0;
4376 KeyName.MaximumLength = (USHORT)KeyNameLength;
4377 KeyName.Buffer = KeyNameBuffer;
4378
4379 /*
4380 * ...and build the key name.
4381 */
4382
4383 KeyName.Length += sizeof(RootKeyName) - sizeof(UNICODE_NULL);
4384 RtlCopyMemory(KeyNameBuffer, RootKeyName, KeyName.Length);
4385
4386 if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE)
4387 RtlAppendUnicodeToString(&KeyName, ProfileKeyName);
4388
4389 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4390 {
4391 RtlAppendUnicodeToString(&KeyName, ClassKeyName);
4392 Status = IoGetDeviceProperty(DeviceObject, DevicePropertyDriverKeyName,
4393 DriverKeyLength, KeyNameBuffer +
4394 (KeyName.Length / sizeof(WCHAR)),
4395 &DriverKeyLength);
4396 if (!NT_SUCCESS(Status))
4397 {
4398 DPRINT1("Call to IoGetDeviceProperty() failed with Status 0x%08lx\n", Status);
4399 ExFreePool(KeyNameBuffer);
4400 return Status;
4401 }
4402 KeyName.Length += (USHORT)DriverKeyLength - sizeof(UNICODE_NULL);
4403 }
4404 else
4405 {
4406 RtlAppendUnicodeToString(&KeyName, EnumKeyName);
4407 Status = RtlAppendUnicodeStringToString(&KeyName, &DeviceNode->InstancePath);
4408 if (DeviceNode->InstancePath.Length == 0)
4409 {
4410 ExFreePool(KeyNameBuffer);
4411 return Status;
4412 }
4413 }
4414
4415 /*
4416 * Open the base key.
4417 */
4418 Status = IopOpenRegistryKeyEx(DevInstRegKey, NULL, &KeyName, DesiredAccess);
4419 if (!NT_SUCCESS(Status))
4420 {
4421 DPRINT1("IoOpenDeviceRegistryKey(%wZ): Base key doesn't exist, exiting... (Status 0x%08lx)\n", &KeyName, Status);
4422 ExFreePool(KeyNameBuffer);
4423 return Status;
4424 }
4425 ExFreePool(KeyNameBuffer);
4426
4427 /*
4428 * For driver key we're done now.
4429 */
4430
4431 if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER)
4432 return Status;
4433
4434 /*
4435 * Let's go further. For device key we must open "Device Parameters"
4436 * subkey and create it if it doesn't exist yet.
4437 */
4438
4439 RtlInitUnicodeString(&KeyName, DeviceParametersKeyName);
4440 InitializeObjectAttributes(&ObjectAttributes, &KeyName,
4441 OBJ_CASE_INSENSITIVE, *DevInstRegKey, NULL);
4442 Status = ZwCreateKey(DevInstRegKey, DesiredAccess, &ObjectAttributes,
4443 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
4444 ZwClose(ObjectAttributes.RootDirectory);
4445
4446 return Status;
4447 }
4448
4449 /*
4450 * @unimplemented
4451 */
4452 VOID
4453 NTAPI
4454 IoRequestDeviceEject(IN PDEVICE_OBJECT PhysicalDeviceObject)
4455 {
4456 UNIMPLEMENTED;
4457 }
4458
4459 /*
4460 * @implemented
4461 */
4462 VOID
4463 NTAPI
4464 IoInvalidateDeviceRelations(
4465 IN PDEVICE_OBJECT DeviceObject,
4466 IN DEVICE_RELATION_TYPE Type)
4467 {
4468 PIO_WORKITEM WorkItem;
4469 PINVALIDATE_DEVICE_RELATION_DATA Data;
4470
4471 Data = ExAllocatePool(PagedPool, sizeof(INVALIDATE_DEVICE_RELATION_DATA));
4472 if (!Data)
4473 return;
4474 WorkItem = IoAllocateWorkItem(DeviceObject);
4475 if (!WorkItem)
4476 {
4477 ExFreePool(Data);
4478 return;
4479 }
4480
4481 ObReferenceObject(DeviceObject);
4482 Data->DeviceObject = DeviceObject;
4483 Data->Type = Type;
4484 Data->WorkItem = WorkItem;
4485
4486 IoQueueWorkItem(
4487 WorkItem,
4488 IopAsynchronousInvalidateDeviceRelations,
4489 DelayedWorkQueue,
4490 Data);
4491 }
4492
4493 /*
4494 * @implemented
4495 */
4496 NTSTATUS
4497 NTAPI
4498 IoSynchronousInvalidateDeviceRelations(
4499 IN PDEVICE_OBJECT DeviceObject,
4500 IN DEVICE_RELATION_TYPE Type)
4501 {
4502 PAGED_CODE();
4503
4504 switch (Type)
4505 {
4506 case BusRelations:
4507 /* Enumerate the device */
4508 return IopEnumerateDevice(DeviceObject);
4509 case PowerRelations:
4510 /* Not handled yet */
4511 return STATUS_NOT_IMPLEMENTED;
4512 case TargetDeviceRelation:
4513 /* Nothing to do */
4514 return STATUS_SUCCESS;
4515 default:
4516 /* Ejection relations are not supported */
4517 return STATUS_NOT_SUPPORTED;
4518 }
4519 }
4520
4521 /*
4522 * @unimplemented
4523 */
4524 BOOLEAN
4525 NTAPI
4526 IoTranslateBusAddress(IN INTERFACE_TYPE InterfaceType,
4527 IN ULONG BusNumber,
4528 IN PHYSICAL_ADDRESS BusAddress,
4529 IN OUT PULONG AddressSpace,
4530 OUT PPHYSICAL_ADDRESS TranslatedAddress)
4531 {
4532 UNIMPLEMENTED;
4533 return FALSE;
4534 }