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 BOOLEAN AlternateRequired
= FALSE
;
208 /* Save the initial resource count when we got here so we can restore if an alternate fails */
209 if (*ResourceList
!= NULL
)
210 OldCount
= (*ResourceList
)->List
[0].PartialResourceList
.Count
;
214 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
217 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
219 /* We need to get back to where we were before processing the last alternative list */
220 if (OldCount
== 0 && *ResourceList
!= NULL
)
222 /* Just free it and kill the pointer */
223 ExFreePool(*ResourceList
);
224 *ResourceList
= NULL
;
226 else if (OldCount
!= 0)
228 PCM_RESOURCE_LIST NewList
;
230 /* Let's resize it */
231 (*ResourceList
)->List
[0].PartialResourceList
.Count
= OldCount
;
233 /* Allocate the new smaller list */
234 NewList
= ExAllocatePool(PagedPool
, PnpDetermineResourceListSize(*ResourceList
));
236 return STATUS_NO_MEMORY
;
238 /* Copy the old stuff back */
239 RtlCopyMemory(NewList
, *ResourceList
, PnpDetermineResourceListSize(*ResourceList
));
241 /* Free the old one */
242 ExFreePool(*ResourceList
);
244 /* Store the pointer to the new one */
245 *ResourceList
= NewList
;
248 for (ii
= 0; ii
< ResList
->Count
; ii
++)
251 PCM_PARTIAL_RESOURCE_LIST PartialList
= (*ResourceList
) ? &(*ResourceList
)->List
[0].PartialResourceList
: NULL
;
252 PIO_RESOURCE_DESCRIPTOR IoDesc
= &ResList
->Descriptors
[ii
];
253 BOOLEAN Matched
= FALSE
;
255 /* Skip alternates if we don't need one */
256 if (!AlternateRequired
&& (IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
258 DPRINT("Skipping unneeded alternate\n");
262 /* Check if we couldn't satsify a requirement or its alternates */
263 if (AlternateRequired
&& !(IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
265 DPRINT1("Unable to satisfy preferred resource or alternates in list %d\n", i
);
267 /* Break out of this loop and try the next list */
271 for (iii
= 0; PartialList
&& iii
< PartialList
->Count
&& !Matched
; iii
++)
273 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
= &PartialList
->PartialDescriptors
[iii
];
275 /* First check types */
276 if (IoDesc
->Type
!= CmDesc
->Type
)
279 switch (IoDesc
->Type
)
281 case CmResourceTypeInterrupt
:
282 /* Make sure it satisfies our vector range */
283 if (CmDesc
->u
.Interrupt
.Vector
>= IoDesc
->u
.Interrupt
.MinimumVector
&&
284 CmDesc
->u
.Interrupt
.Vector
<= IoDesc
->u
.Interrupt
.MaximumVector
)
291 DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n",
292 CmDesc
->u
.Interrupt
.Vector
,
293 IoDesc
->u
.Interrupt
.MinimumVector
,
294 IoDesc
->u
.Interrupt
.MaximumVector
);
298 case CmResourceTypeMemory
:
299 case CmResourceTypePort
:
300 /* Make sure the length matches and it satisfies our address range */
301 if (CmDesc
->u
.Memory
.Length
== IoDesc
->u
.Memory
.Length
&&
302 CmDesc
->u
.Memory
.Start
.QuadPart
>= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
&&
303 CmDesc
->u
.Memory
.Start
.QuadPart
+ CmDesc
->u
.Memory
.Length
- 1 <= IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
)
310 DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n",
311 CmDesc
->u
.Memory
.Start
.QuadPart
,
312 CmDesc
->u
.Memory
.Length
,
313 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
,
314 IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
315 IoDesc
->u
.Memory
.Length
);
319 case CmResourceTypeBusNumber
:
320 /* Make sure the length matches and it satisfies our bus number range */
321 if (CmDesc
->u
.BusNumber
.Length
== IoDesc
->u
.BusNumber
.Length
&&
322 CmDesc
->u
.BusNumber
.Start
>= IoDesc
->u
.BusNumber
.MinBusNumber
&&
323 CmDesc
->u
.BusNumber
.Start
+ CmDesc
->u
.BusNumber
.Length
- 1 <= IoDesc
->u
.BusNumber
.MaxBusNumber
)
330 DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n",
331 CmDesc
->u
.BusNumber
.Start
,
332 CmDesc
->u
.BusNumber
.Length
,
333 IoDesc
->u
.BusNumber
.MinBusNumber
,
334 IoDesc
->u
.BusNumber
.MaxBusNumber
,
335 IoDesc
->u
.BusNumber
.Length
);
339 case CmResourceTypeDma
:
340 /* Make sure it fits in our channel range */
341 if (CmDesc
->u
.Dma
.Channel
>= IoDesc
->u
.Dma
.MinimumChannel
&&
342 CmDesc
->u
.Dma
.Channel
<= IoDesc
->u
.Dma
.MaximumChannel
)
349 DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n",
350 CmDesc
->u
.Dma
.Channel
,
351 IoDesc
->u
.Dma
.MinimumChannel
,
352 IoDesc
->u
.Dma
.MaximumChannel
);
357 /* Other stuff is fine */
363 /* Check if we found a matching descriptor */
366 PCM_RESOURCE_LIST NewList
;
367 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc
;
368 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr
;
369 BOOLEAN FoundResource
= TRUE
;
371 /* Setup the new CM descriptor */
372 NewDesc
.Type
= IoDesc
->Type
;
373 NewDesc
.Flags
= IoDesc
->Flags
;
374 NewDesc
.ShareDisposition
= IoDesc
->ShareDisposition
;
376 /* Let'se see if we can find a resource to satisfy this */
377 switch (IoDesc
->Type
)
379 case CmResourceTypeInterrupt
:
380 /* Find an available interrupt */
381 if (!IopFindInterruptResource(IoDesc
, &NewDesc
))
383 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
384 IoDesc
->u
.Interrupt
.MinimumVector
, IoDesc
->u
.Interrupt
.MaximumVector
);
386 FoundResource
= FALSE
;
390 case CmResourceTypePort
:
391 /* Find an available port range */
392 if (!IopFindPortResource(IoDesc
, &NewDesc
))
394 DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
395 IoDesc
->u
.Port
.MinimumAddress
.QuadPart
, IoDesc
->u
.Port
.MaximumAddress
.QuadPart
,
396 IoDesc
->u
.Port
.Length
);
398 FoundResource
= FALSE
;
402 case CmResourceTypeMemory
:
403 /* Find an available memory range */
404 if (!IopFindMemoryResource(IoDesc
, &NewDesc
))
406 DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
407 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
, IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
408 IoDesc
->u
.Memory
.Length
);
410 FoundResource
= FALSE
;
414 case CmResourceTypeBusNumber
:
415 /* Find an available bus address range */
416 if (!IopFindBusNumberResource(IoDesc
, &NewDesc
))
418 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
419 IoDesc
->u
.BusNumber
.MinBusNumber
, IoDesc
->u
.BusNumber
.MaxBusNumber
,
420 IoDesc
->u
.BusNumber
.Length
);
422 FoundResource
= FALSE
;
426 case CmResourceTypeDma
:
427 /* Find an available DMA channel */
428 if (!IopFindDmaResource(IoDesc
, &NewDesc
))
430 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
431 IoDesc
->u
.Dma
.MinimumChannel
, IoDesc
->u
.Dma
.MaximumChannel
);
433 FoundResource
= FALSE
;
438 DPRINT1("Unsupported resource type: %x\n", IoDesc
->Type
);
439 FoundResource
= FALSE
;
443 /* Check if it's missing and required */
444 if (!FoundResource
&& IoDesc
->Option
== 0)
446 /* Break out of this loop and try the next list */
447 DPRINT1("Unable to satisfy required resource in list %d\n", i
);
450 else if (!FoundResource
)
452 /* Try an alternate for this preferred descriptor */
453 AlternateRequired
= TRUE
;
458 /* Move on to the next preferred or required descriptor after this one */
459 AlternateRequired
= FALSE
;
462 /* Figure out what we need */
463 if (PartialList
== NULL
)
465 /* We need a new list */
466 NewList
= ExAllocatePool(PagedPool
, sizeof(CM_RESOURCE_LIST
));
468 return STATUS_NO_MEMORY
;
472 NewList
->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
473 NewList
->List
[0].BusNumber
= RequirementsList
->BusNumber
;
474 NewList
->List
[0].PartialResourceList
.Version
= 1;
475 NewList
->List
[0].PartialResourceList
.Revision
= 1;
476 NewList
->List
[0].PartialResourceList
.Count
= 1;
478 /* Set our pointer */
479 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[0];
483 /* Allocate the new larger list */
484 NewList
= ExAllocatePool(PagedPool
, PnpDetermineResourceListSize(*ResourceList
) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
486 return STATUS_NO_MEMORY
;
488 /* Copy the old stuff back */
489 RtlCopyMemory(NewList
, *ResourceList
, PnpDetermineResourceListSize(*ResourceList
));
491 /* Set our pointer */
492 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[NewList
->List
[0].PartialResourceList
.Count
];
494 /* Increment the descriptor count */
495 NewList
->List
[0].PartialResourceList
.Count
++;
497 /* Free the old list */
498 ExFreePool(*ResourceList
);
501 /* Copy the descriptor in */
504 /* Store the new list */
505 *ResourceList
= NewList
;
509 /* Check if we need an alternate with no resources left */
510 if (AlternateRequired
)
512 DPRINT1("Unable to satisfy preferred resource or alternates in list %d\n", i
);
514 /* Try the next alternate list */
518 /* We're done because we satisfied one of the alternate lists */
519 return STATUS_SUCCESS
;
522 /* We ran out of alternates */
523 DPRINT1("Out of alternate lists!\n");
528 ExFreePool(*ResourceList
);
529 *ResourceList
= NULL
;
533 return STATUS_CONFLICTING_ADDRESSES
;
538 IopCheckResourceDescriptor(
539 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
540 IN PCM_RESOURCE_LIST ResourceList
,
542 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
545 BOOLEAN Result
= FALSE
;
547 for (i
= 0; i
< ResourceList
->Count
; i
++)
549 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
550 for (ii
= 0; ii
< ResList
->Count
; ii
++)
552 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
554 /* We don't care about shared resources */
555 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
556 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
559 /* Make sure we're comparing the same types */
560 if (ResDesc
->Type
!= ResDesc2
->Type
)
563 switch (ResDesc
->Type
)
565 case CmResourceTypeMemory
:
566 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
567 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
568 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
569 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
570 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
574 DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
575 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
576 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
577 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
586 case CmResourceTypePort
:
587 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
588 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
589 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
590 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
591 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
595 DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
596 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
597 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
598 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
607 case CmResourceTypeInterrupt
:
608 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
612 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
613 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
614 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
623 case CmResourceTypeBusNumber
:
624 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
625 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
626 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
627 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
628 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
632 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
633 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
634 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
635 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
644 case CmResourceTypeDma
:
645 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
649 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
650 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
651 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
665 if (Result
&& ConflictingDescriptor
)
667 RtlCopyMemory(ConflictingDescriptor
,
669 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
677 IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode
)
679 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
680 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
681 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"AllocConfig");
682 HANDLE EnumKey
, InstanceKey
, ControlKey
;
684 OBJECT_ATTRIBUTES ObjectAttributes
;
686 /* Open the Enum key */
687 Status
= IopOpenRegistryKeyEx(&EnumKey
, NULL
, &EnumRoot
, KEY_ENUMERATE_SUB_KEYS
);
688 if (!NT_SUCCESS(Status
))
691 /* Open the instance key (eg. Root\PNP0A03) */
692 Status
= IopOpenRegistryKeyEx(&InstanceKey
, EnumKey
, &DeviceNode
->InstancePath
, KEY_ENUMERATE_SUB_KEYS
);
695 if (!NT_SUCCESS(Status
))
698 /* Create/Open the Control key */
699 InitializeObjectAttributes(&ObjectAttributes
,
701 OBJ_CASE_INSENSITIVE
,
704 Status
= ZwCreateKey(&ControlKey
,
711 ZwClose(InstanceKey
);
713 if (!NT_SUCCESS(Status
))
716 /* Write the resource list */
717 Status
= ZwSetValueKey(ControlKey
,
721 DeviceNode
->ResourceList
,
722 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
725 if (!NT_SUCCESS(Status
))
728 return STATUS_SUCCESS
;
733 IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode
)
735 IO_STACK_LOCATION Stack
;
736 IO_STATUS_BLOCK IoStatusBlock
;
739 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
741 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
742 Status
= IopInitiatePnpIrp(
743 DeviceNode
->PhysicalDeviceObject
,
745 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
747 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
749 DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
752 else if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
754 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
757 return STATUS_SUCCESS
;
762 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
766 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
767 UNICODE_STRING KeyName
;
768 OBJECT_ATTRIBUTES ObjectAttributes
;
770 RtlInitUnicodeString(&KeyName
,
771 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
772 InitializeObjectAttributes(&ObjectAttributes
,
774 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
777 Status
= ZwCreateKey(&ResourceMapKey
,
784 if (!NT_SUCCESS(Status
))
787 RtlInitUnicodeString(&KeyName
, Level1Key
);
788 InitializeObjectAttributes(&ObjectAttributes
,
790 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
793 Status
= ZwCreateKey(&PnpMgrLevel1
,
800 ZwClose(ResourceMapKey
);
801 if (!NT_SUCCESS(Status
))
804 RtlInitUnicodeString(&KeyName
, Level2Key
);
805 InitializeObjectAttributes(&ObjectAttributes
,
807 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
810 Status
= ZwCreateKey(&PnpMgrLevel2
,
817 ZwClose(PnpMgrLevel1
);
818 if (!NT_SUCCESS(Status
))
821 if (DeviceNode
->ResourceList
)
823 UNICODE_STRING NameU
;
824 UNICODE_STRING RawSuffix
, TranslatedSuffix
;
827 ASSERT(DeviceNode
->ResourceListTranslated
);
829 RtlInitUnicodeString(&TranslatedSuffix
, L
".Translated");
830 RtlInitUnicodeString(&RawSuffix
, L
".Raw");
832 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
833 DevicePropertyPhysicalDeviceObjectName
,
837 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
841 NameU
.Buffer
= ExAllocatePool(PagedPool
, OldLength
+ TranslatedSuffix
.Length
);
844 ZwClose(PnpMgrLevel2
);
845 return STATUS_INSUFFICIENT_RESOURCES
;
849 NameU
.MaximumLength
= (USHORT
)OldLength
+ TranslatedSuffix
.Length
;
851 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
852 DevicePropertyPhysicalDeviceObjectName
,
856 if (!NT_SUCCESS(Status
))
858 ZwClose(PnpMgrLevel2
);
859 ExFreePool(NameU
.Buffer
);
863 else if (!NT_SUCCESS(Status
))
866 ZwClose(PnpMgrLevel2
);
871 /* This should never happen */
875 NameU
.Length
= (USHORT
)OldLength
;
877 RtlAppendUnicodeStringToString(&NameU
, &RawSuffix
);
879 Status
= ZwSetValueKey(PnpMgrLevel2
,
883 DeviceNode
->ResourceList
,
884 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
885 if (!NT_SUCCESS(Status
))
887 ZwClose(PnpMgrLevel2
);
888 ExFreePool(NameU
.Buffer
);
892 /* "Remove" the suffix by setting the length back to what it used to be */
893 NameU
.Length
= (USHORT
)OldLength
;
895 RtlAppendUnicodeStringToString(&NameU
, &TranslatedSuffix
);
897 Status
= ZwSetValueKey(PnpMgrLevel2
,
901 DeviceNode
->ResourceListTranslated
,
902 PnpDetermineResourceListSize(DeviceNode
->ResourceListTranslated
));
903 ZwClose(PnpMgrLevel2
);
904 ExFreePool(NameU
.Buffer
);
906 if (!NT_SUCCESS(Status
))
911 ZwClose(PnpMgrLevel2
);
914 return STATUS_SUCCESS
;
918 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
920 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
925 IopTranslateDeviceResources(
926 IN PDEVICE_NODE DeviceNode
)
928 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
929 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
930 ULONG i
, j
, ListSize
;
933 if (!DeviceNode
->ResourceList
)
935 DeviceNode
->ResourceListTranslated
= NULL
;
936 return STATUS_SUCCESS
;
939 /* That's easy to translate a resource list. Just copy the
940 * untranslated one and change few fields in the copy
942 ListSize
= PnpDetermineResourceListSize(DeviceNode
->ResourceList
);
944 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, ListSize
);
945 if (!DeviceNode
->ResourceListTranslated
)
947 Status
= STATUS_NO_MEMORY
;
950 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, ListSize
);
952 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
954 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
955 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
957 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
958 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
959 switch (DescriptorRaw
->Type
)
961 case CmResourceTypePort
:
963 ULONG AddressSpace
= 1; /* IO space */
964 if (!HalTranslateBusAddress(
965 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
966 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
967 DescriptorRaw
->u
.Port
.Start
,
969 &DescriptorTranslated
->u
.Port
.Start
))
971 Status
= STATUS_UNSUCCESSFUL
;
972 DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Port
.Start
.QuadPart
);
976 if (AddressSpace
== 0)
978 DPRINT1("Guessed incorrect address space: 1 -> 0\n");
980 /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
981 * invalid for this state but I'm not 100% sure */
982 DescriptorRaw
->Flags
=
983 DescriptorTranslated
->Flags
= CM_RESOURCE_PORT_MEMORY
;
987 case CmResourceTypeInterrupt
:
989 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
990 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
991 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
992 DescriptorRaw
->u
.Interrupt
.Level
,
993 DescriptorRaw
->u
.Interrupt
.Vector
,
994 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
995 &DescriptorTranslated
->u
.Interrupt
.Affinity
);
997 if (!DescriptorTranslated
->u
.Interrupt
.Vector
)
999 Status
= STATUS_UNSUCCESSFUL
;
1000 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw
->u
.Interrupt
.Vector
,
1001 DescriptorRaw
->u
.Interrupt
.Level
);
1006 case CmResourceTypeMemory
:
1008 ULONG AddressSpace
= 0; /* Memory space */
1009 if (!HalTranslateBusAddress(
1010 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1011 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1012 DescriptorRaw
->u
.Memory
.Start
,
1014 &DescriptorTranslated
->u
.Memory
.Start
))
1016 Status
= STATUS_UNSUCCESSFUL
;
1017 DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Memory
.Start
.QuadPart
);
1021 if (AddressSpace
!= 0)
1023 DPRINT1("Guessed incorrect address space: 0 -> 1\n");
1025 /* This should never happen for memory space */
1030 case CmResourceTypeDma
:
1031 case CmResourceTypeBusNumber
:
1032 case CmResourceTypeDeviceSpecific
:
1036 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
1037 Status
= STATUS_NOT_IMPLEMENTED
;
1042 return STATUS_SUCCESS
;
1045 /* Yes! Also delete ResourceList because ResourceList and
1046 * ResourceListTranslated should be a pair! */
1047 ExFreePool(DeviceNode
->ResourceList
);
1048 DeviceNode
->ResourceList
= NULL
;
1049 if (DeviceNode
->ResourceListTranslated
)
1051 ExFreePool(DeviceNode
->ResourceListTranslated
);
1052 DeviceNode
->ResourceList
= NULL
;
1059 IopAssignDeviceResources(
1060 IN PDEVICE_NODE DeviceNode
)
1065 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1067 Status
= IopFilterResourceRequirements(DeviceNode
);
1068 if (!NT_SUCCESS(Status
))
1071 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1073 DeviceNode
->Flags
|= DNF_NO_RESOURCE_REQUIRED
;
1074 DeviceNode
->Flags
&= ~DNF_ASSIGNING_RESOURCES
;
1076 /* No resource needed for this device */
1077 DeviceNode
->ResourceList
= NULL
;
1078 DeviceNode
->ResourceListTranslated
= NULL
;
1080 return STATUS_SUCCESS
;
1083 if (DeviceNode
->BootResources
)
1085 ListSize
= PnpDetermineResourceListSize(DeviceNode
->BootResources
);
1087 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, ListSize
);
1088 if (!DeviceNode
->ResourceList
)
1090 Status
= STATUS_NO_MEMORY
;
1094 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, ListSize
);
1096 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1097 if (!NT_SUCCESS(Status
))
1099 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1100 ExFreePool(DeviceNode
->ResourceList
);
1101 DeviceNode
->ResourceList
= NULL
;
1106 /* We'll make this from the requirements */
1107 DeviceNode
->ResourceList
= NULL
;
1110 /* No resources requirements */
1111 if (!DeviceNode
->ResourceRequirements
)
1114 /* Call HAL to fixup our resource requirements list */
1115 HalAdjustResourceList(&DeviceNode
->ResourceRequirements
);
1117 /* Add resource requirements that aren't in the list we already got */
1118 Status
= IopFixupResourceListWithRequirements(DeviceNode
->ResourceRequirements
,
1119 &DeviceNode
->ResourceList
);
1120 if (!NT_SUCCESS(Status
))
1122 DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode
->InstancePath
);
1123 DeviceNode
->Problem
= CM_PROB_NORMAL_CONFLICT
;
1127 /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1128 ASSERT(IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
) != STATUS_CONFLICTING_ADDRESSES
);
1131 Status
= IopTranslateDeviceResources(DeviceNode
);
1132 if (!NT_SUCCESS(Status
))
1134 DeviceNode
->Problem
= CM_PROB_TRANSLATION_FAILED
;
1135 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode
->InstancePath
);
1139 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
1140 if (!NT_SUCCESS(Status
))
1143 Status
= IopUpdateControlKeyWithResources(DeviceNode
);
1144 if (!NT_SUCCESS(Status
))
1147 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
1149 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1151 return STATUS_SUCCESS
;
1154 if (DeviceNode
->ResourceList
)
1156 ExFreePool(DeviceNode
->ResourceList
);
1157 DeviceNode
->ResourceList
= NULL
;
1160 DeviceNode
->ResourceListTranslated
= NULL
;
1162 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1169 IopCheckForResourceConflict(
1170 IN PCM_RESOURCE_LIST ResourceList1
,
1171 IN PCM_RESOURCE_LIST ResourceList2
,
1173 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1176 BOOLEAN Result
= FALSE
;
1178 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1180 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1181 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1183 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1185 Result
= IopCheckResourceDescriptor(ResDesc
,
1188 ConflictingDescriptor
);
1189 if (Result
) goto ByeBye
;
1199 IopDetectResourceConflict(
1200 IN PCM_RESOURCE_LIST ResourceList
,
1202 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1204 OBJECT_ATTRIBUTES ObjectAttributes
;
1205 UNICODE_STRING KeyName
;
1206 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1207 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1208 PKEY_BASIC_INFORMATION KeyInformation
;
1209 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1210 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1211 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1214 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1215 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1216 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1217 if (!NT_SUCCESS(Status
))
1219 /* The key is missing which means we are the first device */
1220 return STATUS_SUCCESS
;
1225 Status
= ZwEnumerateKey(ResourceMapKey
,
1227 KeyBasicInformation
,
1231 if (Status
== STATUS_NO_MORE_ENTRIES
)
1233 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1235 KeyInformationLength
= RequiredLength
;
1236 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1237 if (!KeyInformation
)
1239 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1243 Status
= ZwEnumerateKey(ResourceMapKey
,
1245 KeyBasicInformation
,
1247 KeyInformationLength
,
1253 if (!NT_SUCCESS(Status
))
1256 KeyName
.Buffer
= KeyInformation
->Name
;
1257 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1258 InitializeObjectAttributes(&ObjectAttributes
,
1260 OBJ_CASE_INSENSITIVE
,
1263 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1264 ExFreePool(KeyInformation
);
1265 if (!NT_SUCCESS(Status
))
1270 Status
= ZwEnumerateKey(ChildKey2
,
1272 KeyBasicInformation
,
1276 if (Status
== STATUS_NO_MORE_ENTRIES
)
1278 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1280 KeyInformationLength
= RequiredLength
;
1281 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1282 if (!KeyInformation
)
1284 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1288 Status
= ZwEnumerateKey(ChildKey2
,
1290 KeyBasicInformation
,
1292 KeyInformationLength
,
1298 if (!NT_SUCCESS(Status
))
1301 KeyName
.Buffer
= KeyInformation
->Name
;
1302 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1303 InitializeObjectAttributes(&ObjectAttributes
,
1305 OBJ_CASE_INSENSITIVE
,
1308 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1309 ExFreePool(KeyInformation
);
1310 if (!NT_SUCCESS(Status
))
1315 Status
= ZwEnumerateValueKey(ChildKey3
,
1317 KeyValuePartialInformation
,
1321 if (Status
== STATUS_NO_MORE_ENTRIES
)
1323 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1325 KeyValueInformationLength
= RequiredLength
;
1326 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1327 if (!KeyValueInformation
)
1329 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1333 Status
= ZwEnumerateValueKey(ChildKey3
,
1335 KeyValuePartialInformation
,
1336 KeyValueInformation
,
1337 KeyValueInformationLength
,
1342 if (!NT_SUCCESS(Status
))
1345 Status
= ZwEnumerateValueKey(ChildKey3
,
1347 KeyValueBasicInformation
,
1351 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1353 KeyNameInformationLength
= RequiredLength
;
1354 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1355 if (!KeyNameInformation
)
1357 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1361 Status
= ZwEnumerateValueKey(ChildKey3
,
1363 KeyValueBasicInformation
,
1365 KeyNameInformationLength
,
1373 if (!NT_SUCCESS(Status
))
1376 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1378 /* Skip translated entries */
1379 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1381 ExFreePool(KeyNameInformation
);
1385 ExFreePool(KeyNameInformation
);
1387 if (IopCheckForResourceConflict(ResourceList
,
1388 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1390 ConflictingDescriptor
))
1392 ExFreePool(KeyValueInformation
);
1393 Status
= STATUS_CONFLICTING_ADDRESSES
;
1397 ExFreePool(KeyValueInformation
);
1403 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1404 ZwClose(ResourceMapKey
);
1405 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1407 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1410 if (Status
== STATUS_NO_MORE_ENTRIES
)
1411 Status
= STATUS_SUCCESS
;