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