windows-nt/Source/XPSP1/NT/base/busdrv/isapnp/resource.c

1986 lines
63 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995-2000 Microsoft Corporation
Module Name:
devres.c
Abstract:
This module contains the high level device resources support routines.
Author:
Shie-Lin Tzong (shielint) July-27-1995
Environment:
Kernel mode only.
Revision History:
--*/
#include "busp.h"
#include "pnpisa.h"
#include "pbios.h"
#include "pnpcvrt.h"
#if ISOLATE_CARDS
#define IDBG 0
#if 0
NTSTATUS
PipFilterResourceRequirementsList(
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
);
#endif
PIO_RESOURCE_REQUIREMENTS_LIST
PipCmResourcesToIoResources (
IN PCM_RESOURCE_LIST CmResourceList
);
NTSTATUS
PipMergeResourceRequirementsLists (
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1,
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList
);
NTSTATUS
PipBuildBootResourceRequirementsList (
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
IN PCM_RESOURCE_LIST CmList,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList,
OUT PBOOLEAN ExactMatch
);
VOID
PipMergeBootResourcesToRequirementsList(
PDEVICE_INFORMATION DeviceInfo,
PCM_RESOURCE_LIST BootResources,
PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
);
#pragma alloc_text(PAGE, PipGetCardIdentifier)
#pragma alloc_text(PAGE, PipGetFunctionIdentifier)
#pragma alloc_text(PAGE, PipGetCompatibleDeviceId)
#pragma alloc_text(PAGE, PipQueryDeviceId)
#pragma alloc_text(PAGE, PipQueryDeviceUniqueId)
//#pragma alloc_text(PAGE, PipQueryDeviceResources)
#pragma alloc_text(PAGE, PipQueryDeviceResourceRequirements)
//#pragma alloc_text(PAGE, PipFilterResourceRequirementsList)
#pragma alloc_text(PAGE, PipCmResourcesToIoResources)
#pragma alloc_text(PAGE, PipMergeResourceRequirementsLists)
#pragma alloc_text(PAGE, PipBuildBootResourceRequirementsList)
#pragma alloc_text(PAGE, PipMergeBootResourcesToRequirementsList)
//#pragma alloc_text(PAGE, PipSetDeviceResources)
NTSTATUS
PipGetCardIdentifier (
PUCHAR CardData,
PWCHAR *Buffer,
PULONG BufferLength
)
/*++
Routine Description:
This function returns the identifier for a pnpisa card.
Arguments:
CardData - supplies a pointer to the pnp isa device data.
Buffer - supplies a pointer to variable to receive a pointer to the Id.
BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR tag;
LONG size, length;
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
PCHAR ansiBuffer;
*Buffer = NULL;
*BufferLength = 0;
if (CardData == NULL) {
return status;
}
tag = *CardData;
//
// Make sure CardData does *NOT* point to a Logical Device Id tag
//
if ((tag & SMALL_TAG_MASK) == TAG_LOGICAL_ID) {
DbgPrint("PipGetCardIdentifier: CardData is at a Logical Id tag\n");
return status;
}
//
// Find the resource descriptor which describle identifier string
//
do {
//
// Do we find the identifer resource tag?
//
if (tag == TAG_ANSI_ID) {
CardData++;
length = *(USHORT UNALIGNED *)CardData;
CardData += 2;
ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
if (ansiBuffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlMoveMemory(ansiBuffer, CardData, length);
ansiBuffer[length] = 0;
RtlInitAnsiString(&ansiString, ansiBuffer);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
ExFreePool(ansiBuffer);
if (!NT_SUCCESS(status)) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
*Buffer = unicodeString.Buffer;
*BufferLength = unicodeString.Length + sizeof(WCHAR);
break;
}
//
// Determine the size of the BIOS resource descriptor and
// advance to next resource descriptor.
//
if (!(tag & LARGE_RESOURCE_TAG)) {
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
size += 1; // length of small tag
} else {
size = *(USHORT UNALIGNED *)(CardData + 1);
size += 3; // length of large tag
}
CardData += size;
tag = *CardData;
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
return status;
}
NTSTATUS
PipGetFunctionIdentifier (
PUCHAR DeviceData,
PWCHAR *Buffer,
PULONG BufferLength
)
/*++
Routine Description:
This function returns the desired pnp isa identifier for the specified
DeviceData/LogicalFunction. The Identifier for a logical function is
optional. If no Identifier available , Buffer is set to NULL.
Arguments:
DeviceData - supplies a pointer to the pnp isa device data.
Buffer - supplies a pointer to variable to receive a pointer to the Id.
BufferLength - supplies a pointer to a variable to receive the size of the id buffer.
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UCHAR tag;
LONG size, length;
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
PCHAR ansiBuffer;
*Buffer = NULL;
*BufferLength = 0;
if (DeviceData==NULL) {
return status;
}
tag = *DeviceData;
#if DBG
//
// Make sure device data points to Logical Device Id tag
//
if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
DbgPrint("PipGetFunctionIdentifier: DeviceData is not at a Logical Id tag\n");
}
#endif
//
// Skip all the resource descriptors to find compatible Id descriptor
//
do {
//
// Determine the size of the BIOS resource descriptor and
// advance to next resource descriptor.
//
if (!(tag & LARGE_RESOURCE_TAG)) {
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
size += 1; // length of small tag
} else {
size = *(USHORT UNALIGNED *)(DeviceData + 1);
size += 3; // length of large tag
}
DeviceData += size;
tag = *DeviceData;
//
// Do we find the identifer resource tag?
//
if (tag == TAG_ANSI_ID) {
DeviceData++;
length = *(USHORT UNALIGNED *)DeviceData;
DeviceData += 2;
ansiBuffer = (PCHAR)ExAllocatePool(PagedPool, length+1);
if (ansiBuffer == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlMoveMemory(ansiBuffer, DeviceData, length);
ansiBuffer[length] = 0;
RtlInitAnsiString(&ansiString, ansiBuffer);
status = RtlAnsiStringToUnicodeString(&unicodeString,
&ansiString,
TRUE);
ExFreePool(ansiBuffer);
if (!NT_SUCCESS(status)) {
status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
*Buffer = unicodeString.Buffer;
*BufferLength = unicodeString.Length + sizeof(WCHAR);
break;
}
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
return status;
}
NTSTATUS
PipGetCompatibleDeviceId (
PUCHAR DeviceData,
ULONG IdIndex,
PWCHAR *Buffer
)
/*++
Routine Description:
This function returns the desired pnp isa id for the specified DeviceData
and Id index. If Id index = 0, the Hardware ID will be return; if id
index = n, the Nth compatible id will be returned.
Arguments:
DeviceData - supplies a pointer to the pnp isa device data.
IdIndex - supplies the index of the compatible id desired.
Buffer - supplies a pointer to variable to receive a pointer to the compatible Id.
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status = STATUS_NO_MORE_ENTRIES;
UCHAR tag;
ULONG count = 0,length;
LONG size;
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
UCHAR eisaId[8];
ULONG id;
//
// Bail out BEFORE we touch the device data for the RDP
//
if (IdIndex == -1) {
length = 2* sizeof(WCHAR);
*Buffer = (PWCHAR) ExAllocatePool(PagedPool, length);
if (*Buffer) {
RtlZeroMemory (*Buffer,length);
}else {
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
}
tag = *DeviceData;
#if DBG
//
// Make sure device data points to Logical Device Id tag
//
if ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID) {
DbgPrint("PipGetCompatibleDeviceId: DeviceData is not at Logical Id tag\n");
}
#endif
if (IdIndex == 0) {
//
// Caller is asking for hardware id
//
DeviceData++; // Skip tag
id = *(ULONG UNALIGNED *)DeviceData;
status = STATUS_SUCCESS;
} else {
//
// caller is asking for compatible id
//
IdIndex--;
//
// Skip all the resource descriptors to find compatible Id descriptor
//
do {
//
// Determine the size of the BIOS resource descriptor and
// advance to next resource descriptor.
//
if (!(tag & LARGE_RESOURCE_TAG)) {
size = (USHORT)(tag & SMALL_TAG_SIZE_MASK);
size += 1; // length of small tag
} else {
size = *(USHORT UNALIGNED *)(DeviceData + 1);
size += 3; // length of large tag
}
DeviceData += size;
tag = *DeviceData;
//
// Do we reach the compatible ID descriptor?
//
if ((tag & SMALL_TAG_MASK) == TAG_COMPATIBLE_ID) {
if (count == IdIndex) {
id = *(ULONG UNALIGNED *)(DeviceData + 1);
status = STATUS_SUCCESS;
break;
} else {
count++;
}
}
} while ((tag != TAG_COMPLETE_END) && ((tag & SMALL_TAG_MASK) != TAG_LOGICAL_ID));
}
if (NT_SUCCESS(status)) {
PipDecompressEisaId(id, eisaId);
RtlInitAnsiString(&ansiString, eisaId);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (!NT_SUCCESS(status)) {
return status;
}
*Buffer = (PWCHAR)ExAllocatePool (
PagedPool,
sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length
);
if (*Buffer) {
swprintf(*Buffer, L"*%s", unicodeString.Buffer);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
RtlFreeUnicodeString(&unicodeString);
}
return status;
}
NTSTATUS
PipQueryDeviceUniqueId (
PDEVICE_INFORMATION DeviceInfo,
PWCHAR *DeviceId
)
/*++
Routine Description:
This function returns the unique id for the particular device.
Arguments:
DeviceData - Device data information for the specificied device.
DeviceId - supplies a pointer to a variable to receive device id.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
//
// Set up device's unique id.
// device unique id = SerialNumber of the card
//
*DeviceId = (PWCHAR)ExAllocatePool (
PagedPool,
(8 + 1) * sizeof(WCHAR) // serial number + null
);
if (*DeviceId) {
if (DeviceInfo->Flags & DF_READ_DATA_PORT) {
//
// Override the unique ID for the RDP
//
swprintf (*DeviceId,
L"0"
);
} else {
swprintf (*DeviceId,
L"%01X",
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber
);
}
#if IDBG
{
ANSI_STRING ansiString;
UNICODE_STRING unicodeString;
RtlInitUnicodeString(&unicodeString, *DeviceId);
RtlUnicodeStringToAnsiString(&ansiString, &unicodeString, TRUE);
DbgPrint("PnpIsa: return Unique Id = %s\n", ansiString.Buffer);
RtlFreeAnsiString(&ansiString);
}
#endif
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return status;
}
NTSTATUS
PipQueryDeviceId (
PDEVICE_INFORMATION DeviceInfo,
PWCHAR *DeviceId,
ULONG IdIndex
)
/*++
Routine Description:
This function returns the device id for the particular device.
Arguments:
DeviceInfo - Device information for the specificied device.
DeviceId - supplies a pointer to a variable to receive the device id.
IdIndex - specifies device id or compatible id (0 - device id)
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PWSTR format;
ULONG size,length;
UCHAR eisaId[8];
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
//
// Bail out BEFORE we touch the device data for the RDP
//
if (DeviceInfo->Flags & DF_READ_DATA_PORT) {
length = (sizeof (wReadDataPort)+
+ sizeof(WCHAR) +sizeof (L"ISAPNP\\"));
*DeviceId = (PWCHAR) ExAllocatePool(PagedPool, length);
if (*DeviceId) {
_snwprintf(*DeviceId, length, L"ISAPNP\\%s",wReadDataPort);
} else {
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
}
//
// Set up device's id.
// device id = VenderId + Logical device number
//
if (DeviceInfo->CardInformation->NumberLogicalDevices == 1) {
format = L"ISAPNP\\%s";
size = sizeof(L"ISAPNP\\*") + sizeof(WCHAR);
} else {
format = L"ISAPNP\\%s_DEV%04X";
size = sizeof(L"ISAPNP\\_DEV") + 4 * sizeof(WCHAR) + sizeof(WCHAR);
}
PipDecompressEisaId(
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->VenderId,
eisaId
);
RtlInitAnsiString(&ansiString, eisaId);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (!NT_SUCCESS(status)) {
return STATUS_INSUFFICIENT_RESOURCES;
}
size += unicodeString.Length;
*DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size);
if (*DeviceId) {
swprintf (*DeviceId,
format,
unicodeString.Buffer,
DeviceInfo->LogicalDeviceNumber
);
#if IDBG
{
ANSI_STRING dbgAnsiString;
UNICODE_STRING dbgUnicodeString;
RtlInitUnicodeString(&dbgUnicodeString, *DeviceId);
RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE);
DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer);
RtlFreeAnsiString(&dbgAnsiString);
}
#endif
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
RtlFreeUnicodeString(&unicodeString);
return status;
}
NTSTATUS
PipQueryDeviceResources (
PDEVICE_INFORMATION DeviceInfo,
ULONG BusNumber,
PCM_RESOURCE_LIST *CmResources,
ULONG *Size
)
/*++
Routine Description:
This function returns the bus resources being used by the specified device
Arguments:
DeviceInfo - Device information for the specificied slot
BusNumber - should always be 0
CmResources - supplies a pointer to a variable to receive the device resource
data.
Size - Supplies a pointer to avariable to receive the size of device resource
data.
Return Value:
NTSTATUS code.
--*/
{
ULONG length;
NTSTATUS status = STATUS_SUCCESS;
PCM_RESOURCE_LIST cmResources;
*CmResources = NULL;
*Size = 0;
if (DeviceInfo->BootResources){ // && DeviceInfo->LogConfHandle) {
*CmResources = ExAllocatePool(PagedPool, DeviceInfo->BootResourcesLength);
if (*CmResources) {
RtlMoveMemory(*CmResources, DeviceInfo->BootResources, DeviceInfo->BootResourcesLength);
*Size = DeviceInfo->BootResourcesLength;
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
return status;
}
NTSTATUS
PipQueryDeviceResourceRequirements (
PDEVICE_INFORMATION DeviceInfo,
ULONG BusNumber,
ULONG Slot,
PCM_RESOURCE_LIST BootResources,
USHORT IrqFlags,
PIO_RESOURCE_REQUIREMENTS_LIST *IoResources,
ULONG *Size
)
/*++
Routine Description:
This function returns the possible bus resources that this device may be
satisfied with.
Arguments:
DeviceData - Device data information for the specificied slot
BusNumber - Supplies the bus number
Slot - supplies the slot number of the BusNumber
IoResources - supplies a pointer to a variable to receive the IO resource
requirements list
Return Value:
The device control is completed
--*/
{
ULONG length = 0;
NTSTATUS status;
PUCHAR deviceData;
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
deviceData = DeviceInfo->DeviceData;
status = PpBiosResourcesToNtResources (
BusNumber,
Slot,
&deviceData,
0,
&ioResources,
&length
);
//
// Return results
//
if (NT_SUCCESS(status)) {
if (length == 0) {
ioResources = NULL; // Just to make sure
} else {
// * Set the irq level/edge requirements to be consistent
// with the our determination earlier as to what is
// likely to work for this card
//
// * Make requirements reflect boot configed ROM if any.
//
// Make these changes across all alternatives.
PipTrimResourceRequirements(&ioResources,
IrqFlags,
BootResources);
//PipFilterResourceRequirementsList(&ioResources);
PipMergeBootResourcesToRequirementsList(DeviceInfo,
BootResources,
&ioResources
);
ASSERT(ioResources);
length = ioResources->ListSize;
}
*IoResources = ioResources;
*Size = length;
#if IDBG
PipDumpIoResourceList(ioResources);
#endif
}
return status;
}
NTSTATUS
PipSetDeviceResources (
PDEVICE_INFORMATION DeviceInfo,
PCM_RESOURCE_LIST CmResources
)
/*++
Routine Description:
This function configures the device to the specified device setttings
Arguments:
DeviceInfo - Device information for the specificied slot
CmResources - pointer to the desired resource list
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
if (CmResources && (CmResources->Count != 0)) {
//
// Set resource settings for the device
//
status = PipWriteDeviceResources (
DeviceInfo->DeviceData,
(PCM_RESOURCE_LIST) CmResources
);
//
// Put all cards into wait for key state.
//
DebugPrint((DEBUG_STATE,
"SetDeviceResources CSN %d/LDN %d\n",
DeviceInfo->CardInformation->CardSelectNumber,
DeviceInfo->LogicalDeviceNumber));
//
// Delay some time for the newly set resources to be avaiable.
// This is required on some slow machines.
//
KeStallExecutionProcessor(10000); // delay 10 ms
}
return status;
}
#if 0
NTSTATUS
PipFilterResourceRequirementsList(
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
)
/*++
Routine Description:
This routine removes the length zero entries from the input Io resource
requirements list.
Parameters:
IoResources - supplies a pointer to an address to Io resource requirements List.
Return Value:
NTSTATUS code.
--*/
{
NTSTATUS status;
PIO_RESOURCE_REQUIREMENTS_LIST oldIoResources = *IoResources, newIoResources;
PIO_RESOURCE_LIST oldIoResourceList = oldIoResources->List;
PIO_RESOURCE_LIST newIoResourceList;
PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptor, newIoResourceDescriptor;
PIO_RESOURCE_DESCRIPTOR oldIoResourceDescriptorEnd;
#if DBG
PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptorEnd;
#endif
LONG IoResourceListCount = (LONG) oldIoResources->AlternativeLists;
ULONG size;
PAGED_CODE();
//
// Make sure there is some resource requirements to be fulfilled.
//
if (IoResourceListCount == 0) {
return STATUS_SUCCESS;
}
size = oldIoResources->ListSize;
//
// Check if there is any length zero descriptor
//
while (--IoResourceListCount >= 0) {
oldIoResourceDescriptor = oldIoResourceList->Descriptors;
oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count;
while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) {
switch (oldIoResourceDescriptor->Type) {
case CmResourceTypePort:
case CmResourceTypeMemory:
if (oldIoResourceDescriptor->u.Generic.Length == 0) {
size -= sizeof(IO_RESOURCE_DESCRIPTOR);
}
break;
default:
break;
}
oldIoResourceDescriptor++;
}
ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd);
oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptorEnd;
}
if (size == oldIoResources->ListSize) {
return STATUS_SUCCESS;
}
//
// We have length zero descriptor. Rebuild the resources requirements list
//
newIoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (
PagedPool, size);
if (newIoResources == NULL) {
return STATUS_NO_MEMORY;
} else {
RtlMoveMemory(newIoResources,
oldIoResources,
FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List)
);
newIoResources->ListSize = size;
newIoResourceList = newIoResources->List;
#if DBG
newIoResourceDescriptorEnd = (PIO_RESOURCE_DESCRIPTOR)
((PUCHAR)newIoResourceList + size);
#endif
}
//
// filter the IO ResReq list
//
oldIoResourceList = oldIoResources->List;
IoResourceListCount = (LONG) oldIoResources->AlternativeLists;
while (--IoResourceListCount >= 0) {
newIoResourceList->Version = oldIoResourceList->Version;
newIoResourceList->Revision = oldIoResourceList->Revision;
newIoResourceList->Count = oldIoResourceList->Count;
oldIoResourceDescriptor = oldIoResourceList->Descriptors;
newIoResourceDescriptor = newIoResourceList->Descriptors;
oldIoResourceDescriptorEnd = oldIoResourceDescriptor + oldIoResourceList->Count;
while (oldIoResourceDescriptor < oldIoResourceDescriptorEnd) {
switch (oldIoResourceDescriptor->Type) {
case CmResourceTypePort:
case CmResourceTypeMemory:
if (oldIoResourceDescriptor->u.Generic.Length == 0) {
newIoResourceList->Count--;
break;
}
default:
*newIoResourceDescriptor = *oldIoResourceDescriptor;
newIoResourceDescriptor++;
break;
}
oldIoResourceDescriptor++;
}
ASSERT(oldIoResourceDescriptor == oldIoResourceDescriptorEnd);
oldIoResourceList = (PIO_RESOURCE_LIST) oldIoResourceDescriptor;
newIoResourceList = (PIO_RESOURCE_LIST) newIoResourceDescriptor;
}
ASSERT(newIoResourceDescriptor <= newIoResourceDescriptorEnd);
ExFreePool(oldIoResources);
*IoResources = newIoResources;
return STATUS_SUCCESS;
}
#endif
PIO_RESOURCE_REQUIREMENTS_LIST
PipCmResourcesToIoResources (
IN PCM_RESOURCE_LIST CmResourceList
)
/*++
Routine Description:
This routines converts the input CmResourceList to IO_RESOURCE_REQUIREMENTS_LIST.
Arguments:
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;
count--;
break;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
if (count == 0) {
return NULL;
}
//
// Count the extra descriptors for InterfaceType and BusNumber information.
//
count += CmResourceList->Count - 1;
//
// Allocate heap space for IO RESOURCE REQUIREMENTS LIST
//
count++; // add one for CmResourceTypeConfigData
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 = 0;
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;
//
// Generate a CmResourceTypeConfigData descriptor
//
ioDesc = &ioResReqList->List[0].Descriptors[0];
ioDesc->Option = IO_RESOURCE_PREFERRED;
ioDesc->Type = CmResourceTypeConfigData;
ioDesc->ShareDisposition = CmResourceShareShared;
ioDesc->Flags = 0;
ioDesc->Spare1 = 0;
ioDesc->Spare2 = 0;
ioDesc->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
ioDesc++;
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:
#if defined(_X86_)
ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
cmPartDesc->u.Interrupt.Level;
#else
ioDesc->u.Interrupt.MinimumVector = ioDesc->u.Interrupt.MaximumVector =
cmPartDesc->u.Interrupt.Vector;
#endif
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;
case CmResourceTypeBusNumber:
ioDesc->u.BusNumber.MinBusNumber = cmPartDesc->u.BusNumber.Start;
ioDesc->u.BusNumber.MaxBusNumber = cmPartDesc->u.BusNumber.Start +
cmPartDesc->u.BusNumber.Length - 1;
ioDesc->u.BusNumber.Length = cmPartDesc->u.BusNumber.Length;
ioDesc++;
break;
default:
ioDesc->u.DevicePrivate.Data[0] = cmPartDesc->u.DevicePrivate.Data[0];
ioDesc->u.DevicePrivate.Data[1] = cmPartDesc->u.DevicePrivate.Data[1];
ioDesc->u.DevicePrivate.Data[2] = cmPartDesc->u.DevicePrivate.Data[2];
ioDesc++;
break;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
ioResReqList->ListSize = (ULONG)((ULONG_PTR)ioDesc - (ULONG_PTR)ioResReqList);
return ioResReqList;
}
NTSTATUS
PipMergeResourceRequirementsLists (
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList1,
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList2,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *MergedList
)
/*++
Routine Description:
This routines merges two IoLists into one.
Arguments:
IoList1 - supplies the pointer to the first IoResourceRequirementsList
IoList2 - supplies the pointer to the second IoResourceRequirementsList
MergedList - Supplies a variable to receive the merged resource
requirements list.
Return Value:
A NTSTATUS code to indicate the result of the function.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
ULONG size;
PUCHAR p;
PAGED_CODE();
*MergedList = NULL;
//
// First handle the easy cases that both IO Lists are empty or any one of
// them is empty.
//
if ((IoList1 == NULL || IoList1->AlternativeLists == 0) &&
(IoList2 == NULL || IoList2->AlternativeLists == 0)) {
return status;
}
ioList = NULL;
if (IoList1 == NULL || IoList1->AlternativeLists == 0) {
ioList = IoList2;
} else if (IoList2 == NULL || IoList2->AlternativeLists == 0) {
ioList = IoList1;
}
if (ioList) {
newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, ioList->ListSize);
if (newList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlMoveMemory(newList, ioList, ioList->ListSize);
*MergedList = newList;
return status;
}
//
// Do real work...
//
size = IoList1->ListSize + IoList2->ListSize - FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List);
newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(
PagedPool,
size
);
if (newList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
p = (PUCHAR)newList;
RtlMoveMemory(p, IoList1, IoList1->ListSize);
p += IoList1->ListSize;
RtlMoveMemory(p,
&IoList2->List[0],
size - IoList1->ListSize
);
newList->ListSize = size;
newList->AlternativeLists += IoList2->AlternativeLists;
*MergedList = newList;
return status;
}
VOID
PipMergeBootResourcesToRequirementsList(
PDEVICE_INFORMATION DeviceInfo,
PCM_RESOURCE_LIST BootResources,
PIO_RESOURCE_REQUIREMENTS_LIST *IoResources
)
/*++
Routine Description:
This routines merges two IoLists into one.
Arguments:
IoList1 - supplies the pointer to the first IoResourceRequirementsList
IoList2 - supplies the pointer to the second IoResourceRequirementsList
MergedList - Supplies a variable to receive the merged resource
requirements list.
Return Value:
A NTSTATUS code to indicate the result of the function.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_REQUIREMENTS_LIST ioResources = *IoResources, bootResReq = NULL, newList = NULL;
BOOLEAN exactMatch;
PAGED_CODE();
if (DeviceInfo->BootResources) {
PipBuildBootResourceRequirementsList (ioResources, BootResources, &bootResReq, &exactMatch);
if (bootResReq) {
if (exactMatch && ioResources->AlternativeLists == 1) {
ExFreePool(ioResources);
*IoResources = bootResReq;
} else {
PipMergeResourceRequirementsLists (bootResReq, ioResources, &newList);
if (newList) {
ExFreePool(ioResources);
*IoResources = newList;
}
ExFreePool(bootResReq);
}
}
}
}
NTSTATUS
PipBuildBootResourceRequirementsList (
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
IN PCM_RESOURCE_LIST CmList,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *FilteredList,
OUT PBOOLEAN ExactMatch
)
/*++
Routine Description:
This routines adjusts the input IoList based on input BootConfig.
Arguments:
IoList - supplies the pointer to an IoResourceRequirementsList
CmList - supplies the pointer to a BootConfig.
FilteredList - Supplies a variable to receive the filtered resource
requirements list.
Return Value:
A NTSTATUS code to indicate the result of the function.
--*/
{
NTSTATUS status;
PIO_RESOURCE_REQUIREMENTS_LIST ioList, newList;
PIO_RESOURCE_LIST ioResourceList, newIoResourceList;
PIO_RESOURCE_DESCRIPTOR ioResourceDescriptor, ioResourceDescriptorEnd;
PIO_RESOURCE_DESCRIPTOR newIoResourceDescriptor, configDataDescriptor;
LONG ioResourceDescriptorCount = 0;
USHORT version;
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescriptor;
ULONG cmDescriptorCount = 0;
ULONG size, i, j, oldCount, phase;
LONG k, alternativeLists;
BOOLEAN exactMatch;
PAGED_CODE();
*FilteredList = NULL;
*ExactMatch = FALSE;
//
// Make sure there is some resource requirements to be filtered.
// If no, we will convert CmList/BootConfig to an IoResourceRequirementsList
//
if (IoList == NULL || IoList->AlternativeLists == 0) {
if (CmList && CmList->Count != 0) {
*FilteredList = PipCmResourcesToIoResources (CmList);
}
return STATUS_SUCCESS;
}
//
// Make a copy of the Io Resource Requirements List
//
ioList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, IoList->ListSize);
if (ioList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlMoveMemory(ioList, IoList, IoList->ListSize);
//
// If there is no BootConfig, simply return the copy of the input Io list.
//
if (CmList == NULL || CmList->Count == 0) {
*FilteredList = ioList;
return STATUS_SUCCESS;
}
//
// First determine minimum number of descriptors required.
//
cmFullDesc = &CmList->List[0];
for (i = 0; i < CmList->Count; i++) {
cmDescriptorCount += cmFullDesc->PartialResourceList.Count;
cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
size = 0;
switch (cmDescriptor->Type) {
case CmResourceTypeConfigData:
case CmResourceTypeDevicePrivate:
cmDescriptorCount--;
break;
case CmResourceTypeDeviceSpecific:
size = cmDescriptor->u.DeviceSpecificData.DataSize;
cmDescriptorCount--;
break;
default:
//
// Invalid cmresource list. Ignore it and use io resources
//
if (cmDescriptor->Type == CmResourceTypeNull ||
cmDescriptor->Type >= CmResourceTypeMaximum) {
cmDescriptorCount--;
}
}
cmDescriptor++;
cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
}
if (cmDescriptorCount == 0) {
*FilteredList = ioList;
return STATUS_SUCCESS;
}
//
// cmDescriptorCount is the number of BootConfig Descriptors needs.
//
// For each IO list Alternative ...
//
ioResourceList = ioList->List;
k = ioList->AlternativeLists;
while (--k >= 0) {
ioResourceDescriptor = ioResourceList->Descriptors;
ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
ioResourceDescriptor->Spare1 = 0;
ioResourceDescriptor++;
}
ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
}
ioResourceList = ioList->List;
k = alternativeLists = ioList->AlternativeLists;
while (--k >= 0) {
version = ioResourceList->Version;
if (version == 0xffff) { // Convert bogus version to valid number
version = 1;
}
//
// We use Version field to store number of BootConfig found.
// Count field to store new number of descriptor in the alternative list.
//
ioResourceList->Version = 0;
oldCount = ioResourceList->Count;
ioResourceDescriptor = ioResourceList->Descriptors;
ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
if (ioResourceDescriptor == ioResourceDescriptorEnd) {
//
// An alternative list with zero descriptor count
//
ioResourceList->Version = 0xffff; // Mark it as invalid
ioList->AlternativeLists--;
continue;
}
exactMatch = TRUE;
//
// For each Cm Resource descriptor ... except DevicePrivate and
// DeviceSpecific...
//
cmFullDesc = &CmList->List[0];
for (i = 0; i < CmList->Count; i++) {
cmDescriptor = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
size = 0;
switch (cmDescriptor->Type) {
case CmResourceTypeDevicePrivate:
break;
case CmResourceTypeDeviceSpecific:
size = cmDescriptor->u.DeviceSpecificData.DataSize;
break;
default:
if (cmDescriptor->Type == CmResourceTypeNull ||
cmDescriptor->Type >= CmResourceTypeMaximum) {
break;
}
//
// Check CmDescriptor against current Io Alternative list
//
for (phase = 0; phase < 2; phase++) {
ioResourceDescriptor = ioResourceList->Descriptors;
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
if ((ioResourceDescriptor->Type == cmDescriptor->Type) &&
(ioResourceDescriptor->Spare1 == 0)) {
ULONGLONG min1, max1, min2, max2;
ULONG len1 = 1, len2 = 1, align1, align2;
UCHAR share1, share2;
share2 = ioResourceDescriptor->ShareDisposition;
share1 = cmDescriptor->ShareDisposition;
if ((share1 == CmResourceShareUndetermined) ||
(share1 > CmResourceShareShared)) {
share1 = share2;
}
if ((share2 == CmResourceShareUndetermined) ||
(share2 > CmResourceShareShared)) {
share2 = share1;
}
align1 = align2 = 1;
switch (cmDescriptor->Type) {
case CmResourceTypePort:
case CmResourceTypeMemory:
min1 = cmDescriptor->u.Port.Start.QuadPart;
max1 = cmDescriptor->u.Port.Start.QuadPart + cmDescriptor->u.Port.Length - 1;
len1 = cmDescriptor->u.Port.Length;
min2 = ioResourceDescriptor->u.Port.MinimumAddress.QuadPart;
max2 = ioResourceDescriptor->u.Port.MaximumAddress.QuadPart;
len2 = ioResourceDescriptor->u.Port.Length;
align2 = ioResourceDescriptor->u.Port.Alignment;
break;
case CmResourceTypeInterrupt:
max1 = min1 = cmDescriptor->u.Interrupt.Vector;
min2 = ioResourceDescriptor->u.Interrupt.MinimumVector;
max2 = ioResourceDescriptor->u.Interrupt.MaximumVector;
break;
case CmResourceTypeDma:
min1 = max1 =cmDescriptor->u.Dma.Channel;
min2 = ioResourceDescriptor->u.Dma.MinimumChannel;
max2 = ioResourceDescriptor->u.Dma.MaximumChannel;
break;
case CmResourceTypeBusNumber:
min1 = cmDescriptor->u.BusNumber.Start;
max1 = cmDescriptor->u.BusNumber.Start + cmDescriptor->u.BusNumber.Length - 1;
len1 = cmDescriptor->u.BusNumber.Length;
min2 = ioResourceDescriptor->u.BusNumber.MinBusNumber;
max2 = ioResourceDescriptor->u.BusNumber.MaxBusNumber;
len2 = ioResourceDescriptor->u.BusNumber.Length;
break;
default:
ASSERT(0);
break;
}
if (phase == 0) {
if (share1 == share2 && min2 == min1 && max2 >= max1 && len2 >= len1) {
//
// For phase 0 match, we want near exact match...
//
if (max2 != max1) {
exactMatch = FALSE;
}
ioResourceList->Version++;
ioResourceDescriptor->Spare1 = 0x80;
if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
PIO_RESOURCE_DESCRIPTOR ioDesc;
ioDesc = ioResourceDescriptor;
ioDesc--;
while (ioDesc >= ioResourceList->Descriptors) {
ioDesc->Type = CmResourceTypeNull;
ioResourceList->Count--;
if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
ioDesc--;
} else {
break;
}
}
}
ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
if (ioResourceDescriptor->Type == CmResourceTypePort ||
ioResourceDescriptor->Type == CmResourceTypeMemory) {
ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
ioResourceDescriptor->u.Port.Alignment = 1;
} else if (ioResourceDescriptor->Type == CmResourceTypeBusNumber) {
ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
}
ioResourceDescriptor++;
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
ioResourceDescriptor->Type = CmResourceTypeNull;
ioResourceDescriptor++;
ioResourceList->Count--;
} else {
break;
}
}
phase = 1; // skip phase 1
break;
} else {
ioResourceDescriptor++;
}
} else {
exactMatch = FALSE;
if (share1 == share2 && min2 <= min1 && max2 >= max1 && len2 >= len1 &&
(min1 & (align2 - 1)) == 0) {
//
// Io range covers Cm range ... Change the Io range to what is specified
// in BootConfig.
//
//
switch (cmDescriptor->Type) {
case CmResourceTypePort:
case CmResourceTypeMemory:
ioResourceDescriptor->u.Port.MinimumAddress.QuadPart = min1;
ioResourceDescriptor->u.Port.MaximumAddress.QuadPart = min1 + len2 - 1;
break;
case CmResourceTypeInterrupt:
case CmResourceTypeDma:
ioResourceDescriptor->u.Interrupt.MinimumVector = (ULONG)min1;
ioResourceDescriptor->u.Interrupt.MaximumVector = (ULONG)max1;
break;
case CmResourceTypeBusNumber:
ioResourceDescriptor->u.BusNumber.MinBusNumber = (ULONG)min1;
ioResourceDescriptor->u.BusNumber.MaxBusNumber = (ULONG)(min1 + len2 - 1);
break;
}
ioResourceList->Version++;
ioResourceDescriptor->Spare1 = 0x80;
if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
PIO_RESOURCE_DESCRIPTOR ioDesc;
ioDesc = ioResourceDescriptor;
ioDesc--;
while (ioDesc >= ioResourceList->Descriptors) {
ioDesc->Type = CmResourceTypeNull;
ioResourceList->Count--;
if (ioDesc->Option == IO_RESOURCE_ALTERNATIVE) {
ioDesc--;
} else {
break;
}
}
}
ioResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
ioResourceDescriptor++;
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
if (ioResourceDescriptor->Option & IO_RESOURCE_ALTERNATIVE) {
ioResourceDescriptor->Type = CmResourceTypeNull;
ioResourceList->Count--;
ioResourceDescriptor++;
} else {
break;
}
}
break;
} else {
ioResourceDescriptor++;
}
}
} else {
ioResourceDescriptor++;
}
} // Don't add any instruction after this ...
} // phase
} // switch
//
// Move to next Cm Descriptor
//
cmDescriptor++;
cmDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmDescriptor + size);
}
//
// Move to next Cm List
//
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmDescriptor;
}
if (ioResourceList->Version != (USHORT)cmDescriptorCount) {
//
// If the current alternative list does not cover all the boot config
// descriptors, make it as invalid.
//
ioResourceList->Version = 0xffff;
ioList->AlternativeLists--;
} else {
ioResourceDescriptorCount += ioResourceList->Count;
ioResourceList->Version = version;
ioResourceList->Count = oldCount; // ++ single alternative list
break; // ++ single alternative list
}
ioResourceList->Count = oldCount;
//
// Move to next Io alternative list.
//
ioResourceList = (PIO_RESOURCE_LIST) ioResourceDescriptorEnd;
}
//
// If there is not any valid alternative, convert CmList to Io list.
//
if (ioList->AlternativeLists == 0) {
*FilteredList = PipCmResourcesToIoResources (CmList);
ExFreePool(ioList);
return STATUS_SUCCESS;
}
//
// we have finished filtering the resource requirements list. Now allocate memory
// and rebuild a new list.
//
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
//sizeof(IO_RESOURCE_LIST) * (ioList->AlternativeLists - 1) + // ++ Single Alternative list
sizeof(IO_RESOURCE_DESCRIPTOR) * (ioResourceDescriptorCount);
newList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
if (newList == NULL) {
ExFreePool(ioList);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Walk through the io resource requirements list and pick up any valid descriptor.
//
newList->ListSize = size;
newList->InterfaceType = CmList->List->InterfaceType;
newList->BusNumber = CmList->List->BusNumber;
newList->SlotNumber = ioList->SlotNumber;
#if 0 // ++ Single Alternative list
newList->AlternativeLists = ioList->AlternativeLists;
#else
newList->AlternativeLists = 1;
#endif
ioResourceList = ioList->List;
newIoResourceList = newList->List;
while (--alternativeLists >= 0) {
ioResourceDescriptor = ioResourceList->Descriptors;
ioResourceDescriptorEnd = ioResourceDescriptor + ioResourceList->Count;
if (ioResourceList->Version == 0xffff) {
ioResourceList = (PIO_RESOURCE_LIST)ioResourceDescriptorEnd;
continue;
}
newIoResourceList->Version = ioResourceList->Version;
newIoResourceList->Revision = ioResourceList->Revision;
newIoResourceDescriptor = newIoResourceList->Descriptors;
if (ioResourceDescriptor->Type != CmResourceTypeConfigData) {
newIoResourceDescriptor->Option = IO_RESOURCE_PREFERRED;
newIoResourceDescriptor->Type = CmResourceTypeConfigData;
newIoResourceDescriptor->ShareDisposition = CmResourceShareShared;
newIoResourceDescriptor->Flags = 0;
newIoResourceDescriptor->Spare1 = 0;
newIoResourceDescriptor->Spare2 = 0;
newIoResourceDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
configDataDescriptor = newIoResourceDescriptor;
newIoResourceDescriptor++;
} else {
newList->ListSize -= sizeof(IO_RESOURCE_DESCRIPTOR);
configDataDescriptor = newIoResourceDescriptor;
}
while (ioResourceDescriptor < ioResourceDescriptorEnd) {
if (ioResourceDescriptor->Type != CmResourceTypeNull) {
*newIoResourceDescriptor = *ioResourceDescriptor;
newIoResourceDescriptor++;
}
ioResourceDescriptor++;
}
newIoResourceList->Count = (ULONG)(newIoResourceDescriptor - newIoResourceList->Descriptors);
configDataDescriptor->u.ConfigData.Priority = BOOT_CONFIG_PRIORITY;
break;
}
ASSERT((PUCHAR)newIoResourceDescriptor == ((PUCHAR)newList + newList->ListSize));
*FilteredList = newList;
*ExactMatch = exactMatch;
ExFreePool(ioList);
return STATUS_SUCCESS;
}
PCM_PARTIAL_RESOURCE_DESCRIPTOR
PipFindMatchingBootMemResource(
IN ULONG Index,
IN PIO_RESOURCE_DESCRIPTOR IoDesc,
IN PCM_RESOURCE_LIST BootResources
)
/*++
Routine Description:
This routine finds boot resources that match the i/o descriptor
Arguments:
Index - Index of memory boot config resource the caller is interested in.
IoDesc - I/O descriptor
BootResources - boot config
Return Value:
A pointer to a matching descriptor in the boot config
--*/
{
PCM_FULL_RESOURCE_DESCRIPTOR cmFullDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartDesc;
ULONG count = 0, size, i, j, noMem;
if (BootResources == NULL) {
return NULL;
}
cmFullDesc = &BootResources->List[0];
for (i = 0; i < BootResources->Count; i++) {
cmPartDesc = &cmFullDesc->PartialResourceList.PartialDescriptors[0];
noMem = 0;
for (j = 0; j < cmFullDesc->PartialResourceList.Count; j++) {
size = 0;
if (cmPartDesc->Type == CmResourceTypeMemory) {
if (((cmPartDesc->u.Memory.Start.QuadPart >=
IoDesc->u.Memory.MinimumAddress.QuadPart) &&
((cmPartDesc->u.Memory.Start.QuadPart +
cmPartDesc->u.Memory.Length - 1) <=
IoDesc->u.Memory.MaximumAddress.QuadPart)) &&
noMem == Index) {
return cmPartDesc;
}
noMem++;
} else if (cmPartDesc->Type == CmResourceTypeDeviceSpecific) {
size = cmPartDesc->u.DeviceSpecificData.DataSize;
}
cmPartDesc++;
cmPartDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR)cmPartDesc + size);
}
cmFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)cmPartDesc;
}
return NULL;
}
NTSTATUS
PipTrimResourceRequirements (
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoList,
IN USHORT IrqFlags,
IN PCM_RESOURCE_LIST BootResources
)
/*++
Routine Description:
This routine:
* adjusts the irq requirements level/edge to the value
decided on in PipCheckBus()
* adjusts the memory requirements to reflect the memory boot
config.
Arguments:
IoList - supplies the pointer to an IoResourceRequirementsList
IrqFlags - level/edge irq reuirements to be applied to all interrupt requirements in all alternatives.
BootResources - Used as a reference.
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST newReqList;
PIO_RESOURCE_LIST resList, newList;
PIO_RESOURCE_DESCRIPTOR resDesc, newDesc;
PCM_PARTIAL_RESOURCE_DESCRIPTOR bootDesc;
ULONG listCount, i, j, pass, size, noMem;
BOOLEAN goodAlt;
if (IoList == NULL) {
return STATUS_SUCCESS;
}
// The only way to create a new req list only if absolutely
// necessary and make it the perfect size is perform this
// operation in two passes.
// 1. figure out how many alternatives will be eliminated and
// compute size of new req list. if all of the alternatives
// survived, return the original list (now modified)
//
// 2. construct new reqlist minus the bad alternatives.
listCount = 0;
size = 0;
for (pass = 0; pass < 2; pass++) {
if (pass == 0) {
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
sizeof(IO_RESOURCE_LIST);
} else {
newReqList = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool(PagedPool, size);
if (newReqList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
*newReqList = **IoList;
newReqList->ListSize = size;
newReqList->AlternativeLists = listCount;
newList = &newReqList->List[0];
}
resList = &(*IoList)->List[0];
for (i = 0; i < (*IoList)->AlternativeLists; i++) {
if (pass == 1) {
*newList = *resList;
newDesc = &newList->Descriptors[0];
}
resDesc = &resList->Descriptors[0];
goodAlt = TRUE;
noMem = 0;
for (j = 0; j < resList->Count; j++) {
if (resDesc->Type == CmResourceTypeInterrupt) {
resDesc->Flags = IrqFlags;
if (resDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {
resDesc->ShareDisposition = CmResourceShareDeviceExclusive;
}
} else if (resDesc->Type == CmResourceTypeMemory) {
resDesc->Flags |= CM_RESOURCE_MEMORY_24;
if (BootResources) {
bootDesc = PipFindMatchingBootMemResource(noMem, resDesc, BootResources);
// have matching boot config resource, can trim requirements
if (bootDesc) {
if (bootDesc->Flags & CM_RESOURCE_MEMORY_READ_ONLY) {
// exact or inclusive ROM match is
// converted into a fixed requirement.
resDesc->u.Memory.MinimumAddress.QuadPart =
bootDesc->u.Memory.Start.QuadPart;
if (bootDesc->u.Memory.Length) {
resDesc->u.Memory.MaximumAddress.QuadPart =
bootDesc->u.Memory.Start.QuadPart +
bootDesc->u.Memory.Length - 1;
} else {
resDesc->u.Memory.MaximumAddress.QuadPart =
bootDesc->u.Memory.Start.QuadPart;
}
resDesc->u.Memory.Length = bootDesc->u.Memory.Length;
resDesc->u.Memory.Alignment = 1;
resDesc->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
}
} else {
goodAlt = FALSE;
}
} else {
resDesc->Flags &= ~CM_RESOURCE_MEMORY_READ_ONLY;
}
noMem++;
}
if (pass == 1) {
*newDesc = *resDesc;
PipDumpIoResourceDescriptor(" ", newDesc);
newDesc++;
}
resDesc++;
}
if (pass == 0) {
if (goodAlt) {
size += sizeof(IO_RESOURCE_LIST) +
sizeof(IO_RESOURCE_DESCRIPTOR) * (resList->Count - 1);
listCount++;
}
} else {
if (goodAlt) {
newList = (PIO_RESOURCE_LIST) newDesc;
} else {
DebugPrint((DEBUG_RESOURCE, "An alternative trimmed off of reqlist\n"));
}
}
resList = (PIO_RESOURCE_LIST) resDesc;
}
// If we have the same number of alternatives as before use
// the use existing (modified in-place) requirements list
if (!pass && (listCount == (*IoList)->AlternativeLists)) {
return STATUS_SUCCESS;
}
// if all alternatives have been eliminated, then it is better
// to use the existing requirements list than to hope to build
// one out of the boot config alone.
if (!pass && (listCount == 0)) {
DebugPrint((DEBUG_RESOURCE, "All alternatives trimmed off of reqlist, going with original\n"));
return STATUS_SUCCESS;
}
}
ExFreePool(*IoList);
*IoList = newReqList;
return STATUS_SUCCESS;
}
#endif