You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1863 lines
61 KiB
1863 lines
61 KiB
/*++
|
|
|
|
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
|
|
|
|
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 (
|
|
IN PUCHAR DeviceData,
|
|
IN ULONG IdIndex,
|
|
OUT PWCHAR *Buffer,
|
|
OUT PULONG BufferSize
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
BufferSize - the length of the pointer allocated and returned to the caller in *Buffer.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_NO_MORE_ENTRIES;
|
|
UCHAR tag;
|
|
ULONG count = 0,length;
|
|
LONG size;
|
|
UNICODE_STRING unicodeString;
|
|
WCHAR eisaId[8];
|
|
ULONG id;
|
|
ULONG bufferSize;
|
|
|
|
|
|
//
|
|
// 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) {
|
|
*BufferSize = length;
|
|
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);
|
|
RtlInitUnicodeString(&unicodeString, eisaId);
|
|
|
|
bufferSize = sizeof(L"*") + sizeof(WCHAR) + unicodeString.Length;
|
|
*Buffer = (PWCHAR)ExAllocatePool (
|
|
PagedPool,
|
|
bufferSize
|
|
);
|
|
if (*Buffer) {
|
|
|
|
if (FAILED(StringCbPrintf(*Buffer,
|
|
bufferSize,
|
|
L"*%s",
|
|
unicodeString.Buffer
|
|
))) {
|
|
|
|
ASSERT(FALSE);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else {
|
|
*BufferSize = bufferSize;
|
|
}
|
|
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PipQueryDeviceUniqueId (
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
OUT PWCHAR *DeviceId,
|
|
OUT PULONG DeviceIdLength
|
|
)
|
|
/*++
|
|
|
|
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.
|
|
|
|
DeviceIdLength - On success, will contain the length of the buffer
|
|
allocated and returned to the caller in *DeviceId
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG size;
|
|
|
|
//
|
|
// Set up device's unique id.
|
|
// device unique id = SerialNumber of the card
|
|
//
|
|
|
|
size = (8 + 1) * sizeof(WCHAR); // serial number + null
|
|
|
|
*DeviceId = (PWCHAR)ExAllocatePool (
|
|
PagedPool,
|
|
size
|
|
);
|
|
if (*DeviceId) {
|
|
if (DeviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
//
|
|
// Override the unique ID for the RDP
|
|
//
|
|
StringCbPrintf(*DeviceId,
|
|
size,
|
|
L"0"
|
|
);
|
|
|
|
} else {
|
|
StringCbPrintf (*DeviceId,
|
|
size,
|
|
L"%01X",
|
|
((PSERIAL_IDENTIFIER) (DeviceInfo->CardInformation->CardData))->SerialNumber
|
|
);
|
|
}
|
|
|
|
*DeviceIdLength = size;
|
|
|
|
#if IDBG
|
|
{
|
|
ANSI_STRING ansiString;
|
|
UNICODE_STRING unicodeString;
|
|
|
|
RtlInitUnicodeString(&unicodeString, *DeviceId);
|
|
if (NT_SUCCESS(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 (
|
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|
OUT PWCHAR *DeviceId,
|
|
OUT PULONG DeviceIdLength,
|
|
IN 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.
|
|
|
|
DeviceIdLength - On success, will contain the length of the buffer
|
|
allocated and returned to the caller in *DeviceId
|
|
|
|
IdIndex - specifies device id or compatible id (0 - device id)
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PWSTR format;
|
|
ULONG size,length;
|
|
WCHAR eisaId[8];
|
|
UNICODE_STRING unicodeString;
|
|
|
|
|
|
//
|
|
// 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) {
|
|
*DeviceIdLength = length;
|
|
StringCbPrintf(*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
|
|
);
|
|
RtlInitUnicodeString(&unicodeString, eisaId);
|
|
|
|
size += unicodeString.Length;
|
|
*DeviceId = (PWCHAR)ExAllocatePool (PagedPool, size);
|
|
if (*DeviceId) {
|
|
|
|
*DeviceIdLength = size;
|
|
StringCbPrintf(*DeviceId,
|
|
size,
|
|
format,
|
|
unicodeString.Buffer,
|
|
DeviceInfo->LogicalDeviceNumber
|
|
);
|
|
#if IDBG
|
|
{
|
|
ANSI_STRING dbgAnsiString;
|
|
UNICODE_STRING dbgUnicodeString;
|
|
|
|
RtlInitUnicodeString(&dbgUnicodeString, *DeviceId);
|
|
if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&dbgAnsiString, &dbgUnicodeString, TRUE))) {
|
|
DbgPrint("PnpIsa: return device Id = %s\n", dbgAnsiString.Buffer);
|
|
RtlFreeAnsiString(&dbgAnsiString);
|
|
}
|
|
}
|
|
#endif
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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;
|
|
newList->AlternativeLists = 1;
|
|
|
|
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
|