Windows2000/private/ntos/io/filter.c

913 lines
28 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
All rights reserved
Module Name:
filter.c
Abstract:
This module contains support functions for IoAssignResources to filter caller's
IoRequirementResourceList.
Some of the stuff here is copied from KenR's Hal code.
Author:
Shie-Lin Tzong (shielint) Apr-7-1995
Environment:
Kernel mode only.
Revision History:
*/
#include "iop.h"
#if _PNP_POWER_
typedef struct _NRParams {
PIO_RESOURCE_DESCRIPTOR InDesc;
PIO_RESOURCE_DESCRIPTOR OutDesc;
PSUPPORTED_RANGE CurrentPosition;
LONGLONG Base;
LONGLONG Limit;
UCHAR DescOpt;
BOOLEAN AnotherListPending;
} NRPARAMS, *PNRPARAMS;
PIO_RESOURCE_REQUIREMENTS_LIST
IopCmResourcesToIoResources (
IN ULONG SlotNumber,
IN PCM_RESOURCE_LIST CmResourceList
);
NTSTATUS
IopAdjustResourceListRange (
IN PSUPPORTED_RANGES SupportedRanges,
IN PSUPPORTED_RANGE InterruptRange,
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList
);
NTSTATUS
IopGetNextSupportedRange (
IN LONGLONG MinimumAddress,
IN LONGLONG MaximumAddress,
IN OUT PNRPARAMS PNRParams,
OUT PIO_RESOURCE_DESCRIPTOR *IoDescriptor
);
ULONG
IopSortRanges (
IN PSUPPORTED_RANGE RangeList
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,IopAdjustResourceListRange)
#pragma alloc_text(PAGE,IopSortRanges)
#pragma alloc_text(PAGE,IopGetNextSupportedRange)
#pragma alloc_text(PAGE,IopAddDefaultResourceList)
#pragma alloc_text(PAGE,IopCmResourcesToIoResources)
#endif
PIO_RESOURCE_REQUIREMENTS_LIST
IopAddDefaultResourceList (
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
IN PCM_RESOURCE_LIST CmResourceList
)
/*++
Routine Description:
This functions builds an IO resource list by adjusting input IoResourceList to
the ranges specified by CmResourceList and merges the new Io resource list to the
input IoResourceList and returns the combined list.
If IoResourceList has zero descriptor, this routine bulds an
IO RESOURCE REQUIREMENTS LIST by simply converting the CmResourceList.
It's caller's responsiblity to free the returned list.
Arguments:
IoResourceList - The resource requirements list which needs to
be adjusted.
CmResourceList - the cm resource list to specify the resource ranges desired.
Return Value:
returns a IO_RESOURCE_REQUIREMENTS_LISTST if succeeds. Otherwise a NULL value is
returned.
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList, combinedList = NULL;
SUPPORTED_RANGES supportRanges;
SUPPORTED_RANGE interruptRange;
PSUPPORTED_RANGE range, tmpRange;
PSUPPORTED_RANGE intRange = NULL, ioRange = NULL, memRange = NULL, dmaRange = NULL;
ULONG size, i, j, addressSpace = 0;
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
NTSTATUS status;
if (!IoResourceList) {
// If IoResourceList is NULL, return failure.
return NULL;
} else if (IoResourceList->List[0].Count == 0) {
// an empty Io resource requirements list, simply return the converted
// list.
ioResReqList = IopCmResourcesToIoResources(IoResourceList->SlotNumber,
CmResourceList);
return ioResReqList;
}
// Clip the IoResourceList against CmResourceList.
// First, build the supported ranges structure to do the clipping.
RtlZeroMemory(&supportRanges, sizeof(supportRanges));
supportRanges.Version = BUS_SUPPORTED_RANGE_VERSION;
supportRanges.Sorted = FALSE;
ioResReqList = NULL;
cmFullDesc = &CmResourceList->List[0];
for (i = 0; i < CmResourceList->Count; i++) {
cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
size = 0;
range = NULL;
switch (cmPartDesc->Type) {
case CmResourceTypePort:
if (!ioRange) {
range = &supportRanges.IO;
} else {
range = (PSUPPORTED_RANGE)ExAllocatePool(PagedPool, sizeof(SUPPORTED_RANGE));
ioRange->Next = range;
}
range->SystemAddressSpace = 1;
range->SystemBase = 0;
range->Base = cmPartDesc->u.Port.Start.QuadPart;
range->Limit = cmPartDesc->u.Port.Start.QuadPart +
cmPartDesc->u.Port.Length - 1;
range->Next = NULL;
ioRange = range;
supportRanges.NoIO++;
break;
case CmResourceTypeInterrupt:
if (!intRange) {
range = &interruptRange;
} else {
range = (PSUPPORTED_RANGE)ExAllocatePool(PagedPool, sizeof(SUPPORTED_RANGE));
intRange->Next = range;
}
range->SystemAddressSpace = 0;
range->SystemBase = 0;
range->Base = cmPartDesc->u.Interrupt.Vector;
range->Limit = cmPartDesc->u.Interrupt.Vector;
range->Next = NULL;
intRange = range;
break;
case CmResourceTypeMemory:
if (!memRange) {
range = &supportRanges.Memory;
} else {
range = (PSUPPORTED_RANGE)ExAllocatePool(PagedPool, sizeof(SUPPORTED_RANGE));
memRange->Next = range;
}
range->SystemAddressSpace = 0;
range->SystemBase = 0;
range->Base = cmPartDesc->u.Memory.Start.QuadPart;
range->Limit = cmPartDesc->u.Memory.Start.QuadPart +
cmPartDesc->u.Memory.Length - 1;
range->Next = NULL;
memRange = range;
supportRanges.NoMemory++;
break;
case CmResourceTypeDma:
if (!dmaRange) {
range = &supportRanges.Dma;
} else {
range = (PSUPPORTED_RANGE)ExAllocatePool(PagedPool, sizeof(SUPPORTED_RANGE));
dmaRange->Next = range;
}
range->SystemAddressSpace = 0;
range->SystemBase = 0;
range->Base = cmPartDesc->u.Dma.Channel;
range->Limit = cmPartDesc->u.Dma.Channel;
range->Next = NULL;
dmaRange = range;
supportRanges.NoDma++;
break;
case CmResourceTypeDeviceSpecific:
size = cmPartDesc->u.DeviceSpecificData.DataSize;
break;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
// Adjust the input resource requirements list ...
status = IopAdjustResourceListRange (
&supportRanges,
&interruptRange,
IoResourceList,
&ioResReqList
);
if (!NT_SUCCESS(status)) {
goto exit0;
}
// Combine the clipped io resource requirements list with the original resource
// list.
size = ioResReqList->ListSize + IoResourceList->ListSize -
FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
combinedList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
if (combinedList) {
RtlMoveMemory(combinedList, ioResReqList, ioResReqList->ListSize);
combinedList->ListSize = size;
combinedList->AlternativeLists += IoResourceList->AlternativeLists;
RtlMoveMemory((PUCHAR)combinedList + ioResReqList->ListSize,
(PUCHAR)IoResourceList->List,
IoResourceList->ListSize - FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List)
);
}
ExFreePool(ioResReqList);
exit0:
// Release the space allocated for supported ranges...
range = interruptRange.Next;
while (range) {
tmpRange = range;
range = range->Next;
ExFreePool(tmpRange);
}
range = supportRanges.IO.Next;
while (range) {
tmpRange = range;
range = range->Next;
ExFreePool(tmpRange);
}
range = supportRanges.Memory.Next;
while (range) {
tmpRange = range;
range = range->Next;
ExFreePool(tmpRange);
}
range = supportRanges.Dma.Next;
while (range) {
tmpRange = range;
range = range->Next;
ExFreePool(tmpRange);
}
return combinedList;
}
PIO_RESOURCE_REQUIREMENTS_LIST
IopCmResourcesToIoResources (
IN ULONG SlotNumber,
IN PCM_RESOURCE_LIST CmResourceList
)
/*++
Routine Description:
This routines converts the input CmResourceList to IO_RESOURCE_REQUIREMENTS_LIST.
Note, the SlotNumber field of the returned list is not initialized. Caller must
fill in the correct value.
Arguments:
SlotNumber - supplies the SlotNumber the resources refer to.
CmResourceList - the cm resource list to convert.
Return Value:
returns a IO_RESOURCE_REQUIREMENTS_LISTST if succeeds. Otherwise a NULL value is
returned.
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST ioResReqList;
ULONG count = 0, size, i, j;
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
PIO_RESOURCE_DESCRIPTOR ioDesc;
// First determine number of descriptors required.
cmFullDesc = &CmResourceList->List[0];
for (i = 0; i < CmResourceList->Count; i++) {
count += cmFullDesc->PartialResourceList.Count;
cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
size = 0;
switch (cmPartDesc->Type) {
case CmResourceTypeDeviceSpecific:
size = cmPartDesc->u.DeviceSpecificData.DataSize;
break;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
// Allocate heap space for IO RESOURCE REQUIREMENTS LIST
ioResReqList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool(PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + count * sizeof(IO_RESOURCE_DESCRIPTOR));
if (!ioResReqList) {
return NULL;
}
// Parse the cm resource descriptor and build its corresponding IO resource descriptor
ioResReqList->InterfaceType = CmResourceList->List[0].InterfaceType;
ioResReqList->BusNumber = CmResourceList->List[0].BusNumber;
ioResReqList->SlotNumber = SlotNumber;
ioResReqList->Reserved[0] = 0;
ioResReqList->Reserved[1] = 0;
ioResReqList->Reserved[2] = 0;
ioResReqList->AlternativeLists = 1;
ioResReqList->List[0].Version = 1;
ioResReqList->List[0].Revision = 1;
ioResReqList->List[0].Count = count;
ioDesc = &ioResReqList->List[0].Descriptors[0];
cmFullDesc = &CmResourceList->List[0];
for (i = 0; i < CmResourceList->Count; i++) {
cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
ioDesc->Option = IO_RESOURCE_PREFERRED;
ioDesc->Type = cmPartDesc->Type;
ioDesc->ShareDisposition = cmPartDesc->ShareDisposition;
ioDesc->Flags = cmPartDesc->Flags;
ioDesc->Spare1 = 0;
ioDesc->Spare2 = 0;
size = 0;
switch (cmPartDesc->Type) {
case CmResourceTypePort:
ioDesc->u.Port.MinimumAddress = cmPartDesc->u.Port.Start;
ioDesc->u.Port.MaximumAddress.QuadPart = cmPartDesc->u.Port.Start.QuadPart +
cmPartDesc->u.Port.Length - 1;
ioDesc->u.Port.Alignment = 1;
ioDesc->u.Port.Length = cmPartDesc->u.Port.Length;
ioDesc++;
break;
case CmResourceTypeInterrupt:
ioDesc->u.Interrupt.MinimumVector = cmPartDesc->u.Interrupt.Vector;
ioDesc->u.Interrupt.MaximumVector = cmPartDesc->u.Interrupt.Vector;
ioDesc++;
break;
case CmResourceTypeMemory:
ioDesc->u.Memory.MinimumAddress = cmPartDesc->u.Memory.Start;
ioDesc->u.Memory.MaximumAddress.QuadPart = cmPartDesc->u.Memory.Start.QuadPart +
cmPartDesc->u.Memory.Length - 1;
ioDesc->u.Memory.Alignment = 1;
ioDesc->u.Memory.Length = cmPartDesc->u.Memory.Length;
ioDesc++;
break;
case CmResourceTypeDma:
ioDesc->u.Dma.MinimumChannel = cmPartDesc->u.Dma.Channel;
ioDesc->u.Dma.MaximumChannel = cmPartDesc->u.Dma.Channel;
ioDesc++;
break;
case CmResourceTypeDeviceSpecific:
size = cmPartDesc->u.DeviceSpecificData.DataSize;
break;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
ioResReqList->ListSize = (ULONG)ioDesc - (ULONG)ioResReqList;
return ioResReqList;
}
NTSTATUS
IopAdjustResourceListRange (
IN PSUPPORTED_RANGES SupportedRanges,
IN PSUPPORTED_RANGE InterruptRange,
IN PIO_RESOURCE_REQUIREMENTS_LIST IoResourceList,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *ReturnedList
)
/*++
Routine Description:
This functions takes an IO_RESOURCE_REQUIREMENT_LIST and
adjusts it such that all ranges in the list fit in the
ranges specified by SupportedRanges & InterruptRange.
This function is used by some HALs to clip the possible
settings to be contained on what the particular bus supports
in reponse to a HalAdjustResourceList call.
Arguments:
SupportedRanges - Valid IO, Memory, Prefetch Memory, and DMA ranges.
InterruptRange - Valid InterruptRanges
pResourceList - The resource requirements list which needs to
be adjusted to only contain the ranges as
described by SupportedRanges & InterruptRange.
Return Value:
STATUS_SUCCESS or an appropiate error return.
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST InCompleteList, OutCompleteList;
PIO_RESOURCE_LIST InResourceList, OutResourceList;
PIO_RESOURCE_DESCRIPTOR HeadOutDesc, SetDesc;
NRPARAMS Pos;
ULONG len, alt, cnt, i;
ULONG icnt, ListCount;
NTSTATUS status;
// Sanity check
if (!SupportedRanges || SupportedRanges->Version != BUS_SUPPORTED_RANGE_VERSION) {
return STATUS_INVALID_PARAMETER;
}
// If SupportedRanges aren't sorted, sort them and get the
// number of ranges for each type
if (!SupportedRanges->Sorted) {
SupportedRanges->NoIO = IopSortRanges (&SupportedRanges->IO);
SupportedRanges->NoMemory = IopSortRanges (&SupportedRanges->Memory);
SupportedRanges->NoPrefetchMemory = IopSortRanges (&SupportedRanges->PrefetchMemory);
SupportedRanges->NoDma = IopSortRanges (&SupportedRanges->Dma);
SupportedRanges->Sorted = TRUE;
}
icnt = IopSortRanges (InterruptRange);
InCompleteList = IoResourceList;
len = InCompleteList->ListSize;
// Scan input list - verify revision #'s, and increase len varible
// by amount output list may increase.
i = 0;
InResourceList = InCompleteList->List;
for (alt=0; alt < InCompleteList->AlternativeLists; alt++) {
if (InResourceList->Version != 1 || InResourceList->Revision < 1) {
return STATUS_INVALID_PARAMETER;
}
Pos.InDesc = InResourceList->Descriptors;
for (cnt = InResourceList->Count; cnt; cnt--) {
switch (Pos.InDesc->Type) {
case CmResourceTypeInterrupt: i += icnt; break;
case CmResourceTypePort: i += SupportedRanges->NoIO; break;
case CmResourceTypeDma: i += SupportedRanges->NoDma; break;
case CmResourceTypeMemory:
i += SupportedRanges->NoMemory;
if (Pos.InDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) {
i += SupportedRanges->NoPrefetchMemory;
}
break;
default:
return STATUS_INVALID_PARAMETER;
}
i -= 1;// take one off for the original which is already accounted for in 'len'
Pos.InDesc++;// Next descriptor
}
InResourceList = (PIO_RESOURCE_LIST) Pos.InDesc;// Next Resource List
}
len += i * sizeof (IO_RESOURCE_DESCRIPTOR);
// Allocate output list
OutCompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST)ExAllocatePool (PagedPool, len);
if (!OutCompleteList) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory (OutCompleteList, len);
// Walk each ResourceList and build output structure
InResourceList = InCompleteList->List;
*OutCompleteList = *InCompleteList;
OutResourceList = OutCompleteList->List;
ListCount = InCompleteList->AlternativeLists;
for (alt=0; alt < InCompleteList->AlternativeLists; alt++) {
OutResourceList->Version = 1;
OutResourceList->Revision = 1;
Pos.InDesc = InResourceList->Descriptors;
Pos.OutDesc = OutResourceList->Descriptors;
HeadOutDesc = Pos.OutDesc;
for (cnt = InResourceList->Count; cnt; cnt--) {
// Limit desctiptor to be with the buses supported ranges
Pos.DescOpt = Pos.InDesc->Option | IO_RESOURCE_PREFERRED;
Pos.AnotherListPending = FALSE;
switch (Pos.InDesc->Type) {
case CmResourceTypePort:
// Get supported IO ranges
Pos.CurrentPosition = &SupportedRanges->IO;
do {
status = IopGetNextSupportedRange (
Pos.InDesc->u.Port.MinimumAddress.QuadPart,
Pos.InDesc->u.Port.MaximumAddress.QuadPart,
&Pos,
&SetDesc
);
if (NT_SUCCESS(status)) {
if (SetDesc) {
SetDesc->u.Port.MinimumAddress.QuadPart = Pos.Base;
SetDesc->u.Port.MaximumAddress.QuadPart = Pos.Limit;
}
} else {
goto skipCurrentList;
}
} while (SetDesc) ;
break;
case CmResourceTypeInterrupt:
// Get supported Interrupt ranges
Pos.CurrentPosition = InterruptRange;
do {
status = IopGetNextSupportedRange (
Pos.InDesc->u.Interrupt.MinimumVector,
Pos.InDesc->u.Interrupt.MaximumVector,
&Pos,
&SetDesc
);
if (NT_SUCCESS(status)) {
if (SetDesc) {
SetDesc->u.Interrupt.MinimumVector = (ULONG) Pos.Base;
SetDesc->u.Interrupt.MaximumVector = (ULONG) Pos.Limit;
}
} else {
goto skipCurrentList;
}
} while (SetDesc) ;
break;
case CmResourceTypeMemory:
// Get supported memory ranges
if (Pos.InDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) {
// This is a Prefetchable range.
// First add in any supported prefetchable ranges, then
// add in any regualer supported ranges
Pos.AnotherListPending = TRUE;
Pos.CurrentPosition = &SupportedRanges->PrefetchMemory;
do {
status = IopGetNextSupportedRange (
Pos.InDesc->u.Memory.MinimumAddress.QuadPart,
Pos.InDesc->u.Memory.MaximumAddress.QuadPart,
&Pos,
&SetDesc
);
if (NT_SUCCESS(status)) {
if (SetDesc) {
SetDesc->u.Memory.MinimumAddress.QuadPart = Pos.Base;
SetDesc->u.Memory.MaximumAddress.QuadPart = Pos.Limit;
SetDesc->Option |= IO_RESOURCE_PREFERRED;
}
} else {
goto skipCurrentList;
}
} while (SetDesc) ;
Pos.AnotherListPending = FALSE;
}
// Add in supported bus memory ranges
Pos.CurrentPosition = &SupportedRanges->Memory;
do {
status = IopGetNextSupportedRange (
Pos.InDesc->u.Memory.MinimumAddress.QuadPart,
Pos.InDesc->u.Memory.MaximumAddress.QuadPart,
&Pos,
&SetDesc
);
if (NT_SUCCESS(status)) {
if (SetDesc) {
SetDesc->u.Memory.MinimumAddress.QuadPart = Pos.Base;
SetDesc->u.Memory.MaximumAddress.QuadPart = Pos.Limit;
}
} else {
goto skipCurrentList;
}
} while (SetDesc);
break;
case CmResourceTypeDma:
// Get supported DMA ranges
Pos.CurrentPosition = &SupportedRanges->Dma;
do {
status = IopGetNextSupportedRange (
Pos.InDesc->u.Dma.MinimumChannel,
Pos.InDesc->u.Dma.MaximumChannel,
&Pos,
&SetDesc
);
if (NT_SUCCESS(status)) {
if (SetDesc) {
SetDesc->u.Dma.MinimumChannel = (ULONG) Pos.Base;
SetDesc->u.Dma.MaximumChannel = (ULONG) Pos.Limit;
}
} else {
goto skipCurrentList;
}
} while (SetDesc) ;
break;
#if DBG
default:
DbgPrint ("HalAdjustResourceList: Unkown resource type\n");
break;
#endif
}
// Next descriptor
Pos.InDesc++;
}
OutResourceList->Count = Pos.OutDesc - HeadOutDesc;
// Next Resource List
InResourceList = (PIO_RESOURCE_LIST) Pos.InDesc;
OutResourceList = (PIO_RESOURCE_LIST) Pos.OutDesc;
continue;
skipCurrentList:
InResourceList = (PIO_RESOURCE_LIST) (InResourceList->Descriptors + InResourceList->Count);
ListCount--;
}
// Return output list
if (ListCount == 0) {
ExFreePool(OutCompleteList);
return STATUS_UNSUCCESSFUL;
} else {
OutCompleteList->ListSize = (ULONG) ((PUCHAR) OutResourceList - (PUCHAR) OutCompleteList);
OutCompleteList->AlternativeLists = ListCount;
*ReturnedList = OutCompleteList;
return STATUS_SUCCESS;
}
}
NTSTATUS
IopGetNextSupportedRange (
IN LONGLONG MinimumAddress,
IN LONGLONG MaximumAddress,
IN OUT PNRPARAMS Pos,
OUT PIO_RESOURCE_DESCRIPTOR *IoDescriptor
)
/*++
Routine Description:
Support function for IopAdjustResourceListRange.
Returns the next supported range in the area passed in.
Arguments:
MinimumAddress
MaximumAddress - Min & Max address of a range which needs
to be clipped to match that of the supported
ranges of the current bus.
Pos - describes the current postion
IoDescriptor - returns the adjusted resource descriptor
NULL is no more returned ranges
Return Value:
Otherwise, the IO_RESOURCE_DESCRIPTOR which needs to be set
with the matching range returned in Pos.
--*/
{
LONGLONG Base, Limit;
// Find next range which is supported
Base = MinimumAddress;
Limit = MaximumAddress;
while (Pos->CurrentPosition) {
Pos->Base = Base;
Pos->Limit = Limit;
// Clip to current range
if (Pos->Base < Pos->CurrentPosition->Base) {
Pos->Base = Pos->CurrentPosition->Base;
}
if (Pos->Limit > Pos->CurrentPosition->Limit) {
Pos->Limit = Pos->CurrentPosition->Limit;
}
// set position to next range
Pos->CurrentPosition = Pos->CurrentPosition->Next;
// If valid range, return it
if (Pos->Base <= Pos->Limit) {
*Pos->OutDesc = *Pos->InDesc;
Pos->OutDesc->Option = Pos->DescOpt;
// next descriptor (if any) is an alternative
// to the descriptor being returned now
Pos->OutDesc += 1;
Pos->DescOpt |= IO_RESOURCE_ALTERNATIVE;
*IoDescriptor = Pos->OutDesc - 1;
return STATUS_SUCCESS;
}
}
// There's no overlapping range. If this descriptor is
// not an alternative and this descriptor is not going to
// be processed by another range list, then return
// failure.
if (!(Pos->DescOpt & IO_RESOURCE_ALTERNATIVE) &&
Pos->AnotherListPending == FALSE) {
// return a bogus descriptor
Pos->Base = MinimumAddress;
Pos->Limit = Pos->Base - 1;
if (Pos->Base == 0) { // if wrapped, fix it
Pos->Base = 1;
Pos->Limit = 0;
}
*Pos->OutDesc = *Pos->InDesc;
Pos->OutDesc->Option = Pos->DescOpt;
Pos->OutDesc += 1;
Pos->DescOpt |= IO_RESOURCE_ALTERNATIVE;
*IoDescriptor = Pos->OutDesc - 1;
return STATUS_SUCCESS;
}
// No range found (or no more ranges)
*IoDescriptor = NULL;
return STATUS_SUCCESS;
}
ULONG
IopSortRanges (
IN PSUPPORTED_RANGE RangeList
)
/*++
Routine Description:
Support function for IopAdjustResourceListRange.
Sorts a supported range list into decending order.
Arguments:
pRange - List to sort
Return Value:
--*/
{
ULONG cnt;
LONGLONG hldBase, hldLimit;
PSUPPORTED_RANGE Range1, Range2;
// Sort it
for (Range1 = RangeList; Range1; Range1 = Range1->Next) {
for (Range2 = Range1->Next; Range2; Range2 = Range2->Next) {
if (Range2->Base > Range1->Base) {
hldBase = Range1->Base;
hldLimit = Range1->Limit;
Range1->Base = Range2->Base;
Range1->Limit = Range2->Limit;
Range2->Base = hldBase;
Range2->Limit = hldLimit;
}
}
}
// Count the number of ranges
cnt = 0;
for (Range1 = RangeList; Range1; Range1 = Range1->Next) {
cnt += 1;
}
return cnt;
}
#endif // _PNP_POWER_