2 * PROJECT: ReactOS Kernel
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/pnpmgr/pnpres.c
5 * PURPOSE: Resource handling code
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
7 * ReactOS Portable Systems Group
17 IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
, OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
19 CM_RESOURCE_LIST CmList
;
23 CmList
.List
[0].InterfaceType
= InterfaceTypeUndefined
;
24 CmList
.List
[0].BusNumber
= 0;
25 CmList
.List
[0].PartialResourceList
.Version
= 1;
26 CmList
.List
[0].PartialResourceList
.Revision
= 1;
27 CmList
.List
[0].PartialResourceList
.Count
= 1;
28 CmList
.List
[0].PartialResourceList
.PartialDescriptors
[0] = *CmDesc
;
30 Status
= IopDetectResourceConflict(&CmList
, TRUE
, ConflictingDescriptor
);
31 if (Status
== STATUS_CONFLICTING_ADDRESSES
)
39 IopFindBusNumberResource(
40 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
41 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
44 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
46 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
47 ASSERT(IoDesc
->Type
== CmResourceTypeBusNumber
);
49 for (Start
= IoDesc
->u
.BusNumber
.MinBusNumber
;
50 Start
<= IoDesc
->u
.BusNumber
.MaxBusNumber
- IoDesc
->u
.BusNumber
.Length
+ 1;
53 CmDesc
->u
.BusNumber
.Length
= IoDesc
->u
.BusNumber
.Length
;
54 CmDesc
->u
.BusNumber
.Start
= Start
;
56 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
58 Start
+= ConflictingDesc
.u
.BusNumber
.Start
+ ConflictingDesc
.u
.BusNumber
.Length
;
62 DPRINT1("Satisfying bus number requirement with 0x%x (length: 0x%x)\n", Start
, CmDesc
->u
.BusNumber
.Length
);
72 IopFindMemoryResource(
73 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
74 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
77 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
79 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
80 ASSERT(IoDesc
->Type
== CmResourceTypeMemory
);
83 if (IoDesc
->u
.Memory
.Alignment
== 0) IoDesc
->u
.Memory
.Alignment
= 1;
85 for (Start
= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
;
86 Start
<= IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
- IoDesc
->u
.Memory
.Length
+ 1;
87 Start
+= IoDesc
->u
.Memory
.Alignment
)
89 CmDesc
->u
.Memory
.Length
= IoDesc
->u
.Memory
.Length
;
90 CmDesc
->u
.Memory
.Start
.QuadPart
= Start
;
92 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
94 Start
+= ConflictingDesc
.u
.Memory
.Start
.QuadPart
+
95 ConflictingDesc
.u
.Memory
.Length
;
99 DPRINT1("Satisfying memory requirement with 0x%I64x (length: 0x%x)\n", Start
, CmDesc
->u
.Memory
.Length
);
110 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
111 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
114 CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc
;
116 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
117 ASSERT(IoDesc
->Type
== CmResourceTypePort
);
120 if (IoDesc
->u
.Port
.Alignment
== 0) IoDesc
->u
.Port
.Alignment
= 1;
122 for (Start
= IoDesc
->u
.Port
.MinimumAddress
.QuadPart
;
123 Start
<= IoDesc
->u
.Port
.MaximumAddress
.QuadPart
- IoDesc
->u
.Port
.Length
+ 1;
124 Start
+= IoDesc
->u
.Port
.Alignment
)
126 CmDesc
->u
.Port
.Length
= IoDesc
->u
.Port
.Length
;
127 CmDesc
->u
.Port
.Start
.QuadPart
= Start
;
129 if (IopCheckDescriptorForConflict(CmDesc
, &ConflictingDesc
))
131 Start
+= ConflictingDesc
.u
.Port
.Start
.QuadPart
+ ConflictingDesc
.u
.Port
.Length
;
135 DPRINT1("Satisfying port requirement with 0x%I64x (length: 0x%x)\n", Start
, CmDesc
->u
.Port
.Length
);
146 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
147 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
151 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
152 ASSERT(IoDesc
->Type
== CmResourceTypeDma
);
154 for (Channel
= IoDesc
->u
.Dma
.MinimumChannel
;
155 Channel
<= IoDesc
->u
.Dma
.MaximumChannel
;
158 CmDesc
->u
.Dma
.Channel
= Channel
;
159 CmDesc
->u
.Dma
.Port
= 0;
161 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
163 DPRINT1("Satisfying DMA requirement with channel 0x%x\n", Channel
);
173 IopFindInterruptResource(
174 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
175 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
179 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
180 ASSERT(IoDesc
->Type
== CmResourceTypeInterrupt
);
182 for (Vector
= IoDesc
->u
.Interrupt
.MinimumVector
;
183 Vector
<= IoDesc
->u
.Interrupt
.MaximumVector
;
186 CmDesc
->u
.Interrupt
.Vector
= Vector
;
187 CmDesc
->u
.Interrupt
.Level
= Vector
;
188 CmDesc
->u
.Interrupt
.Affinity
= (KAFFINITY
)-1;
190 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
192 DPRINT1("Satisfying interrupt requirement with IRQ 0x%x\n", Vector
);
201 IopFixupResourceListWithRequirements(
202 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
,
203 OUT PCM_RESOURCE_LIST
*ResourceList
)
206 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
209 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
210 BOOLEAN AlternateRequired
= FALSE
;
212 for (ii
= 0; ii
< ResList
->Count
; ii
++)
215 PCM_PARTIAL_RESOURCE_LIST PartialList
= (*ResourceList
) ? &(*ResourceList
)->List
[0].PartialResourceList
: NULL
;
216 PIO_RESOURCE_DESCRIPTOR IoDesc
= &ResList
->Descriptors
[ii
];
217 BOOLEAN Matched
= FALSE
;
219 /* Skip alternates if we don't need one */
220 if (!AlternateRequired
&& (IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
222 DPRINT("Skipping unneeded alternate\n");
226 /* Check if we couldn't satsify a requirement or its alternates */
227 if (AlternateRequired
&& !(IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
229 DPRINT1("Unable to satisfy preferred resource or alternates\n");
233 ExFreePool(*ResourceList
);
234 *ResourceList
= NULL
;
236 return STATUS_CONFLICTING_ADDRESSES
;
239 for (iii
= 0; PartialList
&& iii
< PartialList
->Count
&& !Matched
; iii
++)
241 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
= &PartialList
->PartialDescriptors
[iii
];
243 /* First check types */
244 if (IoDesc
->Type
!= CmDesc
->Type
)
247 switch (IoDesc
->Type
)
249 case CmResourceTypeInterrupt
:
250 /* Make sure it satisfies our vector range */
251 if (CmDesc
->u
.Interrupt
.Vector
>= IoDesc
->u
.Interrupt
.MinimumVector
&&
252 CmDesc
->u
.Interrupt
.Vector
<= IoDesc
->u
.Interrupt
.MaximumVector
)
259 DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n",
260 CmDesc
->u
.Interrupt
.Vector
,
261 IoDesc
->u
.Interrupt
.MinimumVector
,
262 IoDesc
->u
.Interrupt
.MaximumVector
);
266 case CmResourceTypeMemory
:
267 case CmResourceTypePort
:
268 /* Make sure the length matches and it satisfies our address range */
269 if (CmDesc
->u
.Memory
.Length
== IoDesc
->u
.Memory
.Length
&&
270 CmDesc
->u
.Memory
.Start
.QuadPart
>= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
&&
271 CmDesc
->u
.Memory
.Start
.QuadPart
+ CmDesc
->u
.Memory
.Length
- 1 <= IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
)
278 DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n",
279 CmDesc
->u
.Memory
.Start
.QuadPart
,
280 CmDesc
->u
.Memory
.Length
,
281 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
,
282 IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
283 IoDesc
->u
.Memory
.Length
);
287 case CmResourceTypeBusNumber
:
288 /* Make sure the length matches and it satisfies our bus number range */
289 if (CmDesc
->u
.BusNumber
.Length
== IoDesc
->u
.BusNumber
.Length
&&
290 CmDesc
->u
.BusNumber
.Start
>= IoDesc
->u
.BusNumber
.MinBusNumber
&&
291 CmDesc
->u
.BusNumber
.Start
+ CmDesc
->u
.BusNumber
.Length
- 1 <= IoDesc
->u
.BusNumber
.MaxBusNumber
)
298 DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n",
299 CmDesc
->u
.BusNumber
.Start
,
300 CmDesc
->u
.BusNumber
.Length
,
301 IoDesc
->u
.BusNumber
.MinBusNumber
,
302 IoDesc
->u
.BusNumber
.MaxBusNumber
,
303 IoDesc
->u
.BusNumber
.Length
);
307 case CmResourceTypeDma
:
308 /* Make sure it fits in our channel range */
309 if (CmDesc
->u
.Dma
.Channel
>= IoDesc
->u
.Dma
.MinimumChannel
&&
310 CmDesc
->u
.Dma
.Channel
<= IoDesc
->u
.Dma
.MaximumChannel
)
317 DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n",
318 CmDesc
->u
.Dma
.Channel
,
319 IoDesc
->u
.Dma
.MinimumChannel
,
320 IoDesc
->u
.Dma
.MaximumChannel
);
325 /* Other stuff is fine */
331 /* Check if we found a matching descriptor */
334 PCM_RESOURCE_LIST NewList
;
335 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc
;
336 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr
;
337 BOOLEAN FoundResource
= TRUE
;
339 /* Setup the new CM descriptor */
340 NewDesc
.Type
= IoDesc
->Type
;
341 NewDesc
.Flags
= IoDesc
->Flags
;
342 NewDesc
.ShareDisposition
= IoDesc
->ShareDisposition
;
344 /* Let'se see if we can find a resource to satisfy this */
345 switch (IoDesc
->Type
)
347 case CmResourceTypeInterrupt
:
348 /* Find an available interrupt */
349 if (!IopFindInterruptResource(IoDesc
, &NewDesc
))
351 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
352 IoDesc
->u
.Interrupt
.MinimumVector
, IoDesc
->u
.Interrupt
.MaximumVector
);
354 FoundResource
= FALSE
;
358 case CmResourceTypePort
:
359 /* Find an available port range */
360 if (!IopFindPortResource(IoDesc
, &NewDesc
))
362 DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
363 IoDesc
->u
.Port
.MinimumAddress
.QuadPart
, IoDesc
->u
.Port
.MaximumAddress
.QuadPart
,
364 IoDesc
->u
.Port
.Length
);
366 FoundResource
= FALSE
;
370 case CmResourceTypeMemory
:
371 /* Find an available memory range */
372 if (!IopFindMemoryResource(IoDesc
, &NewDesc
))
374 DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
375 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
, IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
376 IoDesc
->u
.Memory
.Length
);
378 FoundResource
= FALSE
;
382 case CmResourceTypeBusNumber
:
383 /* Find an available bus address range */
384 if (!IopFindBusNumberResource(IoDesc
, &NewDesc
))
386 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
387 IoDesc
->u
.BusNumber
.MinBusNumber
, IoDesc
->u
.BusNumber
.MaxBusNumber
,
388 IoDesc
->u
.BusNumber
.Length
);
390 FoundResource
= FALSE
;
394 case CmResourceTypeDma
:
395 /* Find an available DMA channel */
396 if (!IopFindDmaResource(IoDesc
, &NewDesc
))
398 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
399 IoDesc
->u
.Dma
.MinimumChannel
, IoDesc
->u
.Dma
.MaximumChannel
);
401 FoundResource
= FALSE
;
406 DPRINT1("Unsupported resource type: %x\n", IoDesc
->Type
);
407 FoundResource
= FALSE
;
411 /* Check if it's missing and required */
412 if (!FoundResource
&& IoDesc
->Option
== 0)
416 ExFreePool(*ResourceList
);
417 *ResourceList
= NULL
;
419 return STATUS_CONFLICTING_ADDRESSES
;
421 else if (!FoundResource
)
423 /* Try an alternate for this preferred descriptor */
424 AlternateRequired
= TRUE
;
429 /* Move on to the next preferred or required descriptor after this one */
430 AlternateRequired
= FALSE
;
433 /* Figure out what we need */
434 if (PartialList
== NULL
)
436 /* We need a new list */
437 NewList
= ExAllocatePool(PagedPool
, sizeof(CM_RESOURCE_LIST
));
439 return STATUS_NO_MEMORY
;
443 NewList
->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
444 NewList
->List
[0].BusNumber
= RequirementsList
->BusNumber
;
445 NewList
->List
[0].PartialResourceList
.Version
= 1;
446 NewList
->List
[0].PartialResourceList
.Revision
= 1;
447 NewList
->List
[0].PartialResourceList
.Count
= 1;
449 /* Set our pointer */
450 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[0];
454 /* Allocate the new larger list */
455 NewList
= ExAllocatePool(PagedPool
, PnpDetermineResourceListSize(*ResourceList
) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
457 return STATUS_NO_MEMORY
;
459 /* Copy the old stuff back */
460 RtlCopyMemory(NewList
, *ResourceList
, PnpDetermineResourceListSize(*ResourceList
));
462 /* Set our pointer */
463 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[NewList
->List
[0].PartialResourceList
.Count
];
465 /* Increment the descriptor count */
466 NewList
->List
[0].PartialResourceList
.Count
++;
468 /* Free the old list */
469 ExFreePool(*ResourceList
);
472 /* Copy the descriptor in */
475 /* Store the new list */
476 *ResourceList
= NewList
;
482 return STATUS_SUCCESS
;
487 IopCheckResourceDescriptor(
488 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
489 IN PCM_RESOURCE_LIST ResourceList
,
491 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
494 BOOLEAN Result
= FALSE
;
496 for (i
= 0; i
< ResourceList
->Count
; i
++)
498 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
499 for (ii
= 0; ii
< ResList
->Count
; ii
++)
501 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
503 /* We don't care about shared resources */
504 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
505 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
508 /* Make sure we're comparing the same types */
509 if (ResDesc
->Type
!= ResDesc2
->Type
)
512 switch (ResDesc
->Type
)
514 case CmResourceTypeMemory
:
515 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
516 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
517 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
518 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
519 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
523 DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
524 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
525 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
526 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
535 case CmResourceTypePort
:
536 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
537 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
538 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
539 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
540 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
544 DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
545 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
546 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
547 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
556 case CmResourceTypeInterrupt
:
557 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
561 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
562 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
563 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
572 case CmResourceTypeBusNumber
:
573 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
574 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
575 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
576 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
577 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
581 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
582 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
583 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
584 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
593 case CmResourceTypeDma
:
594 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
598 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
599 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
600 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
614 if (Result
&& ConflictingDescriptor
)
616 RtlCopyMemory(ConflictingDescriptor
,
618 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
626 IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode
)
628 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
629 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
630 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"AllocConfig");
631 HANDLE EnumKey
, InstanceKey
, ControlKey
;
633 OBJECT_ATTRIBUTES ObjectAttributes
;
635 /* Open the Enum key */
636 Status
= IopOpenRegistryKeyEx(&EnumKey
, NULL
, &EnumRoot
, KEY_ENUMERATE_SUB_KEYS
);
637 if (!NT_SUCCESS(Status
))
640 /* Open the instance key (eg. Root\PNP0A03) */
641 Status
= IopOpenRegistryKeyEx(&InstanceKey
, EnumKey
, &DeviceNode
->InstancePath
, KEY_ENUMERATE_SUB_KEYS
);
644 if (!NT_SUCCESS(Status
))
647 /* Create/Open the Control key */
648 InitializeObjectAttributes(&ObjectAttributes
,
650 OBJ_CASE_INSENSITIVE
,
653 Status
= ZwCreateKey(&ControlKey
,
660 ZwClose(InstanceKey
);
662 if (!NT_SUCCESS(Status
))
665 /* Write the resource list */
666 Status
= ZwSetValueKey(ControlKey
,
670 DeviceNode
->ResourceList
,
671 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
674 if (!NT_SUCCESS(Status
))
677 return STATUS_SUCCESS
;
682 IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode
)
684 IO_STACK_LOCATION Stack
;
685 IO_STATUS_BLOCK IoStatusBlock
;
688 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
690 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
691 Status
= IopInitiatePnpIrp(
692 DeviceNode
->PhysicalDeviceObject
,
694 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
696 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
698 DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
701 else if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
703 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
706 return STATUS_SUCCESS
;
711 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
715 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
716 UNICODE_STRING KeyName
;
717 OBJECT_ATTRIBUTES ObjectAttributes
;
719 RtlInitUnicodeString(&KeyName
,
720 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
721 InitializeObjectAttributes(&ObjectAttributes
,
723 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
726 Status
= ZwCreateKey(&ResourceMapKey
,
733 if (!NT_SUCCESS(Status
))
736 RtlInitUnicodeString(&KeyName
, Level1Key
);
737 InitializeObjectAttributes(&ObjectAttributes
,
739 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
742 Status
= ZwCreateKey(&PnpMgrLevel1
,
749 ZwClose(ResourceMapKey
);
750 if (!NT_SUCCESS(Status
))
753 RtlInitUnicodeString(&KeyName
, Level2Key
);
754 InitializeObjectAttributes(&ObjectAttributes
,
756 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
759 Status
= ZwCreateKey(&PnpMgrLevel2
,
766 ZwClose(PnpMgrLevel1
);
767 if (!NT_SUCCESS(Status
))
770 if (DeviceNode
->ResourceList
)
772 UNICODE_STRING NameU
;
773 UNICODE_STRING RawSuffix
, TranslatedSuffix
;
776 ASSERT(DeviceNode
->ResourceListTranslated
);
778 RtlInitUnicodeString(&TranslatedSuffix
, L
".Translated");
779 RtlInitUnicodeString(&RawSuffix
, L
".Raw");
781 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
782 DevicePropertyPhysicalDeviceObjectName
,
786 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
790 NameU
.Buffer
= ExAllocatePool(PagedPool
, OldLength
+ TranslatedSuffix
.Length
);
793 ZwClose(PnpMgrLevel2
);
794 return STATUS_INSUFFICIENT_RESOURCES
;
798 NameU
.MaximumLength
= (USHORT
)OldLength
+ TranslatedSuffix
.Length
;
800 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
801 DevicePropertyPhysicalDeviceObjectName
,
805 if (!NT_SUCCESS(Status
))
807 ZwClose(PnpMgrLevel2
);
808 ExFreePool(NameU
.Buffer
);
812 else if (!NT_SUCCESS(Status
))
815 ZwClose(PnpMgrLevel2
);
820 /* This should never happen */
824 NameU
.Length
= (USHORT
)OldLength
;
826 RtlAppendUnicodeStringToString(&NameU
, &RawSuffix
);
828 Status
= ZwSetValueKey(PnpMgrLevel2
,
832 DeviceNode
->ResourceList
,
833 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
834 if (!NT_SUCCESS(Status
))
836 ZwClose(PnpMgrLevel2
);
837 ExFreePool(NameU
.Buffer
);
841 /* "Remove" the suffix by setting the length back to what it used to be */
842 NameU
.Length
= (USHORT
)OldLength
;
844 RtlAppendUnicodeStringToString(&NameU
, &TranslatedSuffix
);
846 Status
= ZwSetValueKey(PnpMgrLevel2
,
850 DeviceNode
->ResourceListTranslated
,
851 PnpDetermineResourceListSize(DeviceNode
->ResourceListTranslated
));
852 ZwClose(PnpMgrLevel2
);
853 ExFreePool(NameU
.Buffer
);
855 if (!NT_SUCCESS(Status
))
860 ZwClose(PnpMgrLevel2
);
863 return STATUS_SUCCESS
;
867 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
869 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
874 IopTranslateDeviceResources(
875 IN PDEVICE_NODE DeviceNode
)
877 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
878 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
879 ULONG i
, j
, ListSize
;
882 if (!DeviceNode
->ResourceList
)
884 DeviceNode
->ResourceListTranslated
= NULL
;
885 return STATUS_SUCCESS
;
888 /* That's easy to translate a resource list. Just copy the
889 * untranslated one and change few fields in the copy
891 ListSize
= PnpDetermineResourceListSize(DeviceNode
->ResourceList
);
893 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, ListSize
);
894 if (!DeviceNode
->ResourceListTranslated
)
896 Status
= STATUS_NO_MEMORY
;
899 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, ListSize
);
901 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
903 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
904 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
906 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
907 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
908 switch (DescriptorRaw
->Type
)
910 case CmResourceTypePort
:
912 ULONG AddressSpace
= 1; /* IO space */
913 if (!HalTranslateBusAddress(
914 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
915 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
916 DescriptorRaw
->u
.Port
.Start
,
918 &DescriptorTranslated
->u
.Port
.Start
))
920 Status
= STATUS_UNSUCCESSFUL
;
921 DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Port
.Start
.QuadPart
);
925 if (AddressSpace
== 0)
927 DPRINT1("Guessed incorrect address space: 1 -> 0\n");
929 /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
930 * invalid for this state but I'm not 100% sure */
931 DescriptorRaw
->Flags
=
932 DescriptorTranslated
->Flags
= CM_RESOURCE_PORT_MEMORY
;
936 case CmResourceTypeInterrupt
:
938 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
939 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
940 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
941 DescriptorRaw
->u
.Interrupt
.Level
,
942 DescriptorRaw
->u
.Interrupt
.Vector
,
943 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
944 &DescriptorTranslated
->u
.Interrupt
.Affinity
);
946 if (!DescriptorTranslated
->u
.Interrupt
.Vector
)
948 Status
= STATUS_UNSUCCESSFUL
;
949 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw
->u
.Interrupt
.Vector
,
950 DescriptorRaw
->u
.Interrupt
.Level
);
955 case CmResourceTypeMemory
:
957 ULONG AddressSpace
= 0; /* Memory space */
958 if (!HalTranslateBusAddress(
959 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
960 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
961 DescriptorRaw
->u
.Memory
.Start
,
963 &DescriptorTranslated
->u
.Memory
.Start
))
965 Status
= STATUS_UNSUCCESSFUL
;
966 DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Memory
.Start
.QuadPart
);
970 if (AddressSpace
!= 0)
972 DPRINT1("Guessed incorrect address space: 0 -> 1\n");
974 /* This should never happen for memory space */
979 case CmResourceTypeDma
:
980 case CmResourceTypeBusNumber
:
981 case CmResourceTypeDeviceSpecific
:
985 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
986 Status
= STATUS_NOT_IMPLEMENTED
;
991 return STATUS_SUCCESS
;
994 /* Yes! Also delete ResourceList because ResourceList and
995 * ResourceListTranslated should be a pair! */
996 ExFreePool(DeviceNode
->ResourceList
);
997 DeviceNode
->ResourceList
= NULL
;
998 if (DeviceNode
->ResourceListTranslated
)
1000 ExFreePool(DeviceNode
->ResourceListTranslated
);
1001 DeviceNode
->ResourceList
= NULL
;
1008 IopAssignDeviceResources(
1009 IN PDEVICE_NODE DeviceNode
)
1014 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1016 Status
= IopFilterResourceRequirements(DeviceNode
);
1017 if (!NT_SUCCESS(Status
))
1020 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1022 DeviceNode
->Flags
|= DNF_NO_RESOURCE_REQUIRED
;
1023 DeviceNode
->Flags
&= ~DNF_ASSIGNING_RESOURCES
;
1025 /* No resource needed for this device */
1026 DeviceNode
->ResourceList
= NULL
;
1027 DeviceNode
->ResourceListTranslated
= NULL
;
1029 return STATUS_SUCCESS
;
1032 if (DeviceNode
->BootResources
)
1034 ListSize
= PnpDetermineResourceListSize(DeviceNode
->BootResources
);
1036 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, ListSize
);
1037 if (!DeviceNode
->ResourceList
)
1039 Status
= STATUS_NO_MEMORY
;
1043 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, ListSize
);
1045 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1049 ExFreePool(DeviceNode
->ResourceList
);
1050 DeviceNode
->ResourceList
= NULL
;
1055 /* We'll make this from the requirements */
1056 DeviceNode
->ResourceList
= NULL
;
1059 /* No resources requirements */
1060 if (!DeviceNode
->ResourceRequirements
)
1063 /* Add resource requirements that aren't in the list we already got */
1064 Status
= IopFixupResourceListWithRequirements(DeviceNode
->ResourceRequirements
,
1065 &DeviceNode
->ResourceList
);
1066 if (!NT_SUCCESS(Status
))
1068 DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode
->InstancePath
);
1072 /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1073 ASSERT(IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
) != STATUS_CONFLICTING_ADDRESSES
);
1076 Status
= IopTranslateDeviceResources(DeviceNode
);
1077 if (!NT_SUCCESS(Status
))
1079 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode
->InstancePath
);
1083 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
1084 if (!NT_SUCCESS(Status
))
1087 Status
= IopUpdateControlKeyWithResources(DeviceNode
);
1088 if (!NT_SUCCESS(Status
))
1091 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
1093 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1095 return STATUS_SUCCESS
;
1098 if (DeviceNode
->ResourceList
)
1100 ExFreePool(DeviceNode
->ResourceList
);
1101 DeviceNode
->ResourceList
= NULL
;
1104 DeviceNode
->ResourceListTranslated
= NULL
;
1106 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1113 IopCheckForResourceConflict(
1114 IN PCM_RESOURCE_LIST ResourceList1
,
1115 IN PCM_RESOURCE_LIST ResourceList2
,
1117 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1120 BOOLEAN Result
= FALSE
;
1122 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1124 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1125 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1127 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1129 Result
= IopCheckResourceDescriptor(ResDesc
,
1132 ConflictingDescriptor
);
1133 if (Result
) goto ByeBye
;
1143 IopDetectResourceConflict(
1144 IN PCM_RESOURCE_LIST ResourceList
,
1146 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1148 OBJECT_ATTRIBUTES ObjectAttributes
;
1149 UNICODE_STRING KeyName
;
1150 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1151 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1152 PKEY_BASIC_INFORMATION KeyInformation
;
1153 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1154 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1155 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1158 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1159 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1160 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1161 if (!NT_SUCCESS(Status
))
1163 /* The key is missing which means we are the first device */
1164 return STATUS_SUCCESS
;
1169 Status
= ZwEnumerateKey(ResourceMapKey
,
1171 KeyBasicInformation
,
1175 if (Status
== STATUS_NO_MORE_ENTRIES
)
1177 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1179 KeyInformationLength
= RequiredLength
;
1180 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1181 if (!KeyInformation
)
1183 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1187 Status
= ZwEnumerateKey(ResourceMapKey
,
1189 KeyBasicInformation
,
1191 KeyInformationLength
,
1197 if (!NT_SUCCESS(Status
))
1200 KeyName
.Buffer
= KeyInformation
->Name
;
1201 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1202 InitializeObjectAttributes(&ObjectAttributes
,
1204 OBJ_CASE_INSENSITIVE
,
1207 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1208 ExFreePool(KeyInformation
);
1209 if (!NT_SUCCESS(Status
))
1214 Status
= ZwEnumerateKey(ChildKey2
,
1216 KeyBasicInformation
,
1220 if (Status
== STATUS_NO_MORE_ENTRIES
)
1222 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1224 KeyInformationLength
= RequiredLength
;
1225 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1226 if (!KeyInformation
)
1228 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1232 Status
= ZwEnumerateKey(ChildKey2
,
1234 KeyBasicInformation
,
1236 KeyInformationLength
,
1242 if (!NT_SUCCESS(Status
))
1245 KeyName
.Buffer
= KeyInformation
->Name
;
1246 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1247 InitializeObjectAttributes(&ObjectAttributes
,
1249 OBJ_CASE_INSENSITIVE
,
1252 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1253 ExFreePool(KeyInformation
);
1254 if (!NT_SUCCESS(Status
))
1259 Status
= ZwEnumerateValueKey(ChildKey3
,
1261 KeyValuePartialInformation
,
1265 if (Status
== STATUS_NO_MORE_ENTRIES
)
1267 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1269 KeyValueInformationLength
= RequiredLength
;
1270 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1271 if (!KeyValueInformation
)
1273 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1277 Status
= ZwEnumerateValueKey(ChildKey3
,
1279 KeyValuePartialInformation
,
1280 KeyValueInformation
,
1281 KeyValueInformationLength
,
1286 if (!NT_SUCCESS(Status
))
1289 Status
= ZwEnumerateValueKey(ChildKey3
,
1291 KeyValueBasicInformation
,
1295 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1297 KeyNameInformationLength
= RequiredLength
;
1298 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1299 if (!KeyNameInformation
)
1301 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1305 Status
= ZwEnumerateValueKey(ChildKey3
,
1307 KeyValueBasicInformation
,
1309 KeyNameInformationLength
,
1317 if (!NT_SUCCESS(Status
))
1320 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1322 /* Skip translated entries */
1323 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1325 ExFreePool(KeyNameInformation
);
1329 ExFreePool(KeyNameInformation
);
1331 if (IopCheckForResourceConflict(ResourceList
,
1332 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1334 ConflictingDescriptor
))
1336 ExFreePool(KeyValueInformation
);
1337 Status
= STATUS_CONFLICTING_ADDRESSES
;
1341 ExFreePool(KeyValueInformation
);
1347 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1348 ZwClose(ResourceMapKey
);
1349 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1351 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1354 if (Status
== STATUS_NO_MORE_ENTRIES
)
1355 Status
= STATUS_SUCCESS
;