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 DPRINT("Satisfying port requirement with 0x%I64x (length: 0x%x)\n", Start
, CmDesc
->u
.Port
.Length
);
140 DPRINT1("IopFindPortResource failed!\n");
147 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
148 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
152 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
153 ASSERT(IoDesc
->Type
== CmResourceTypeDma
);
155 for (Channel
= IoDesc
->u
.Dma
.MinimumChannel
;
156 Channel
<= IoDesc
->u
.Dma
.MaximumChannel
;
159 CmDesc
->u
.Dma
.Channel
= Channel
;
160 CmDesc
->u
.Dma
.Port
= 0;
162 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
164 DPRINT1("Satisfying DMA requirement with channel 0x%x\n", Channel
);
174 IopFindInterruptResource(
175 IN PIO_RESOURCE_DESCRIPTOR IoDesc
,
176 OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
)
180 ASSERT(IoDesc
->Type
== CmDesc
->Type
);
181 ASSERT(IoDesc
->Type
== CmResourceTypeInterrupt
);
183 for (Vector
= IoDesc
->u
.Interrupt
.MinimumVector
;
184 Vector
<= IoDesc
->u
.Interrupt
.MaximumVector
;
187 CmDesc
->u
.Interrupt
.Vector
= Vector
;
188 CmDesc
->u
.Interrupt
.Level
= Vector
;
189 CmDesc
->u
.Interrupt
.Affinity
= (KAFFINITY
)-1;
191 if (!IopCheckDescriptorForConflict(CmDesc
, NULL
))
193 DPRINT1("Satisfying interrupt requirement with IRQ 0x%x\n", Vector
);
202 IopFixupResourceListWithRequirements(
203 IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList
,
204 OUT PCM_RESOURCE_LIST
*ResourceList
)
207 BOOLEAN AlternateRequired
= FALSE
;
209 /* Save the initial resource count when we got here so we can restore if an alternate fails */
210 if (*ResourceList
!= NULL
)
211 OldCount
= (*ResourceList
)->List
[0].PartialResourceList
.Count
;
215 for (i
= 0; i
< RequirementsList
->AlternativeLists
; i
++)
218 PIO_RESOURCE_LIST ResList
= &RequirementsList
->List
[i
];
220 /* We need to get back to where we were before processing the last alternative list */
221 if (OldCount
== 0 && *ResourceList
!= NULL
)
223 /* Just free it and kill the pointer */
224 ExFreePool(*ResourceList
);
225 *ResourceList
= NULL
;
227 else if (OldCount
!= 0)
229 PCM_RESOURCE_LIST NewList
;
231 /* Let's resize it */
232 (*ResourceList
)->List
[0].PartialResourceList
.Count
= OldCount
;
234 /* Allocate the new smaller list */
235 NewList
= ExAllocatePool(PagedPool
, PnpDetermineResourceListSize(*ResourceList
));
237 return STATUS_NO_MEMORY
;
239 /* Copy the old stuff back */
240 RtlCopyMemory(NewList
, *ResourceList
, PnpDetermineResourceListSize(*ResourceList
));
242 /* Free the old one */
243 ExFreePool(*ResourceList
);
245 /* Store the pointer to the new one */
246 *ResourceList
= NewList
;
249 for (ii
= 0; ii
< ResList
->Count
; ii
++)
252 PCM_PARTIAL_RESOURCE_LIST PartialList
= (*ResourceList
) ? &(*ResourceList
)->List
[0].PartialResourceList
: NULL
;
253 PIO_RESOURCE_DESCRIPTOR IoDesc
= &ResList
->Descriptors
[ii
];
254 BOOLEAN Matched
= FALSE
;
256 /* Skip alternates if we don't need one */
257 if (!AlternateRequired
&& (IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
259 DPRINT("Skipping unneeded alternate\n");
263 /* Check if we couldn't satsify a requirement or its alternates */
264 if (AlternateRequired
&& !(IoDesc
->Option
& IO_RESOURCE_ALTERNATIVE
))
266 DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i
);
268 /* Break out of this loop and try the next list */
272 for (iii
= 0; PartialList
&& iii
< PartialList
->Count
&& !Matched
; iii
++)
274 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc
= &PartialList
->PartialDescriptors
[iii
];
276 /* First check types */
277 if (IoDesc
->Type
!= CmDesc
->Type
)
280 switch (IoDesc
->Type
)
282 case CmResourceTypeInterrupt
:
283 /* Make sure it satisfies our vector range */
284 if (CmDesc
->u
.Interrupt
.Vector
>= IoDesc
->u
.Interrupt
.MinimumVector
&&
285 CmDesc
->u
.Interrupt
.Vector
<= IoDesc
->u
.Interrupt
.MaximumVector
)
292 DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n",
293 CmDesc
->u
.Interrupt
.Vector
,
294 IoDesc
->u
.Interrupt
.MinimumVector
,
295 IoDesc
->u
.Interrupt
.MaximumVector
);
299 case CmResourceTypeMemory
:
300 case CmResourceTypePort
:
301 /* Make sure the length matches and it satisfies our address range */
302 if (CmDesc
->u
.Memory
.Length
== IoDesc
->u
.Memory
.Length
&&
303 CmDesc
->u
.Memory
.Start
.QuadPart
>= IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
&&
304 CmDesc
->u
.Memory
.Start
.QuadPart
+ CmDesc
->u
.Memory
.Length
- 1 <= IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
)
311 DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n",
312 CmDesc
->u
.Memory
.Start
.QuadPart
,
313 CmDesc
->u
.Memory
.Length
,
314 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
,
315 IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
316 IoDesc
->u
.Memory
.Length
);
320 case CmResourceTypeBusNumber
:
321 /* Make sure the length matches and it satisfies our bus number range */
322 if (CmDesc
->u
.BusNumber
.Length
== IoDesc
->u
.BusNumber
.Length
&&
323 CmDesc
->u
.BusNumber
.Start
>= IoDesc
->u
.BusNumber
.MinBusNumber
&&
324 CmDesc
->u
.BusNumber
.Start
+ CmDesc
->u
.BusNumber
.Length
- 1 <= IoDesc
->u
.BusNumber
.MaxBusNumber
)
331 DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n",
332 CmDesc
->u
.BusNumber
.Start
,
333 CmDesc
->u
.BusNumber
.Length
,
334 IoDesc
->u
.BusNumber
.MinBusNumber
,
335 IoDesc
->u
.BusNumber
.MaxBusNumber
,
336 IoDesc
->u
.BusNumber
.Length
);
340 case CmResourceTypeDma
:
341 /* Make sure it fits in our channel range */
342 if (CmDesc
->u
.Dma
.Channel
>= IoDesc
->u
.Dma
.MinimumChannel
&&
343 CmDesc
->u
.Dma
.Channel
<= IoDesc
->u
.Dma
.MaximumChannel
)
350 DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n",
351 CmDesc
->u
.Dma
.Channel
,
352 IoDesc
->u
.Dma
.MinimumChannel
,
353 IoDesc
->u
.Dma
.MaximumChannel
);
358 /* Other stuff is fine */
364 /* Check if we found a matching descriptor */
367 PCM_RESOURCE_LIST NewList
;
368 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc
;
369 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr
;
370 BOOLEAN FoundResource
= TRUE
;
372 /* Setup the new CM descriptor */
373 NewDesc
.Type
= IoDesc
->Type
;
374 NewDesc
.Flags
= IoDesc
->Flags
;
375 NewDesc
.ShareDisposition
= IoDesc
->ShareDisposition
;
377 /* Let'se see if we can find a resource to satisfy this */
378 switch (IoDesc
->Type
)
380 case CmResourceTypeInterrupt
:
381 /* Find an available interrupt */
382 if (!IopFindInterruptResource(IoDesc
, &NewDesc
))
384 DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
385 IoDesc
->u
.Interrupt
.MinimumVector
, IoDesc
->u
.Interrupt
.MaximumVector
);
387 FoundResource
= FALSE
;
391 case CmResourceTypePort
:
392 /* Find an available port range */
393 if (!IopFindPortResource(IoDesc
, &NewDesc
))
395 DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
396 IoDesc
->u
.Port
.MinimumAddress
.QuadPart
, IoDesc
->u
.Port
.MaximumAddress
.QuadPart
,
397 IoDesc
->u
.Port
.Length
);
399 FoundResource
= FALSE
;
403 case CmResourceTypeMemory
:
404 /* Find an available memory range */
405 if (!IopFindMemoryResource(IoDesc
, &NewDesc
))
407 DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
408 IoDesc
->u
.Memory
.MinimumAddress
.QuadPart
, IoDesc
->u
.Memory
.MaximumAddress
.QuadPart
,
409 IoDesc
->u
.Memory
.Length
);
411 FoundResource
= FALSE
;
415 case CmResourceTypeBusNumber
:
416 /* Find an available bus address range */
417 if (!IopFindBusNumberResource(IoDesc
, &NewDesc
))
419 DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
420 IoDesc
->u
.BusNumber
.MinBusNumber
, IoDesc
->u
.BusNumber
.MaxBusNumber
,
421 IoDesc
->u
.BusNumber
.Length
);
423 FoundResource
= FALSE
;
427 case CmResourceTypeDma
:
428 /* Find an available DMA channel */
429 if (!IopFindDmaResource(IoDesc
, &NewDesc
))
431 DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
432 IoDesc
->u
.Dma
.MinimumChannel
, IoDesc
->u
.Dma
.MaximumChannel
);
434 FoundResource
= FALSE
;
439 DPRINT1("Unsupported resource type: %x\n", IoDesc
->Type
);
440 FoundResource
= FALSE
;
444 /* Check if it's missing and required */
445 if (!FoundResource
&& IoDesc
->Option
== 0)
447 /* Break out of this loop and try the next list */
448 DPRINT1("Unable to satisfy required resource in list %lu\n", i
);
451 else if (!FoundResource
)
453 /* Try an alternate for this preferred descriptor */
454 AlternateRequired
= TRUE
;
459 /* Move on to the next preferred or required descriptor after this one */
460 AlternateRequired
= FALSE
;
463 /* Figure out what we need */
464 if (PartialList
== NULL
)
466 /* We need a new list */
467 NewList
= ExAllocatePool(PagedPool
, sizeof(CM_RESOURCE_LIST
));
469 return STATUS_NO_MEMORY
;
473 NewList
->List
[0].InterfaceType
= RequirementsList
->InterfaceType
;
474 NewList
->List
[0].BusNumber
= RequirementsList
->BusNumber
;
475 NewList
->List
[0].PartialResourceList
.Version
= 1;
476 NewList
->List
[0].PartialResourceList
.Revision
= 1;
477 NewList
->List
[0].PartialResourceList
.Count
= 1;
479 /* Set our pointer */
480 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[0];
484 /* Allocate the new larger list */
485 NewList
= ExAllocatePool(PagedPool
, PnpDetermineResourceListSize(*ResourceList
) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
487 return STATUS_NO_MEMORY
;
489 /* Copy the old stuff back */
490 RtlCopyMemory(NewList
, *ResourceList
, PnpDetermineResourceListSize(*ResourceList
));
492 /* Set our pointer */
493 DescPtr
= &NewList
->List
[0].PartialResourceList
.PartialDescriptors
[NewList
->List
[0].PartialResourceList
.Count
];
495 /* Increment the descriptor count */
496 NewList
->List
[0].PartialResourceList
.Count
++;
498 /* Free the old list */
499 ExFreePool(*ResourceList
);
502 /* Copy the descriptor in */
505 /* Store the new list */
506 *ResourceList
= NewList
;
510 /* Check if we need an alternate with no resources left */
511 if (AlternateRequired
)
513 DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i
);
515 /* Try the next alternate list */
519 /* We're done because we satisfied one of the alternate lists */
520 return STATUS_SUCCESS
;
523 /* We ran out of alternates */
524 DPRINT1("Out of alternate lists!\n");
529 ExFreePool(*ResourceList
);
530 *ResourceList
= NULL
;
534 return STATUS_CONFLICTING_ADDRESSES
;
539 IopCheckResourceDescriptor(
540 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
,
541 IN PCM_RESOURCE_LIST ResourceList
,
543 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
546 BOOLEAN Result
= FALSE
;
548 for (i
= 0; i
< ResourceList
->Count
; i
++)
550 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList
->List
[i
].PartialResourceList
;
551 for (ii
= 0; ii
< ResList
->Count
; ii
++)
553 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2
= &ResList
->PartialDescriptors
[ii
];
555 /* We don't care about shared resources */
556 if (ResDesc
->ShareDisposition
== CmResourceShareShared
&&
557 ResDesc2
->ShareDisposition
== CmResourceShareShared
)
560 /* Make sure we're comparing the same types */
561 if (ResDesc
->Type
!= ResDesc2
->Type
)
564 switch (ResDesc
->Type
)
566 case CmResourceTypeMemory
:
567 if ((ResDesc
->u
.Memory
.Start
.QuadPart
< ResDesc2
->u
.Memory
.Start
.QuadPart
&&
568 ResDesc
->u
.Memory
.Start
.QuadPart
+ ResDesc
->u
.Memory
.Length
>
569 ResDesc2
->u
.Memory
.Start
.QuadPart
) || (ResDesc2
->u
.Memory
.Start
.QuadPart
<
570 ResDesc
->u
.Memory
.Start
.QuadPart
&& ResDesc2
->u
.Memory
.Start
.QuadPart
+
571 ResDesc2
->u
.Memory
.Length
> ResDesc
->u
.Memory
.Start
.QuadPart
))
575 DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
576 ResDesc
->u
.Memory
.Start
.QuadPart
, ResDesc
->u
.Memory
.Start
.QuadPart
+
577 ResDesc
->u
.Memory
.Length
, ResDesc2
->u
.Memory
.Start
.QuadPart
,
578 ResDesc2
->u
.Memory
.Start
.QuadPart
+ ResDesc2
->u
.Memory
.Length
);
587 case CmResourceTypePort
:
588 if ((ResDesc
->u
.Port
.Start
.QuadPart
< ResDesc2
->u
.Port
.Start
.QuadPart
&&
589 ResDesc
->u
.Port
.Start
.QuadPart
+ ResDesc
->u
.Port
.Length
>
590 ResDesc2
->u
.Port
.Start
.QuadPart
) || (ResDesc2
->u
.Port
.Start
.QuadPart
<
591 ResDesc
->u
.Port
.Start
.QuadPart
&& ResDesc2
->u
.Port
.Start
.QuadPart
+
592 ResDesc2
->u
.Port
.Length
> ResDesc
->u
.Port
.Start
.QuadPart
))
596 DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
597 ResDesc
->u
.Port
.Start
.QuadPart
, ResDesc
->u
.Port
.Start
.QuadPart
+
598 ResDesc
->u
.Port
.Length
, ResDesc2
->u
.Port
.Start
.QuadPart
,
599 ResDesc2
->u
.Port
.Start
.QuadPart
+ ResDesc2
->u
.Port
.Length
);
608 case CmResourceTypeInterrupt
:
609 if (ResDesc
->u
.Interrupt
.Vector
== ResDesc2
->u
.Interrupt
.Vector
)
613 DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
614 ResDesc
->u
.Interrupt
.Vector
, ResDesc
->u
.Interrupt
.Level
,
615 ResDesc2
->u
.Interrupt
.Vector
, ResDesc2
->u
.Interrupt
.Level
);
624 case CmResourceTypeBusNumber
:
625 if ((ResDesc
->u
.BusNumber
.Start
< ResDesc2
->u
.BusNumber
.Start
&&
626 ResDesc
->u
.BusNumber
.Start
+ ResDesc
->u
.BusNumber
.Length
>
627 ResDesc2
->u
.BusNumber
.Start
) || (ResDesc2
->u
.BusNumber
.Start
<
628 ResDesc
->u
.BusNumber
.Start
&& ResDesc2
->u
.BusNumber
.Start
+
629 ResDesc2
->u
.BusNumber
.Length
> ResDesc
->u
.BusNumber
.Start
))
633 DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
634 ResDesc
->u
.BusNumber
.Start
, ResDesc
->u
.BusNumber
.Start
+
635 ResDesc
->u
.BusNumber
.Length
, ResDesc2
->u
.BusNumber
.Start
,
636 ResDesc2
->u
.BusNumber
.Start
+ ResDesc2
->u
.BusNumber
.Length
);
645 case CmResourceTypeDma
:
646 if (ResDesc
->u
.Dma
.Channel
== ResDesc2
->u
.Dma
.Channel
)
650 DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
651 ResDesc
->u
.Dma
.Channel
, ResDesc
->u
.Dma
.Port
,
652 ResDesc2
->u
.Dma
.Channel
, ResDesc2
->u
.Dma
.Port
);
666 if (Result
&& ConflictingDescriptor
)
668 RtlCopyMemory(ConflictingDescriptor
,
670 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
678 IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode
)
680 UNICODE_STRING EnumRoot
= RTL_CONSTANT_STRING(ENUM_ROOT
);
681 UNICODE_STRING Control
= RTL_CONSTANT_STRING(L
"Control");
682 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"AllocConfig");
683 HANDLE EnumKey
, InstanceKey
, ControlKey
;
685 OBJECT_ATTRIBUTES ObjectAttributes
;
687 /* Open the Enum key */
688 Status
= IopOpenRegistryKeyEx(&EnumKey
, NULL
, &EnumRoot
, KEY_ENUMERATE_SUB_KEYS
);
689 if (!NT_SUCCESS(Status
))
692 /* Open the instance key (eg. Root\PNP0A03) */
693 Status
= IopOpenRegistryKeyEx(&InstanceKey
, EnumKey
, &DeviceNode
->InstancePath
, KEY_ENUMERATE_SUB_KEYS
);
696 if (!NT_SUCCESS(Status
))
699 /* Create/Open the Control key */
700 InitializeObjectAttributes(&ObjectAttributes
,
702 OBJ_CASE_INSENSITIVE
,
705 Status
= ZwCreateKey(&ControlKey
,
712 ZwClose(InstanceKey
);
714 if (!NT_SUCCESS(Status
))
717 /* Write the resource list */
718 Status
= ZwSetValueKey(ControlKey
,
722 DeviceNode
->ResourceList
,
723 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
726 if (!NT_SUCCESS(Status
))
729 return STATUS_SUCCESS
;
734 IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode
)
736 IO_STACK_LOCATION Stack
;
737 IO_STATUS_BLOCK IoStatusBlock
;
740 DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
742 Stack
.Parameters
.FilterResourceRequirements
.IoResourceRequirementList
= DeviceNode
->ResourceRequirements
;
743 Status
= IopInitiatePnpIrp(
744 DeviceNode
->PhysicalDeviceObject
,
746 IRP_MN_FILTER_RESOURCE_REQUIREMENTS
,
748 if (!NT_SUCCESS(Status
) && Status
!= STATUS_NOT_SUPPORTED
)
750 DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
753 else if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
)
755 DeviceNode
->ResourceRequirements
= (PIO_RESOURCE_REQUIREMENTS_LIST
)IoStatusBlock
.Information
;
758 return STATUS_SUCCESS
;
763 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode
, PWCHAR Level1Key
, PWCHAR Level2Key
)
767 HANDLE PnpMgrLevel1
, PnpMgrLevel2
, ResourceMapKey
;
768 UNICODE_STRING KeyName
;
769 OBJECT_ATTRIBUTES ObjectAttributes
;
771 RtlInitUnicodeString(&KeyName
,
772 L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
773 InitializeObjectAttributes(&ObjectAttributes
,
775 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
778 Status
= ZwCreateKey(&ResourceMapKey
,
785 if (!NT_SUCCESS(Status
))
788 RtlInitUnicodeString(&KeyName
, Level1Key
);
789 InitializeObjectAttributes(&ObjectAttributes
,
791 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
794 Status
= ZwCreateKey(&PnpMgrLevel1
,
801 ZwClose(ResourceMapKey
);
802 if (!NT_SUCCESS(Status
))
805 RtlInitUnicodeString(&KeyName
, Level2Key
);
806 InitializeObjectAttributes(&ObjectAttributes
,
808 OBJ_CASE_INSENSITIVE
| OBJ_OPENIF
,
811 Status
= ZwCreateKey(&PnpMgrLevel2
,
818 ZwClose(PnpMgrLevel1
);
819 if (!NT_SUCCESS(Status
))
822 if (DeviceNode
->ResourceList
)
824 UNICODE_STRING NameU
;
825 UNICODE_STRING RawSuffix
, TranslatedSuffix
;
828 ASSERT(DeviceNode
->ResourceListTranslated
);
830 RtlInitUnicodeString(&TranslatedSuffix
, L
".Translated");
831 RtlInitUnicodeString(&RawSuffix
, L
".Raw");
833 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
834 DevicePropertyPhysicalDeviceObjectName
,
838 if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
842 NameU
.Buffer
= ExAllocatePool(PagedPool
, OldLength
+ TranslatedSuffix
.Length
);
845 ZwClose(PnpMgrLevel2
);
846 return STATUS_INSUFFICIENT_RESOURCES
;
850 NameU
.MaximumLength
= (USHORT
)OldLength
+ TranslatedSuffix
.Length
;
852 Status
= IoGetDeviceProperty(DeviceNode
->PhysicalDeviceObject
,
853 DevicePropertyPhysicalDeviceObjectName
,
857 if (!NT_SUCCESS(Status
))
859 ZwClose(PnpMgrLevel2
);
860 ExFreePool(NameU
.Buffer
);
864 else if (!NT_SUCCESS(Status
))
867 ZwClose(PnpMgrLevel2
);
872 /* This should never happen */
876 NameU
.Length
= (USHORT
)OldLength
;
878 RtlAppendUnicodeStringToString(&NameU
, &RawSuffix
);
880 Status
= ZwSetValueKey(PnpMgrLevel2
,
884 DeviceNode
->ResourceList
,
885 PnpDetermineResourceListSize(DeviceNode
->ResourceList
));
886 if (!NT_SUCCESS(Status
))
888 ZwClose(PnpMgrLevel2
);
889 ExFreePool(NameU
.Buffer
);
893 /* "Remove" the suffix by setting the length back to what it used to be */
894 NameU
.Length
= (USHORT
)OldLength
;
896 RtlAppendUnicodeStringToString(&NameU
, &TranslatedSuffix
);
898 Status
= ZwSetValueKey(PnpMgrLevel2
,
902 DeviceNode
->ResourceListTranslated
,
903 PnpDetermineResourceListSize(DeviceNode
->ResourceListTranslated
));
904 ZwClose(PnpMgrLevel2
);
905 ExFreePool(NameU
.Buffer
);
907 if (!NT_SUCCESS(Status
))
912 ZwClose(PnpMgrLevel2
);
915 return STATUS_SUCCESS
;
919 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode
)
921 return IopUpdateResourceMap(DeviceNode
, L
"PnP Manager", L
"PnpManager");
926 IopTranslateDeviceResources(
927 IN PDEVICE_NODE DeviceNode
)
929 PCM_PARTIAL_RESOURCE_LIST pPartialResourceList
;
930 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw
, DescriptorTranslated
;
931 ULONG i
, j
, ListSize
;
934 if (!DeviceNode
->ResourceList
)
936 DeviceNode
->ResourceListTranslated
= NULL
;
937 return STATUS_SUCCESS
;
940 /* That's easy to translate a resource list. Just copy the
941 * untranslated one and change few fields in the copy
943 ListSize
= PnpDetermineResourceListSize(DeviceNode
->ResourceList
);
945 DeviceNode
->ResourceListTranslated
= ExAllocatePool(PagedPool
, ListSize
);
946 if (!DeviceNode
->ResourceListTranslated
)
948 Status
= STATUS_NO_MEMORY
;
951 RtlCopyMemory(DeviceNode
->ResourceListTranslated
, DeviceNode
->ResourceList
, ListSize
);
953 for (i
= 0; i
< DeviceNode
->ResourceList
->Count
; i
++)
955 pPartialResourceList
= &DeviceNode
->ResourceList
->List
[i
].PartialResourceList
;
956 for (j
= 0; j
< pPartialResourceList
->Count
; j
++)
958 DescriptorRaw
= &pPartialResourceList
->PartialDescriptors
[j
];
959 DescriptorTranslated
= &DeviceNode
->ResourceListTranslated
->List
[i
].PartialResourceList
.PartialDescriptors
[j
];
960 switch (DescriptorRaw
->Type
)
962 case CmResourceTypePort
:
964 ULONG AddressSpace
= 1; /* IO space */
965 if (!HalTranslateBusAddress(
966 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
967 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
968 DescriptorRaw
->u
.Port
.Start
,
970 &DescriptorTranslated
->u
.Port
.Start
))
972 Status
= STATUS_UNSUCCESSFUL
;
973 DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Port
.Start
.QuadPart
);
977 if (AddressSpace
== 0)
979 DPRINT1("Guessed incorrect address space: 1 -> 0\n");
981 /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
982 * invalid for this state but I'm not 100% sure */
983 DescriptorRaw
->Flags
=
984 DescriptorTranslated
->Flags
= CM_RESOURCE_PORT_MEMORY
;
988 case CmResourceTypeInterrupt
:
990 DescriptorTranslated
->u
.Interrupt
.Vector
= HalGetInterruptVector(
991 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
992 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
993 DescriptorRaw
->u
.Interrupt
.Level
,
994 DescriptorRaw
->u
.Interrupt
.Vector
,
995 (PKIRQL
)&DescriptorTranslated
->u
.Interrupt
.Level
,
996 &DescriptorTranslated
->u
.Interrupt
.Affinity
);
998 if (!DescriptorTranslated
->u
.Interrupt
.Vector
)
1000 Status
= STATUS_UNSUCCESSFUL
;
1001 DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw
->u
.Interrupt
.Vector
,
1002 DescriptorRaw
->u
.Interrupt
.Level
);
1007 case CmResourceTypeMemory
:
1009 ULONG AddressSpace
= 0; /* Memory space */
1010 if (!HalTranslateBusAddress(
1011 DeviceNode
->ResourceList
->List
[i
].InterfaceType
,
1012 DeviceNode
->ResourceList
->List
[i
].BusNumber
,
1013 DescriptorRaw
->u
.Memory
.Start
,
1015 &DescriptorTranslated
->u
.Memory
.Start
))
1017 Status
= STATUS_UNSUCCESSFUL
;
1018 DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw
->u
.Memory
.Start
.QuadPart
);
1022 if (AddressSpace
!= 0)
1024 DPRINT1("Guessed incorrect address space: 0 -> 1\n");
1026 /* This should never happen for memory space */
1031 case CmResourceTypeDma
:
1032 case CmResourceTypeBusNumber
:
1033 case CmResourceTypeDeviceSpecific
:
1037 DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw
->Type
);
1038 Status
= STATUS_NOT_IMPLEMENTED
;
1043 return STATUS_SUCCESS
;
1046 /* Yes! Also delete ResourceList because ResourceList and
1047 * ResourceListTranslated should be a pair! */
1048 ExFreePool(DeviceNode
->ResourceList
);
1049 DeviceNode
->ResourceList
= NULL
;
1050 if (DeviceNode
->ResourceListTranslated
)
1052 ExFreePool(DeviceNode
->ResourceListTranslated
);
1053 DeviceNode
->ResourceList
= NULL
;
1060 IopAssignDeviceResources(
1061 IN PDEVICE_NODE DeviceNode
)
1066 IopDeviceNodeSetFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1068 Status
= IopFilterResourceRequirements(DeviceNode
);
1069 if (!NT_SUCCESS(Status
))
1072 if (!DeviceNode
->BootResources
&& !DeviceNode
->ResourceRequirements
)
1074 DeviceNode
->Flags
|= DNF_NO_RESOURCE_REQUIRED
;
1075 DeviceNode
->Flags
&= ~DNF_ASSIGNING_RESOURCES
;
1077 /* No resource needed for this device */
1078 DeviceNode
->ResourceList
= NULL
;
1079 DeviceNode
->ResourceListTranslated
= NULL
;
1081 return STATUS_SUCCESS
;
1084 if (DeviceNode
->BootResources
)
1086 ListSize
= PnpDetermineResourceListSize(DeviceNode
->BootResources
);
1088 DeviceNode
->ResourceList
= ExAllocatePool(PagedPool
, ListSize
);
1089 if (!DeviceNode
->ResourceList
)
1091 Status
= STATUS_NO_MEMORY
;
1095 RtlCopyMemory(DeviceNode
->ResourceList
, DeviceNode
->BootResources
, ListSize
);
1097 Status
= IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
);
1098 if (!NT_SUCCESS(Status
))
1100 DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode
->InstancePath
);
1101 ExFreePool(DeviceNode
->ResourceList
);
1102 DeviceNode
->ResourceList
= NULL
;
1107 /* We'll make this from the requirements */
1108 DeviceNode
->ResourceList
= NULL
;
1111 /* No resources requirements */
1112 if (!DeviceNode
->ResourceRequirements
)
1115 /* Call HAL to fixup our resource requirements list */
1116 HalAdjustResourceList(&DeviceNode
->ResourceRequirements
);
1118 /* Add resource requirements that aren't in the list we already got */
1119 Status
= IopFixupResourceListWithRequirements(DeviceNode
->ResourceRequirements
,
1120 &DeviceNode
->ResourceList
);
1121 if (!NT_SUCCESS(Status
))
1123 DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode
->InstancePath
);
1124 DeviceNode
->Problem
= CM_PROB_NORMAL_CONFLICT
;
1128 /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1129 ASSERT(IopDetectResourceConflict(DeviceNode
->ResourceList
, FALSE
, NULL
) != STATUS_CONFLICTING_ADDRESSES
);
1132 Status
= IopTranslateDeviceResources(DeviceNode
);
1133 if (!NT_SUCCESS(Status
))
1135 DeviceNode
->Problem
= CM_PROB_TRANSLATION_FAILED
;
1136 DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode
->InstancePath
);
1140 Status
= IopUpdateResourceMapForPnPDevice(DeviceNode
);
1141 if (!NT_SUCCESS(Status
))
1144 Status
= IopUpdateControlKeyWithResources(DeviceNode
);
1145 if (!NT_SUCCESS(Status
))
1148 IopDeviceNodeSetFlag(DeviceNode
, DNF_RESOURCE_ASSIGNED
);
1150 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1152 return STATUS_SUCCESS
;
1155 if (DeviceNode
->ResourceList
)
1157 ExFreePool(DeviceNode
->ResourceList
);
1158 DeviceNode
->ResourceList
= NULL
;
1161 DeviceNode
->ResourceListTranslated
= NULL
;
1163 IopDeviceNodeClearFlag(DeviceNode
, DNF_ASSIGNING_RESOURCES
);
1170 IopCheckForResourceConflict(
1171 IN PCM_RESOURCE_LIST ResourceList1
,
1172 IN PCM_RESOURCE_LIST ResourceList2
,
1174 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1177 BOOLEAN Result
= FALSE
;
1179 for (i
= 0; i
< ResourceList1
->Count
; i
++)
1181 PCM_PARTIAL_RESOURCE_LIST ResList
= &ResourceList1
->List
[i
].PartialResourceList
;
1182 for (ii
= 0; ii
< ResList
->Count
; ii
++)
1184 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc
= &ResList
->PartialDescriptors
[ii
];
1186 Result
= IopCheckResourceDescriptor(ResDesc
,
1189 ConflictingDescriptor
);
1190 if (Result
) goto ByeBye
;
1200 IopDetectResourceConflict(
1201 IN PCM_RESOURCE_LIST ResourceList
,
1203 OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor
)
1205 OBJECT_ATTRIBUTES ObjectAttributes
;
1206 UNICODE_STRING KeyName
;
1207 HANDLE ResourceMapKey
= INVALID_HANDLE_VALUE
, ChildKey2
= INVALID_HANDLE_VALUE
, ChildKey3
= INVALID_HANDLE_VALUE
;
1208 ULONG KeyInformationLength
, RequiredLength
, KeyValueInformationLength
, KeyNameInformationLength
;
1209 PKEY_BASIC_INFORMATION KeyInformation
;
1210 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
1211 PKEY_VALUE_BASIC_INFORMATION KeyNameInformation
;
1212 ULONG ChildKeyIndex1
= 0, ChildKeyIndex2
= 0, ChildKeyIndex3
= 0;
1215 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1216 InitializeObjectAttributes(&ObjectAttributes
, &KeyName
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1217 Status
= ZwOpenKey(&ResourceMapKey
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1218 if (!NT_SUCCESS(Status
))
1220 /* The key is missing which means we are the first device */
1221 return STATUS_SUCCESS
;
1226 Status
= ZwEnumerateKey(ResourceMapKey
,
1228 KeyBasicInformation
,
1232 if (Status
== STATUS_NO_MORE_ENTRIES
)
1234 else if (Status
== STATUS_BUFFER_OVERFLOW
|| Status
== STATUS_BUFFER_TOO_SMALL
)
1236 KeyInformationLength
= RequiredLength
;
1237 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1238 if (!KeyInformation
)
1240 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1244 Status
= ZwEnumerateKey(ResourceMapKey
,
1246 KeyBasicInformation
,
1248 KeyInformationLength
,
1254 if (!NT_SUCCESS(Status
))
1257 KeyName
.Buffer
= KeyInformation
->Name
;
1258 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1259 InitializeObjectAttributes(&ObjectAttributes
,
1261 OBJ_CASE_INSENSITIVE
,
1264 Status
= ZwOpenKey(&ChildKey2
, KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
, &ObjectAttributes
);
1265 ExFreePool(KeyInformation
);
1266 if (!NT_SUCCESS(Status
))
1271 Status
= ZwEnumerateKey(ChildKey2
,
1273 KeyBasicInformation
,
1277 if (Status
== STATUS_NO_MORE_ENTRIES
)
1279 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1281 KeyInformationLength
= RequiredLength
;
1282 KeyInformation
= ExAllocatePool(PagedPool
, KeyInformationLength
);
1283 if (!KeyInformation
)
1285 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1289 Status
= ZwEnumerateKey(ChildKey2
,
1291 KeyBasicInformation
,
1293 KeyInformationLength
,
1299 if (!NT_SUCCESS(Status
))
1302 KeyName
.Buffer
= KeyInformation
->Name
;
1303 KeyName
.MaximumLength
= KeyName
.Length
= (USHORT
)KeyInformation
->NameLength
;
1304 InitializeObjectAttributes(&ObjectAttributes
,
1306 OBJ_CASE_INSENSITIVE
,
1309 Status
= ZwOpenKey(&ChildKey3
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1310 ExFreePool(KeyInformation
);
1311 if (!NT_SUCCESS(Status
))
1316 Status
= ZwEnumerateValueKey(ChildKey3
,
1318 KeyValuePartialInformation
,
1322 if (Status
== STATUS_NO_MORE_ENTRIES
)
1324 else if (Status
== STATUS_BUFFER_TOO_SMALL
)
1326 KeyValueInformationLength
= RequiredLength
;
1327 KeyValueInformation
= ExAllocatePool(PagedPool
, KeyValueInformationLength
);
1328 if (!KeyValueInformation
)
1330 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1334 Status
= ZwEnumerateValueKey(ChildKey3
,
1336 KeyValuePartialInformation
,
1337 KeyValueInformation
,
1338 KeyValueInformationLength
,
1343 if (!NT_SUCCESS(Status
))
1346 Status
= ZwEnumerateValueKey(ChildKey3
,
1348 KeyValueBasicInformation
,
1352 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1354 KeyNameInformationLength
= RequiredLength
;
1355 KeyNameInformation
= ExAllocatePool(PagedPool
, KeyNameInformationLength
+ sizeof(WCHAR
));
1356 if (!KeyNameInformation
)
1358 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1362 Status
= ZwEnumerateValueKey(ChildKey3
,
1364 KeyValueBasicInformation
,
1366 KeyNameInformationLength
,
1374 if (!NT_SUCCESS(Status
))
1377 KeyNameInformation
->Name
[KeyNameInformation
->NameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1379 /* Skip translated entries */
1380 if (wcsstr(KeyNameInformation
->Name
, L
".Translated"))
1382 ExFreePool(KeyNameInformation
);
1386 ExFreePool(KeyNameInformation
);
1388 if (IopCheckForResourceConflict(ResourceList
,
1389 (PCM_RESOURCE_LIST
)KeyValueInformation
->Data
,
1391 ConflictingDescriptor
))
1393 ExFreePool(KeyValueInformation
);
1394 Status
= STATUS_CONFLICTING_ADDRESSES
;
1398 ExFreePool(KeyValueInformation
);
1404 if (ResourceMapKey
!= INVALID_HANDLE_VALUE
)
1405 ZwClose(ResourceMapKey
);
1406 if (ChildKey2
!= INVALID_HANDLE_VALUE
)
1408 if (ChildKey3
!= INVALID_HANDLE_VALUE
)
1411 if (Status
== STATUS_NO_MORE_ENTRIES
)
1412 Status
= STATUS_SUCCESS
;