Leaked source code of windows server 2003
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.
 
 
 
 
 
 

3179 lines
85 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
res_bios.c
Abstract:
This file contains routines to translate resources between PnP ISA/BIOS
format and Windows NT formats.
Author:
Shie-Lin Tzong (shielint) 12-Apr-1995
Stephane Plante (splante) 20-Nov-1996
Environment:
Kernel mode only.
Revision History:
20-Nov-1996:
Changed to conform with ACPI environment
22-Jan-1997:
Changed to remove all traces of original Shie Lin code
--*/
#include "pch.h"
#define RESOURCE_LIST_GROWTH_SIZE 8
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,PnpiBiosAddressHandleBusFlags)
#pragma alloc_text(PAGE,PnpiBiosAddressHandleGlobalFlags)
#pragma alloc_text(PAGE,PnpiBiosAddressHandleMemoryFlags)
#pragma alloc_text(PAGE,PnpiBiosAddressHandlePortFlags)
#pragma alloc_text(PAGE,PnpiBiosAddressToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosAddressDoubleToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosAddressQuadToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosDmaToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosExtendedIrqToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosIrqToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosMemoryToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosPortFixedToIoDescriptor)
#pragma alloc_text(PAGE,PnpiBiosPortToIoDescriptor)
#pragma alloc_text(PAGE,PnpiClearAllocatedMemory)
#pragma alloc_text(PAGE,PnpiGrowResourceDescriptor)
#pragma alloc_text(PAGE,PnpiGrowResourceList)
#pragma alloc_text(PAGE,PnpiUpdateResourceList)
#pragma alloc_text(PAGE,PnpBiosResourcesToNtResources)
#pragma alloc_text(PAGE,PnpIoResourceListToCmResourceList)
#endif
VOID
PnpiBiosAddressHandleBusFlags(
IN PVOID Buffer,
IN PIO_RESOURCE_DESCRIPTOR Descriptor
)
/*++
Routine Description:
This routine handles the Type specific flags in an Address Descriptor of
type Bus
Arguments:
Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
because the initial memory placement is identical
Descriptor - Where to set the flags
Return Value:
None
--*/
{
PAGED_CODE();
ASSERT(Descriptor->u.BusNumber.Length > 0);
}
VOID
PnpiBiosAddressHandleGlobalFlags(
IN PVOID Buffer,
IN PIO_RESOURCE_DESCRIPTOR Descriptor
)
/*++
Routine Descriptoin:
This routine handles all the Global 'generic' flags in an Address Descriptor
Arguments:
Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
because the initial memory placement is identical
Descriptor - Where to set the flags
Return Value:
None
--*/
{
PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
ULONG newValue;
ULONG oldValue;
ULONG bound;
PAGED_CODE();
//
// If the resource is marked as being consumed only, then it is
// exclusive, otherwise, it is shared
//
if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY) {
Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
} else {
Descriptor->ShareDisposition = CmResourceShareShared;
}
//
// Handle the hints that are given to us
//
if (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED &&
buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) {
if (Descriptor->Type == CmResourceTypeBusNumber) {
oldValue = Descriptor->u.BusNumber.Length;
newValue = Descriptor->u.BusNumber.Length =
Descriptor->u.BusNumber.MaxBusNumber -
Descriptor->u.BusNumber.MinBusNumber + 1;
} else {
oldValue = Descriptor->u.Memory.Length;
newValue = Descriptor->u.Memory.Length =
Descriptor->u.Memory.MaximumAddress.LowPart -
Descriptor->u.Memory.MinimumAddress.LowPart + 1;
}
} else if (buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) {
if (Descriptor->Type == CmResourceTypeBusNumber) {
bound = Descriptor->u.BusNumber.MaxBusNumber;
oldValue = Descriptor->u.BusNumber.MinBusNumber;
newValue = Descriptor->u.BusNumber.MinBusNumber = 1 +
Descriptor->u.BusNumber.MaxBusNumber -
Descriptor->u.BusNumber.Length;
} else {
bound = Descriptor->u.Memory.MaximumAddress.LowPart;
oldValue = Descriptor->u.Memory.MinimumAddress.LowPart;
newValue = Descriptor->u.Memory.MinimumAddress.LowPart = 1 +
Descriptor->u.Memory.MaximumAddress.LowPart -
Descriptor->u.Memory.Length;
}
} else if (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) {
if (Descriptor->Type == CmResourceTypeBusNumber) {
bound = Descriptor->u.BusNumber.MinBusNumber;
oldValue = Descriptor->u.BusNumber.MaxBusNumber;
newValue = Descriptor->u.BusNumber.MaxBusNumber =
Descriptor->u.BusNumber.MinBusNumber +
Descriptor->u.BusNumber.Length - 1;
} else {
bound = Descriptor->u.Memory.MinimumAddress.LowPart;
oldValue = Descriptor->u.Memory.MaximumAddress.LowPart;
newValue = Descriptor->u.Memory.MaximumAddress.LowPart =
Descriptor->u.Memory.MinimumAddress.LowPart -
Descriptor->u.Memory.Length - 1;
}
}
}
VOID
PnpiBiosAddressHandleMemoryFlags(
IN PVOID Buffer,
IN PIO_RESOURCE_DESCRIPTOR Descriptor
)
/*++
Routine Description:
This routine handles the Type specific flags in an Address Descriptor of
type Memory
Arguments:
Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
because the initial memory placement is identical
Descriptor - Where to set the flags
Return Value:
None
--*/
{
PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
PAGED_CODE();
//
// Set the proper memory type flags
//
switch( buffer->TFlag & PNP_ADDRESS_TYPE_MEMORY_MASK) {
case PNP_ADDRESS_TYPE_MEMORY_CACHEABLE:
Descriptor->Flags |= CM_RESOURCE_MEMORY_CACHEABLE;
break;
case PNP_ADDRESS_TYPE_MEMORY_WRITE_COMBINE:
Descriptor->Flags |= CM_RESOURCE_MEMORY_COMBINEDWRITE;
break;
case PNP_ADDRESS_TYPE_MEMORY_PREFETCHABLE:
Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
break;
case PNP_ADDRESS_TYPE_MEMORY_NONCACHEABLE:
break;
default:
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpiBiosAddressHandleMemoryFlags: Unknown Memory TFlag "
"0x%02x\n",
buffer->TFlag
) );
break;
}
//
// This bit is used to turn on/off write access to memory
//
if (buffer->TFlag & PNP_ADDRESS_TYPE_MEMORY_READ_WRITE) {
Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
} else {
Descriptor->Flags |= CM_RESOURCE_MEMORY_READ_ONLY;
}
}
VOID
PnpiBiosAddressHandlePortFlags(
IN PVOID Buffer,
IN PIO_RESOURCE_DESCRIPTOR Descriptor
)
/*++
Routine Description:
This routine handles the Type specific flags in an Address Descriptor of
type Port
Arguments:
Buffer - The pnp descriptor. Can be a WORD, DWORD, or QWORD descriptor,
because the initial memory placement is identical
Descriptor - Where to set the flags
Return Value:
None
--*/
{
PPNP_WORD_ADDRESS_DESCRIPTOR buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Buffer;
ULONG granularity = Descriptor->u.Port.Alignment;
PAGED_CODE();
//
// We can determine if the device uses a positive decode or not
//
if ( !(buffer->GFlag & PNP_ADDRESS_FLAG_SUBTRACTIVE_DECODE)) {
Descriptor->Flags |= CM_RESOURCE_PORT_POSITIVE_DECODE;
}
}
NTSTATUS
PnpiBiosAddressToIoDescriptor(
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status;
PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
PPNP_WORD_ADDRESS_DESCRIPTOR buffer;
ULONG alignment;
ULONG length;
UCHAR decodeLength;
USHORT parentMin, childMin, childMax;
PAGED_CODE();
ASSERT( Array != NULL );
buffer = (PPNP_WORD_ADDRESS_DESCRIPTOR) Data;
//
// Check to see if we are are allowed to use this resource
//
if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
return STATUS_SUCCESS;
}
//
// If the length of the address range is zero, ignore this descriptor.
// This makes it easier for BIOS writers to set up a template and then
// whack its length to zero if it doesn't apply.
//
if (buffer->AddressLength == 0) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// If this is I/O or Memory, then we will need to make enough space for
// a device private resource too.
//
if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
(buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Calling PnpiUpdateResourceList may have invalidated
// rangeDescriptor. So make sure it's OK now.
//
ASSERT(Array[ArrayIndex]->Count >= 2);
rangeDescriptor = privateDescriptor - 1;
privateDescriptor->Type = CmResourceTypeDevicePrivate;
//
// Mark this descriptor as containing the start
// address of the translated resource.
//
privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
//
// Fill in the top 32 bits of the start address.
//
privateDescriptor->u.DevicePrivate.Data[2] = 0;
}
//
// Do we met the minimum length requirements ?
//
if ( buffer->Length < PNP_ADDRESS_WORD_MINIMUM_LENGTH) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpiBiosAddressToIoDescriptor: Descriptor too small 0x%08lx\n",
buffer->Length
) );
//
// We can go no further
//
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
(ULONG_PTR) buffer,
buffer->Tag,
buffer->Length
);
}
//
// Length is the stored within the descriptor record
//
length = (ULONG)(buffer->AddressLength);
alignment = (ULONG) (buffer->Granularity) + 1;
//
// Calculate the bounds of both the parent and child sides of
// the bridge.
//
// The translation field applies to the parent address i.e.
// the child address is the address in the buffer and the
// parent address is the addition of the child address and
// the translation field.
//
parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
childMin = buffer->MinimumAddress;
childMax = buffer->MaximumAddress;
//
// Patch the length based on wether or not the min/max flags are set
//
if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
(buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
ULONG length2;
ULONG alignment2;
//
// Calculate the length based on the fact that the min and
// max addresses are locked down.
//
length2 = childMax - childMin + 1;
//
// Test #1 --- The length had better be correct
//
if (length2 != length) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Length does not match fixed attributes\n"
) );
length = length2;
}
//
// Test #2 --- The granularity had also better be correct
//
if ( (childMin & (ULONG) buffer->Granularity ) ) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Granularity does not match fixed attributes\n"
) );
alignment = 1;
}
}
//
// Handle the Resource type seperately
//
switch (buffer->RFlag) {
case PNP_ADDRESS_MEMORY_TYPE:
//
// Set the proper ranges
//
rangeDescriptor->u.Memory.Alignment = alignment;
rangeDescriptor->u.Memory.Length = length;
rangeDescriptor->u.Memory.MinimumAddress.LowPart = childMin;
rangeDescriptor->u.Memory.MaximumAddress.LowPart = childMax;
rangeDescriptor->u.Memory.MinimumAddress.HighPart =
rangeDescriptor->u.Memory.MaximumAddress.HighPart = 0;
rangeDescriptor->Type = CmResourceTypeMemory;
//
// The child address is the address in the PnP address
// space descriptor and the child descriptor will inherit
// the descriptor type from the PnP address space
// descriptor.
//
if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// change from Memory to IO.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypePort;
} else {
//
// The parent descriptor type will not change.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypeMemory;
}
//
// Fill in the bottom 32 bits of the parent's start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
//
// Handle memory flags
//
PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
//
// Reset the alignment
//
rangeDescriptor->u.Memory.Alignment = 1;
break;
case PNP_ADDRESS_IO_TYPE:
//
// Any flags that are set here must be handled
// through the use of device privates
//
rangeDescriptor->u.Port.Alignment = alignment;
rangeDescriptor->u.Port.Length = length;
rangeDescriptor->u.Port.MinimumAddress.LowPart = childMin;
rangeDescriptor->u.Port.MaximumAddress.LowPart = childMax;
rangeDescriptor->u.Port.MinimumAddress.HighPart =
rangeDescriptor->u.Port.MaximumAddress.HighPart = 0;
rangeDescriptor->Type = CmResourceTypePort;
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
}
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// change from IO to Memory.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypeMemory;
} else {
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypePort;
}
//
// Fill in the bottom 32 bits of the parent's start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
//
// Handle port flags
//
PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
//
// Reset the alignment
//
rangeDescriptor->u.Port.Alignment = 1;
break;
case PNP_ADDRESS_BUS_NUMBER_TYPE:
rangeDescriptor->Type = CmResourceTypeBusNumber;
rangeDescriptor->u.BusNumber.MinBusNumber = (buffer->MinimumAddress);
rangeDescriptor->u.BusNumber.MaxBusNumber = (buffer->MaximumAddress);
rangeDescriptor->u.BusNumber.Length = length;
//
// Handle busnumber flags
//
PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
break;
default:
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpiBiosAddressToIoDescriptor: Unknown Type 0x%2x\n",
buffer->RFlag ) );
break;
}
//
// Handle global flags
//
PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
return STATUS_SUCCESS;
}
NTSTATUS
PnpiBiosAddressDoubleToIoDescriptor(
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status;
PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
PPNP_DWORD_ADDRESS_DESCRIPTOR buffer;
UCHAR decodeLength;
ULONG alignment;
ULONG length;
ULONG parentMin, childMin, childMax;
PAGED_CODE();
ASSERT( Array != NULL );
buffer = (PPNP_DWORD_ADDRESS_DESCRIPTOR) Data;
//
// Check to see if we are are allowed to use this resource
//
if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
return STATUS_SUCCESS;
}
//
// If the length of the address range is zero, ignore this descriptor.
// This makes it easier for BIOS writers to set up a template and then
// whack its length to zero if it doesn't apply.
//
if (buffer->AddressLength == 0) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// If this is I/O or Memory, then we will need to make enough space for
// a device private resource too.
//
if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
(buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Calling PnpiUpdateResourceList may have invalidated
// rangeDescriptor. So make sure it's OK now.
//
ASSERT(Array[ArrayIndex]->Count >= 2);
rangeDescriptor = privateDescriptor - 1;
privateDescriptor->Type = CmResourceTypeDevicePrivate;
//
// Mark this descriptor as containing the start
// address of the translated resource.
//
privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
//
// Fill in the top 32 bits of the start address.
//
privateDescriptor->u.DevicePrivate.Data[2] = 0;
}
//
//
// Do we met the minimum length requirements ?
//
if ( buffer->Length < PNP_ADDRESS_DWORD_MINIMUM_LENGTH) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpiBiosAddressDoubleToIoDescriptor: Descriptor too small 0x%08lx\n",
buffer->Length ) );
//
// We can go no further
//
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
(ULONG_PTR) buffer,
buffer->Tag,
buffer->Length
);
}
//
// Length is the stored within the descriptor record
//
// Note. AddressLength field and Granularity field are both ULONG
// values and don't require casting. beware if you cut and paste
// this code as other descriptor types don't necessarily match that.
//
length = buffer->AddressLength;
alignment = buffer->Granularity + 1;
//
// Calculate the bounds of both the parent and child sides of
// the bridge.
//
// The translation field applies to the parent address i.e.
// the child address is the address in the buffer and the
// parent address is the addition of the child address and
// the translation field.
//
parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
childMin = buffer->MinimumAddress;
childMax = buffer->MaximumAddress;
//
// Patch the length based on wether or not the min/max flags are set
//
if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
(buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
ULONG length2;
ULONG alignment2;
//
// Calculate the length based on the fact that the min and
// max addresses are locked down.
//
length2 = childMax - childMin + 1;
//
// Test #1 --- The length had better be correct
//
if (length2 != length) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Length does not match fixed attributes\n"
) );
length = length2;
}
//
// Test #2 --- The granularity had also better be correct
//
if ( (childMin & buffer->Granularity) ) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Granularity does not match fixed attributes\n"
) );
alignment = 1;
}
}
//
// Handle the Resource type seperately
//
switch (buffer->RFlag) {
case PNP_ADDRESS_MEMORY_TYPE:
//
// Set the proper ranges
//
rangeDescriptor->u.Memory.Alignment = alignment;
rangeDescriptor->u.Memory.Length = length;
rangeDescriptor->u.Memory.MinimumAddress.LowPart = childMin;
rangeDescriptor->u.Memory.MaximumAddress.LowPart = childMax;
rangeDescriptor->u.Memory.MinimumAddress.HighPart =
rangeDescriptor->u.Memory.MaximumAddress.HighPart = 0;
rangeDescriptor->Type = CmResourceTypeMemory;
//
// The child address is the address in the PnP address
// space descriptor and the child descriptor will inherit
// the descriptor type from the PnP address space
// descriptor.
//
if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// changed from Memory to IO.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypePort;
} else {
//
// The parent descriptor type will not change.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypeMemory;
}
//
// Fill in the bottom 32 bits of the parent's start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
//
// Handle memory flags
//
PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
//
// Reset the alignment
//
rangeDescriptor->u.Memory.Alignment = 1;
break;
case PNP_ADDRESS_IO_TYPE:
//
// Any flags that are set here must be handled
// through the use of device privates
//
rangeDescriptor->u.Port.Alignment = alignment;
rangeDescriptor->u.Port.Length = length;
rangeDescriptor->u.Port.MinimumAddress.LowPart = childMin;
rangeDescriptor->u.Port.MaximumAddress.LowPart = childMax;
rangeDescriptor->u.Port.MinimumAddress.HighPart =
rangeDescriptor->u.Port.MaximumAddress.HighPart = 0;
rangeDescriptor->Type = CmResourceTypePort;
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
}
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// changed from IO to Memory.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypeMemory;
} else {
//
// The parent descriptor type will not change.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypePort;
}
//
// Fill in the bottom 32 bits of the parent's start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = parentMin;
//
// Handle port flags
//
PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
//
// Reset the alignment
//
rangeDescriptor->u.Port.Alignment = 1;
break;
case PNP_ADDRESS_BUS_NUMBER_TYPE:
rangeDescriptor->Type = CmResourceTypeBusNumber;
rangeDescriptor->u.BusNumber.Length = length;
rangeDescriptor->u.BusNumber.MinBusNumber = (buffer->MinimumAddress);
rangeDescriptor->u.BusNumber.MaxBusNumber = (buffer->MaximumAddress);
//
// Handle busnumber flags
//
PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
break;
default:
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpiBiosAddressDoubleToIoDescriptor: Unknown Type 0x%2x\n",
buffer->RFlag ) );
break;
}
//
// Handle global flags
//
PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
return STATUS_SUCCESS;
}
NTSTATUS
PnpiBiosAddressQuadToIoDescriptor(
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status;
PIO_RESOURCE_DESCRIPTOR rangeDescriptor, privateDescriptor;
PPNP_QWORD_ADDRESS_DESCRIPTOR buffer;
UCHAR decodeLength;
ULONGLONG alignment;
ULONGLONG length;
ULONGLONG parentMin, childMin, childMax;
PAGED_CODE();
ASSERT( Array != NULL );
buffer = (PPNP_QWORD_ADDRESS_DESCRIPTOR) Data;
//
// Check to see if we are are allowed to use this resource
//
if (buffer->GFlag & PNP_ADDRESS_FLAG_CONSUMED_ONLY &&
buffer->RFlag == PNP_ADDRESS_IO_TYPE &&
Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
return STATUS_SUCCESS;
}
//
// If the length of the address range is zero, ignore this descriptor.
// This makes it easier for BIOS writers to set up a template and then
// whack its length to zero if it doesn't apply.
//
if (buffer->AddressLength == 0) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &rangeDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// If this is I/O or Memory, then we will need to make enough space for
// a device private resource too.
//
if ((buffer->RFlag == PNP_ADDRESS_MEMORY_TYPE) ||
(buffer->RFlag == PNP_ADDRESS_IO_TYPE)) {
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &privateDescriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Calling PnpiUpdateResourceList may have invalidated
// rangeDescriptor. So make sure it's OK now.
//
ASSERT(Array[ArrayIndex]->Count >= 2);
rangeDescriptor = privateDescriptor - 1;
privateDescriptor->Type = CmResourceTypeDevicePrivate;
//
// Mark this descriptor as containing the start
// address of the translated resource.
//
privateDescriptor->Flags = TRANSLATION_DATA_PARENT_ADDRESS;
}
//
//
// Do we met the minimum length requirements ?
//
if ( buffer->Length < PNP_ADDRESS_QWORD_MINIMUM_LENGTH) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpiBiosAddressQuadToIoDescriptor: Descriptor too small 0x%08lx\n",
buffer->Length ) );
//
// We can go no further
//
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_PNP_RESOURCE_LIST_BUFFER_TOO_SMALL,
(ULONG_PTR) buffer,
buffer->Tag,
buffer->Length
);
}
//
// Length is the stored within the descriptor record
//
length = (ULONGLONG) (buffer->AddressLength);
alignment = (ULONGLONG) (buffer->Granularity) + 1;
//
// Calculate the bounds of both the parent and child sides of
// the bridge.
//
// The translation field applies to the parent address i.e.
// the child address is the address in the buffer and the
// parent address is the addition of the child address and
// the translation field.
//
parentMin = buffer->MinimumAddress + buffer->TranslationAddress;
childMin = buffer->MinimumAddress;
childMax = buffer->MaximumAddress;
//
// Patch the length based on wether or not the min/max flags are set
//
if ( (buffer->GFlag & PNP_ADDRESS_FLAG_MINIMUM_FIXED) &&
(buffer->GFlag & PNP_ADDRESS_FLAG_MAXIMUM_FIXED) ) {
ULONGLONG length2;
ULONGLONG alignment2;
//
// Calculate the length based on the fact that the min and
// max addresses are locked down.
//
length2 = childMax - childMin + 1;
//
// Test #1 --- The length had better be correct
//
if (length2 != length) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Length does not match fixed attributes\n"
) );
length = length2;
}
//
// Test #2 --- The granularity had also better be correct
//
if ( (childMin & (ULONGLONG) buffer->Granularity) ) {
//
// Bummer. Let the world know
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"ACPI: Granularity does not match fixed attributes\n"
) );
alignment = 1;
}
}
if (length > MAXULONG) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"ACPI: descriptor length %I64x exceeds MAXULONG\n",
length
) );
if ((!(AcpiOverrideAttributes & ACPI_OVERRIDE_DELL_MAXULONG_BUGCHECK)) || (childMin < MAXULONG)) {
//
// We can go no further
//
KeBugCheckEx(
ACPI_BIOS_ERROR,
ACPI_PNP_RESOURCE_LIST_LENGTH_TOO_LARGE,
(ULONG_PTR) buffer,
buffer->Tag,
(ULONG_PTR)&length
);
}
}
//
// Handle the Resource type seperately
//
switch (buffer->RFlag) {
case PNP_ADDRESS_MEMORY_TYPE:
//
// Set the proper ranges
//
rangeDescriptor->u.Memory.Alignment = (ULONG)alignment ;
rangeDescriptor->u.Memory.Length = (ULONG)length;
rangeDescriptor->u.Memory.MinimumAddress.QuadPart = childMin;
rangeDescriptor->u.Memory.MaximumAddress.QuadPart = childMax;
rangeDescriptor->Type = CmResourceTypeMemory;
//
// The child address is the address in the PnP address
// space descriptor and the child descriptor will inherit
// the descriptor type from the PnP address space
// descriptor.
//
if (buffer->TFlag & TRANSLATION_MEM_TO_IO) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// changed from Memory to IO.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypePort;
} else {
//
// The parent descriptor type will not change.
//
privateDescriptor->u.DevicePrivate.Data[0] =
CmResourceTypeMemory;
}
//
// Fill in all 64 bits of the start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = (ULONG)(parentMin & 0xffffffff);
privateDescriptor->u.DevicePrivate.Data[2] = (ULONG)(parentMin >> 32);
//
// Handle memory flags
//
PnpiBiosAddressHandleMemoryFlags( buffer, rangeDescriptor );
break;
case PNP_ADDRESS_IO_TYPE:
//
// Any flags that are set here must be handled
// through the use of device privates
//
rangeDescriptor->u.Port.Alignment = (ULONG) alignment;
rangeDescriptor->u.Port.Length = (ULONG) length;
rangeDescriptor->u.Port.MinimumAddress.QuadPart = childMin;
rangeDescriptor->u.Port.MaximumAddress.QuadPart = childMax;
rangeDescriptor->Type = CmResourceTypePort;
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_SPARSE_TRANSLATION) {
privateDescriptor->Flags |= TRANSLATION_RANGE_SPARSE;
}
if (buffer->TFlag & PNP_ADDRESS_TYPE_IO_TRANSLATE_IO_TO_MEM) {
//
// The device private describes the parent. With this
// flag set, the descriptor type of the parent will
// change from IO to Memory.
//
privateDescriptor->u.DevicePrivate.Data[0] = CmResourceTypeMemory;
} else {
//
// Bridges that implement I/O on the parent side never
// implement memory on the child side.
//
privateDescriptor->u.DevicePrivate.Data[0] = CmResourceTypePort;
}
//
// Fill in all 64 bits of the start address.
//
privateDescriptor->u.DevicePrivate.Data[1] = (ULONG)(parentMin & 0xffffffff);
privateDescriptor->u.DevicePrivate.Data[2] = (ULONG)(parentMin >> 32);
//
// Handle port flags
//
PnpiBiosAddressHandlePortFlags( buffer, rangeDescriptor );
//
// Reset the alignment
//
rangeDescriptor->u.Port.Alignment = 1;
break;
case PNP_ADDRESS_BUS_NUMBER_TYPE:
rangeDescriptor->Type = CmResourceTypeBusNumber;
rangeDescriptor->u.BusNumber.Length = (ULONG) length;
rangeDescriptor->u.BusNumber.MinBusNumber = (ULONG) (buffer->MinimumAddress);
rangeDescriptor->u.BusNumber.MaxBusNumber = (ULONG) (buffer->MaximumAddress);
//
// Handle busnumber flags
//
PnpiBiosAddressHandleBusFlags( buffer, rangeDescriptor );
break;
default:
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpiBiosAddressQuadToIoDescriptor: Unknown Type 0x%2x\n",
buffer->RFlag ) );
break;
}
//
// Handle global flags
//
PnpiBiosAddressHandleGlobalFlags( buffer, rangeDescriptor );
return STATUS_SUCCESS;
}
NTSTATUS
PnpiBiosDmaToIoDescriptor (
IN PUCHAR Data,
IN UCHAR Channel,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN USHORT Count,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPNP_DMA_DESCRIPTOR buffer;
PAGED_CODE();
ASSERT (Array != NULL);
buffer = (PPNP_DMA_DESCRIPTOR)Data;
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in Io resource descriptor
//
descriptor->Option = (Count ? IO_RESOURCE_ALTERNATIVE : 0);
descriptor->Type = CmResourceTypeDma;
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
descriptor->u.Dma.MinimumChannel = Channel;
descriptor->u.Dma.MaximumChannel = Channel;
//
// Set some information about the type of DMA channel
//
switch ( (buffer->Flags & PNP_DMA_SIZE_MASK) ) {
case PNP_DMA_SIZE_8:
descriptor->Flags |= CM_RESOURCE_DMA_8;
break;
case PNP_DMA_SIZE_8_AND_16:
descriptor->Flags |= CM_RESOURCE_DMA_8_AND_16;
break;
case PNP_DMA_SIZE_16:
descriptor->Flags |= CM_RESOURCE_DMA_16;
break;
case PNP_DMA_SIZE_RESERVED:
default:
ASSERT( (buffer->Flags & 0x3) == 0x3);
descriptor->Flags |= CM_RESOURCE_DMA_32;
break;
}
if ( (buffer->Flags & PNP_DMA_BUS_MASTER) ) {
descriptor->Flags |= CM_RESOURCE_DMA_BUS_MASTER;
}
switch ( (buffer->Flags & PNP_DMA_TYPE_MASK) ) {
default:
case PNP_DMA_TYPE_COMPATIBLE:
break;
case PNP_DMA_TYPE_A:
descriptor->Flags |= CM_RESOURCE_DMA_TYPE_A;
break;
case PNP_DMA_TYPE_B:
descriptor->Flags |= CM_RESOURCE_DMA_TYPE_B;
break;
case PNP_DMA_TYPE_F:
descriptor->Flags |= CM_RESOURCE_DMA_TYPE_F;
break;
}
return status;
}
NTSTATUS
PnpiBiosExtendedIrqToIoDescriptor (
IN PUCHAR Data,
IN UCHAR DataIndex,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPNP_EXTENDED_IRQ_DESCRIPTOR buffer;
PULONG polarity;
PAGED_CODE();
ASSERT (Array != NULL);
buffer = (PPNP_EXTENDED_IRQ_DESCRIPTOR)Data;
//
// Are we within bounds?
//
if (DataIndex >= buffer->TableSize) {
return STATUS_INVALID_PARAMETER;
}
//
// Is the vector null? If so, then this is a 'skip' condition
//
if (buffer->Table[DataIndex] == 0) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in Io resource descriptor
//
descriptor->Option = (DataIndex ? IO_RESOURCE_ALTERNATIVE : 0);
descriptor->Type = CmResourceTypeInterrupt;
descriptor->u.Interrupt.MinimumVector =
descriptor->u.Interrupt.MaximumVector = buffer->Table[DataIndex];
//
// Crack the rest of the flags
//
descriptor->Flags = 0;
if ((buffer->Flags & PNP_EXTENDED_IRQ_MODE) == $LVL) {
descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
//
// Crack the share flags
//
if (buffer->Flags & PNP_EXTENDED_IRQ_SHARED) {
descriptor->ShareDisposition = CmResourceShareShared;
} else {
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
}
}
if ((buffer->Flags & PNP_EXTENDED_IRQ_MODE) == $EDG) {
descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
//
// Crack the share flags
//
if (buffer->Flags & PNP_EXTENDED_IRQ_SHARED) {
descriptor->ShareDisposition = CmResourceShareDriverExclusive;
} else {
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
}
}
//
// Warning! Awful HACK coming.
//
// The original designer of the flags for CmResourceTypeInterrupt
// was bad. Instead of a bit field, it's an enum. Which means
// that we can't add any flags now. So I'm stuffing the interrupt
// polarity information into an unused DWORD of the IO_RES_LIST.
//
polarity = (PULONG)(&descriptor->u.Interrupt.MaximumVector) + 1;
if ((buffer->Flags & PNP_EXTENDED_IRQ_POLARITY) == $LOW) {
*polarity = VECTOR_ACTIVE_LOW;
} else {
*polarity = VECTOR_ACTIVE_HIGH;
}
//
// To show anything else, we will need to use device private
// resources
//
return status;
}
NTSTATUS
PnpiBiosIrqToIoDescriptor (
IN PUCHAR Data,
IN USHORT Interrupt,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN USHORT Count,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPNP_IRQ_DESCRIPTOR buffer;
PULONG polarity;
PAGED_CODE();
ASSERT (Array != NULL);
buffer = (PPNP_IRQ_DESCRIPTOR)Data;
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in the resource descriptor
//
descriptor->Option = (Count ? IO_RESOURCE_ALTERNATIVE : 0);
descriptor->Type = CmResourceTypeInterrupt;
descriptor->u.Interrupt.MinimumVector = Interrupt;
descriptor->u.Interrupt.MaximumVector = Interrupt;
//
// Warning! Awful HACK coming.
//
// The original designer of the flags for CmResourceTypeInterrupt
// was bad. Instead of a bit field, it's an enum. Which means
// that we can't add any flags now. So I'm stuffing the interrupt
// polarity information into an unused DWORD of the IO_RES_LIST.
//
polarity = (PULONG)(&descriptor->u.Interrupt.MaximumVector) + 1;
if ( (buffer->Tag & SMALL_TAG_SIZE_MASK) == 3) {
//
// Set the type flags
//
descriptor->Flags = 0;
if (buffer->Information & PNP_IRQ_LATCHED) {
descriptor->Flags |= CM_RESOURCE_INTERRUPT_LATCHED;
*polarity = VECTOR_ACTIVE_HIGH;
//
// Set the share flags
//
if (buffer->Information & PNP_IRQ_SHARED) {
descriptor->ShareDisposition = CmResourceShareDriverExclusive;
} else {
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
}
}
if (buffer->Information & PNP_IRQ_LEVEL) {
descriptor->Flags |= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
*polarity = VECTOR_ACTIVE_LOW;
//
// Set the share flags
//
if (buffer->Information & PNP_IRQ_SHARED) {
descriptor->ShareDisposition = CmResourceShareShared;
} else {
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
}
}
} else {
descriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
}
return status;
}
NTSTATUS
PnpiBiosMemoryToIoDescriptor (
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PHYSICAL_ADDRESS minAddr;
PHYSICAL_ADDRESS maxAddr;
PIO_RESOURCE_DESCRIPTOR descriptor;
UCHAR tag;
ULONG alignment;
ULONG length = 0;
USHORT flags;
PAGED_CODE();
ASSERT (Array != NULL);
//
// Grab the memory range limits
//
tag = ((PPNP_MEMORY_DESCRIPTOR)Data)->Tag;
minAddr.HighPart = 0;
maxAddr.HighPart = 0;
flags = 0;
//
// Setup the flags
//
if ( ((PPNP_MEMORY_DESCRIPTOR)Data)->Information & PNP_MEMORY_READ_WRITE) {
flags |= CM_RESOURCE_MEMORY_READ_WRITE;
} else {
flags |= CM_RESOURCE_MEMORY_READ_ONLY;
}
//
// Grab the other values from the descriptor
//
switch (tag) {
case TAG_MEMORY: {
PPNP_MEMORY_DESCRIPTOR buffer;
//
// 24 Bit Memory
//
flags |= CM_RESOURCE_MEMORY_24;
buffer = (PPNP_MEMORY_DESCRIPTOR) Data;
length = ( (ULONG)(buffer->MemorySize) ) << 8;
minAddr.LowPart =( (ULONG)(buffer->MinimumAddress) ) << 8;
maxAddr.LowPart =( ( (ULONG)(buffer->MaximumAddress) ) << 8) + length - 1;
if ( (alignment = buffer->Alignment) == 0) {
alignment = 0x10000;
}
break;
}
case TAG_MEMORY32: {
PPNP_MEMORY32_DESCRIPTOR buffer;
buffer = (PPNP_MEMORY32_DESCRIPTOR) Data;
length = buffer->MemorySize;
minAddr.LowPart = buffer->MinimumAddress;
maxAddr.LowPart = buffer->MaximumAddress +length - 1;
alignment = buffer->Alignment;
break;
}
case TAG_MEMORY32_FIXED: {
PPNP_FIXED_MEMORY32_DESCRIPTOR buffer;
buffer = (PPNP_FIXED_MEMORY32_DESCRIPTOR) Data;
length = buffer->MemorySize;
minAddr.LowPart = buffer->BaseAddress;
maxAddr.LowPart = minAddr.LowPart + length - 1;
alignment = 1;
break;
}
default:
ASSERT( (tag != TAG_MEMORY) && (tag != TAG_MEMORY32) &&
(tag != TAG_MEMORY32_FIXED) );
}
//
// If the length that we calculated is 0, then we don't have a real
// descriptor that we should report
//
if (length == 0) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in common memory buffers
//
descriptor->Type = CmResourceTypeMemory;
descriptor->Flags = (CM_RESOURCE_PORT_MEMORY | flags);
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
//
// Fill in Memory Descriptor
//
descriptor->u.Memory.MinimumAddress = minAddr;
descriptor->u.Memory.MaximumAddress = maxAddr;
descriptor->u.Memory.Alignment = alignment;
descriptor->u.Memory.Length = length;
return STATUS_SUCCESS;
}
NTSTATUS
PnpiBiosPortFixedToIoDescriptor (
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPNP_FIXED_PORT_DESCRIPTOR buffer;
PAGED_CODE();
ASSERT (Array != NULL);
buffer = (PPNP_FIXED_PORT_DESCRIPTOR)Data;
//
// Check to see if we are are allowed to use this resource
//
if (Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
return STATUS_SUCCESS;
}
//
// If the length of the descriptor is 0, then we don't have a descriptor
// that we can report to the OS
//
if (buffer->Length == 0 ) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in Io resource descriptor
//
descriptor->Type = CmResourceTypePort;
descriptor->Flags = CM_RESOURCE_PORT_IO | CM_RESOURCE_PORT_10_BIT_DECODE;
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
descriptor->u.Port.Length = (ULONG)buffer->Length;
descriptor->u.Port.MinimumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff);
descriptor->u.Port.MaximumAddress.LowPart = (ULONG)(buffer->MinimumAddress & 0x3ff) +
(ULONG)buffer->Length - 1;
descriptor->u.Port.Alignment = 1;
return STATUS_SUCCESS;
}
NTSTATUS
PnpiBiosPortToIoDescriptor (
IN PUCHAR Data,
IN PIO_RESOURCE_LIST Array[],
IN ULONG ArrayIndex,
IN ULONG Flags
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_RESOURCE_DESCRIPTOR descriptor;
PPNP_PORT_DESCRIPTOR buffer;
PAGED_CODE();
ASSERT (Array != NULL);
buffer = (PPNP_PORT_DESCRIPTOR)Data;
//
// Check to see if we are are allowed to use this resource
//
if (Flags & PNP_BIOS_TO_IO_NO_CONSUMED_RESOURCES) {
return STATUS_SUCCESS;
}
//
// If the length of the descriptor is 0, then we don't have a descriptor
// that we can report to the OS
//
if (buffer->Length == 0 ) {
return STATUS_SUCCESS;
}
//
// Ensure that there is enough space within the chosen list to add the
// resource
//
status = PnpiUpdateResourceList( & (Array[ArrayIndex]), &descriptor );
if (!NT_SUCCESS(status)) {
return status;
}
//
// Fill in Io resource descriptor
//
descriptor->Type = CmResourceTypePort;
descriptor->Flags = CM_RESOURCE_PORT_IO;
descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
descriptor->u.Port.Length = (ULONG)buffer->Length;
descriptor->u.Port.MinimumAddress.LowPart = (ULONG)buffer->MinimumAddress;
descriptor->u.Port.MaximumAddress.LowPart = (ULONG)buffer->MaximumAddress +
buffer->Length - 1;
descriptor->u.Port.Alignment = (ULONG)buffer->Alignment;
//
// Set the flags
//
switch (buffer->Information & PNP_PORT_DECODE_MASK) {
case PNP_PORT_10_BIT_DECODE:
descriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
break;
default:
case PNP_PORT_16_BIT_DECODE:
descriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
break;
}
return STATUS_SUCCESS;
}
VOID
PnpiClearAllocatedMemory(
IN PIO_RESOURCE_LIST ResourceArray[],
IN ULONG ResourceArraySize
)
/*++
Routine Description:
This routine frees all the memory that was allocated in building the resource
lists in the system
Arguments:
ResourceArray - Table of PIO_RESOURCE_LIST
ResourceArraySize - How large the table is
Return Value:
VOID
--*/
{
ULONG i;
PAGED_CODE();
if (ResourceArray == NULL) {
return;
}
for (i = 0; i < ResourceArraySize; i++) {
if (ResourceArray[i] != NULL) {
ExFreePool( ResourceArray[i] );
}
}
ExFreePool( ResourceArray );
}
NTSTATUS
PnpiGrowResourceDescriptor(
IN OUT PIO_RESOURCE_LIST *ResourceList
)
/*++
Routine Description:
This routine takes a pointer to a Resource list and returns a pointer to resource list
that contained all the old information, but is now larger
Arguments:
ResourceList - ResourceList pointer to change
Return Value:
NTSTATUS (in case the memory allocation fails)
--*/
{
NTSTATUS status;
ULONG count = 0;
ULONG size = 0;
ULONG size2 = 0;
PAGED_CODE();
ASSERT( ResourceList != NULL );
//
// Are we looking at a null resource list???
//
if (*ResourceList == NULL) {
//
// Determine how much space is required
//
count = 0;
size = sizeof(IO_RESOURCE_LIST) + ( (count + 7) * sizeof(IO_RESOURCE_DESCRIPTOR) );
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpiGrowResourceDescriptor: Count: %d -> %d, Size: %#08lx\n",
count, count + RESOURCE_LIST_GROWTH_SIZE, size
) );
//
// Allocate the ResourceList
//
*ResourceList = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
//
// Failed?
//
if (*ResourceList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Init resource list
//
RtlZeroMemory( *ResourceList, size );
(*ResourceList)->Version = 0x01;
(*ResourceList)->Revision = 0x01;
(*ResourceList)->Count = 0x00;
return STATUS_SUCCESS;
}
//
// We already have a resource list, so what we should do is add 8 to the number of
// existing blocks that we have now, and copy over the old memory
//
count = (*ResourceList)->Count ;
size = sizeof(IO_RESOURCE_LIST) + ( (count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
size2 = size + (8 * sizeof(IO_RESOURCE_DESCRIPTOR) );
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpiGrowResourceDescriptor: Count: %d -> %d, Size: %#08lx\n",
count, count + RESOURCE_LIST_GROWTH_SIZE, size2
) );
//
// Grow the List
//
status = ACPIInternalGrowBuffer( ResourceList, size, size2 );
return status;
}
NTSTATUS
PnpiGrowResourceList(
IN OUT PIO_RESOURCE_LIST *ResourceListArray[],
IN OUT ULONG *ResourceListArraySize
)
/*++
Routine Description:
This function is responsible for growing the array of resource lists
Arguments:
ResourceListArray - An array of pointers to IO_RESOURCE_LISTs
ResourceListSize - The current size of the array
Return Value:
NTSTATUS (in case memory allocation fails)
--*/
{
NTSTATUS status;
ULONG count;
ULONG size;
ULONG size2;
PAGED_CODE();
ASSERT( ResourceListArray != NULL);
//
// Its always a special case if the table is null
//
if ( *ResourceListArray == NULL || *ResourceListArraySize == 0) {
count = 0;
size = (count + RESOURCE_LIST_GROWTH_SIZE ) * sizeof(PIO_RESOURCE_LIST);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpiGrowResourceList: Count: %d -> %d, Size: %#08lx\n",
count, count + RESOURCE_LIST_GROWTH_SIZE, size
) );
//
// Allocate the ResourceListArray
//
*ResourceListArray = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
//
// Failed?
//
if (*ResourceListArray == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Increment the size
//
*ResourceListArraySize = count + RESOURCE_LIST_GROWTH_SIZE;
RtlZeroMemory( *ResourceListArray, size );
return STATUS_SUCCESS;
}
count = *ResourceListArraySize;
size = count * sizeof(PIO_RESOURCE_LIST);
size2 = size + (RESOURCE_LIST_GROWTH_SIZE * sizeof(PIO_RESOURCE_LIST));
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpiGrowResourceList: Count: %d -> %d, Size: %#08lx\n",
count, count + RESOURCE_LIST_GROWTH_SIZE, size2
) );
status = ACPIInternalGrowBuffer( (PVOID *) ResourceListArray, size, size2 );
if (!NT_SUCCESS(status)) {
*ResourceListArraySize = 0;
} else {
*ResourceListArraySize = (count + RESOURCE_LIST_GROWTH_SIZE);
}
return status;
}
NTSTATUS
PnpiUpdateResourceList(
IN OUT PIO_RESOURCE_LIST *ResourceList,
OUT PIO_RESOURCE_DESCRIPTOR *ResourceDesc
)
/*++
Routine Description:
This function is called when a new resource is about to be added. This routine
ensures that enough space is present within the list, and gives a pointer to the
location of the Resource Descriptor where the list should be added...
Arguments:
ResourceList - Pointer to list to check
ResourceDesc - Location to store pointer to descriptor
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
ASSERT( ResourceList != NULL);
if ( *ResourceList == NULL ||
(*ResourceList)->Count % RESOURCE_LIST_GROWTH_SIZE == 0) {
//
// Oops, not enough space for the next descriptor
//
status = PnpiGrowResourceDescriptor( ResourceList );
if (!NT_SUCCESS(status)) {
return status;
}
}
//
// Find the next descriptor to use
//
*ResourceDesc = & ( (*ResourceList)->Descriptors[ (*ResourceList)->Count ] );
//
// Update the count of in-use descriptors
//
(*ResourceList)->Count += 1;
return status;
}
NTSTATUS
PnpBiosResourcesToNtResources(
IN PUCHAR Data,
IN ULONG Flags,
OUT PIO_RESOURCE_REQUIREMENTS_LIST *List
)
/*++
Routine Description:
This routine parses the Bios resource list and generates an NT resource list.
The returned NT resource list must be freed by the caller
Arguments:
Data - Pointer to PNP ISA Configuration Information
Flags - Options to use when parsing the data
List - Pointer to NT Configuration Information
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status;
PIO_RESOURCE_LIST *Array = NULL;
PUCHAR buffer;
UCHAR tagName;
USHORT increment;
ULONG ArraySize = 0;
ULONG ArrayIndex = 0;
ULONG ArrayAlternateIndex = 0;
ULONG size;
ULONG size2;
ULONG ResourceCount = 0;
ULONG VendorTagCount = 0;
PAGED_CODE();
ASSERT( Data != NULL );
//
// First we need to build the pointer list
//
status = PnpiGrowResourceList( &Array, &ArraySize );
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpBiosResourcesToNtResources: PnpiGrowResourceList = 0x%8lx\n",
status ) );
return status;
}
//
// Setup initial variables
//
buffer = Data;
tagName = *buffer;
//
// Look through all the descriptors.
//
while (TRUE) {
//
// Determine the size of the PNP resource descriptor
//
if ( !(tagName & LARGE_RESOURCE_TAG) ) {
//
// Small Tag
//
increment = (USHORT) (tagName & SMALL_TAG_SIZE_MASK) + 1;
tagName &= SMALL_TAG_MASK;
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: small = %#02lx incr = 0x%2lx\n",
tagName, increment ) );
} else {
//
// Large Tag
//
increment = ( *(USHORT UNALIGNED *)(buffer+1) ) + 3;
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: large = %#02lx incr = 0x%2lx\n",
tagName, increment
) );
}
//
// We are done if the current tag is the end tag
//
if (tagName == TAG_END) {
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_END\n"
) );
break;
}
ResourceCount++;
switch(tagName) {
case TAG_IRQ: {
USHORT mask = ( (PPNP_IRQ_DESCRIPTOR)buffer)->IrqMask;
USHORT interrupt = 0;
USHORT count = 0;
//
// Find all of interrupts to set
//
for ( ;mask && NT_SUCCESS(status); interrupt++, mask >>= 1) {
if (mask & 1) {
status = PnpiBiosIrqToIoDescriptor(
buffer,
interrupt,
Array,
ArrayIndex,
count,
Flags
);
count++;
}
}
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_IRQ(count: 0x%2lx) "
"= 0x%8lx\n",
count, status
) );
break;
}
case TAG_EXTENDED_IRQ: {
UCHAR tableSize =
( (PPNP_EXTENDED_IRQ_DESCRIPTOR)buffer)->TableSize;
UCHAR irqCount = 0;
//
// For each of the interrupts to set, do
//
for ( ;irqCount < tableSize && NT_SUCCESS(status); irqCount++) {
status = PnpiBiosExtendedIrqToIoDescriptor(
buffer,
irqCount,
Array,
ArrayIndex,
Flags
);
}
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_EXTENDED_IRQ(count: "
"0x%2lx) = 0x%8lx\n",
irqCount, status
) );
break;
}
case TAG_DMA: {
UCHAR mask = ( (PPNP_DMA_DESCRIPTOR)buffer)->ChannelMask;
UCHAR channel = 0;
USHORT count = 0;
//
// Find all the dma's to set
//
for ( ;mask && NT_SUCCESS(status); channel++, mask >>= 1 ) {
if (mask & 1) {
status = PnpiBiosDmaToIoDescriptor(
buffer,
channel,
Array,
ArrayIndex,
count,
Flags
);
count++;
}
}
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_DMA(count: 0x%2lx) "
"= 0x%8lx\n",
count, status
) );
break;
}
case TAG_START_DEPEND: {
//
// Increment the alternate list index
//
ArrayAlternateIndex++;
//
// This is now our current index
//
ArrayIndex = ArrayAlternateIndex;
//
// We need to use DevicePrivate data to give the
// arbiter a helping hand
//
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_START_DEPEND(Index: "
"0x%2lx)\n",
ArrayIndex
) );
//
// Make sure that there is a pointer allocated for this index
//
if (ArrayIndex == ArraySize) {
//
// Not enough space
//
status = PnpiGrowResourceList( &Array, &ArraySize );
}
break;
}
case TAG_END_DEPEND: {
//
// Debug Info
//
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_END_DEPEND(Index: "
"0x%2lx)\n",
ArrayIndex
) );
//
// All we have to do is go back to our original index
//
ArrayIndex = 0;
break;
}
case TAG_IO: {
status = PnpiBiosPortToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_IO = 0x%8lx\n",
status
) );
break;
}
case TAG_IO_FIXED: {
status = PnpiBiosPortFixedToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_IO_FIXED = 0x%8lx\n",
status
) );
break;
}
case TAG_MEMORY:
case TAG_MEMORY32:
case TAG_MEMORY32_FIXED: {
status = PnpiBiosMemoryToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_MEMORY = 0x%8lx\n",
status
) );
break;
}
case TAG_WORD_ADDRESS: {
status = PnpiBiosAddressToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_WORD_ADDRESS = 0x%8lx\n",
status
) );
break;
}
case TAG_DOUBLE_ADDRESS: {
status = PnpiBiosAddressDoubleToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_DOUBLE_ADDRESS = 0x%8lx\n",
status
) );
break;
}
case TAG_QUAD_ADDRESS: {
status = PnpiBiosAddressQuadToIoDescriptor(
buffer,
Array,
ArrayIndex,
Flags
);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: TAG_QUAD_ADDRESS = 0x%8lx\n",
status
) );
break;
}
case TAG_VENDOR:
case TAG_VENDOR_LONG:{
//
// Ignore this tag. Skip over it.
//
VendorTagCount++;
status = STATUS_SUCCESS;
break;
}
default: {
//
// Unknown tag. Skip it
//
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpBiosResourceToNtResources: TAG_UNKNOWN(tagName:"
" 0x%2lx)\n",
tagName ) );
break;
}
} // switch
//
// Did we fail?
//
if (!NT_SUCCESS(status)) {
break;
}
//
// Move to the next descriptor
//
buffer += increment;
tagName = *buffer;
}
//
// This is a special case check for cases where a vendor has just a
// Vendor short or vendor long defined in the _CRS. In this case we
// dont need to allocate any resources and bail ...
//
if (NT_SUCCESS(status) && (ResourceCount) && (VendorTagCount == ResourceCount)) {
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: This _CRS contains vendor defined tags only. No resources will be allocated.\n"
) );
//
// Clean up any allocated memory and return
//
PnpiClearAllocatedMemory( Array, ArraySize );
*List = NULL;
return status;
}
//
// At this point, if everything is okay, we should be looking at the end tag
// If not, we will have a failed status value to account for it...
//
if (!NT_SUCCESS(status)) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpBiosResourcesToNtResources: Failed on Tag - %d Status %#08lx\n",
tagName, status
) );
//
// Clean up any allocated memory and return
//
PnpiClearAllocatedMemory( Array, ArraySize );
return status;
}
//
// Now, we must figure out how many bytes to allocate for the lists...
// We can start out by determining the size of just the REQUIREMENT_LIST
//
size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST);
//
// How much many common resources are there?
//
if (Array[0] != NULL) {
size2 = Array[0]->Count;
} else {
size2 = 0;
}
//
// This is tricky. The first array is the list of resources that are
// common to *all* lists, so we don't begin by counting it. Rather, we
// figure out how much the other lists will take up
//
for (ArrayIndex = 1; ArrayIndex <= ArrayAlternateIndex; ArrayIndex++) {
if (Array[ArrayIndex] == NULL) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpBiosResourcesToNtResources: Bad List at Array[%d]\n",
ArrayIndex
) );
PnpiClearAllocatedMemory( Array, ArraySize );
*List = NULL;
return STATUS_UNSUCCESSFUL;
}
//
// Just to make sure that we don't get tricked into adding an alternate list
// if we do not need to...
//
if ( (Array[ArrayIndex])->Count == 0) {
continue;
}
//
// How much space does the current Resource List take?
//
size += sizeof(IO_RESOURCE_LIST) +
( (Array[ArrayIndex])->Count - 1 + size2) * sizeof(IO_RESOURCE_DESCRIPTOR);
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: Index %d Size %#08lx\n",
ArrayIndex, size
) );
} // for
//
// This is to account for the case where there are no dependent resources...
//
if (ArrayAlternateIndex == 0) {
if (Array[0] == NULL || Array[0]->Count == 0) {
ACPIPrint( (
ACPI_PRINT_WARNING,
"PnpBiosResourcesToNtResources: No Resources to Report\n"
) );
PnpiClearAllocatedMemory( Array, ArraySize );
*List = NULL;
return STATUS_UNSUCCESSFUL;
}
size += ( (Array[0])->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) +
sizeof(IO_RESOURCE_LIST);
}
//
// This is a redundant check. If we don't have at least enough information
// to create a single list, then we should not be returning anything. Period.
//
if (size < sizeof(IO_RESOURCE_REQUIREMENTS_LIST) ) {
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpBiosResourcesToNtResources: Resources smaller than a List\n"
) );
PnpiClearAllocatedMemory( Array, ArraySize );
*List = NULL;
return STATUS_UNSUCCESSFUL;
}
//
// Allocate the required amount of space
//
(*List) = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourceToNtResources: ResourceRequirementsList = %#08lx (%#08lx)\n",
(*List), size ) );
if (*List == NULL) {
//
// Oops...
//
ACPIPrint( (
ACPI_PRINT_CRITICAL,
"PnpBiosResourceToNtResources: Could not allocate memory for "
"ResourceRequirementList\n" ) );
//
// Clean up any allocated memory and return
//
PnpiClearAllocatedMemory( Array, ArraySize );
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( (*List), size );
//
// Find the first place to store the information
//
(*List)->InterfaceType = PNPBus;
(*List)->BusNumber = 0;
(*List)->ListSize = size;
buffer = (PUCHAR) &( (*List)->List[0]);
for (ArrayIndex = 1; ArrayIndex <= ArrayAlternateIndex; ArrayIndex++) {
//
// Just to make sure that we don't get tricked into adding an alternate list
// if we do not need to...
//
if ( (Array[ArrayIndex])->Count == 0) {
continue;
}
//
// How much space does the current Resource List take?
//
size = ( ( (Array[ArrayIndex])->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) +
sizeof(IO_RESOURCE_LIST) );
//
// This is tricky. Using the sideeffect of if I upgrade the count field
// in the dependent resource descriptor, then when I copy it over, it will
// be correct, I avoid issues with trying to message with pointers at a
// later point in time.
//
(Array[ArrayIndex])->Count += size2;
ACPIPrint( (
ACPI_PRINT_RESOURCES_2,
"PnpBiosResourcesToNtResources: %d@%#08lx Size %#04lx Items %#04x\n",
ArrayIndex, buffer, size, (Array[ArrayIndex])->Count
) );
//
// Copy the resources
//
RtlCopyMemory(buffer, Array[ArrayIndex], size );
buffer += size;
//
// Now we account for the common resources
//
if (size2) {
RtlCopyMemory(
buffer,
&( (Array[0])->Descriptors[0]),
size2 * sizeof(IO_RESOURCE_DESCRIPTOR)
);
buffer += (size2 * sizeof(IO_RESOURCE_DESCRIPTOR));
}
//
// Update the number of alternate lists in the ResourceRequirement List
//
(*List)->AlternativeLists += 1;
}
//
// This check is required because we might just have a common list, with
// no dependent resources...
//
if (ArrayAlternateIndex == 0) {
ASSERT( size2 != 0 );
size = (size2 - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) + sizeof(IO_RESOURCE_LIST);
RtlCopyMemory(buffer,Array[0],size);
(*List)->AlternativeLists += 1;
}
//
// Clean up the copies
//
PnpiClearAllocatedMemory( Array, ArraySize );
return STATUS_SUCCESS;
}
NTSTATUS
PnpIoResourceListToCmResourceList(
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList,
IN OUT PCM_RESOURCE_LIST *CmList
)
/*++
Routine Description:
This routine takes an IO_RESOURCE_REQUIREMENTS_LIST and generates a
CM_RESOURCE_LIST
Arguments:
IoList - The list to convert
CmList - Points to pointer of where to store the new list. The caller is
responsible for freeing this
Return Value:
NTSTATUS
--*/
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
PCM_PARTIAL_RESOURCE_LIST cmPartialList;
PCM_RESOURCE_LIST cmList;
PIO_RESOURCE_DESCRIPTOR ioDesc;
PIO_RESOURCE_LIST ioResList;
ULONG size;
ULONG count;
PAGED_CODE();
*CmList = NULL;
//
// As a trivial check, if there are no lists, than we can simply return
//
if (IoList == NULL || IoList->List == NULL || IoList->List[0].Count == 0) {
return STATUS_INVALID_DEVICE_REQUEST;
}
//
// The first step is to allocate the correct number of bytes for the CmList. The
// first simplifying assumptions that can be me is that the IoList will not have
// more than one alternative.
//
size = (IoList->List[0].Count - 1) * sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ) +
sizeof( CM_RESOURCE_LIST );
//
// Now, allocate this block of memory
//
cmList = ExAllocatePoolWithTag( PagedPool, size, ACPI_RESOURCE_POOLTAG );
if (cmList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( cmList, size );
//
// Setup the initial values for the CmList
//
ioResList = &(IoList->List[0]);
cmList->Count = 1;
cmList->List[0].InterfaceType = IoList->InterfaceType;
cmList->List[0].BusNumber = IoList->BusNumber;
cmPartialList = &(cmList->List[0].PartialResourceList);
cmPartialList->Version = 1;
cmPartialList->Revision = 1;
cmPartialList->Count = ioResList->Count;
for (count = 0; count < ioResList->Count; count++) {
//
// Grab the current CmDescriptor and IoDescriptor
//
cmDesc = &(cmPartialList->PartialDescriptors[count]);
ioDesc = &(ioResList->Descriptors[count]);
//
// Now, copy the information from one descriptor to another
//
cmDesc->Type = ioDesc->Type;
cmDesc->ShareDisposition = ioDesc->ShareDisposition;
cmDesc->Flags = ioDesc->Flags;
switch (cmDesc->Type) {
case CmResourceTypeBusNumber:
cmDesc->u.BusNumber.Start = ioDesc->u.BusNumber.MinBusNumber;
cmDesc->u.BusNumber.Length = ioDesc->u.BusNumber.Length;
break;
case CmResourceTypePort:
cmDesc->u.Port.Length = ioDesc->u.Port.Length;
cmDesc->u.Port.Start = ioDesc->u.Port.MinimumAddress;
break;
case CmResourceTypeInterrupt:
cmDesc->u.Interrupt.Level =
cmDesc->u.Interrupt.Vector = ioDesc->u.Interrupt.MinimumVector;
cmDesc->u.Interrupt.Affinity = (ULONG)-1;
break;
case CmResourceTypeMemory:
cmDesc->u.Memory.Length = ioDesc->u.Memory.Length;
cmDesc->u.Memory.Start = ioDesc->u.Memory.MinimumAddress;
break;
case CmResourceTypeDma:
cmDesc->u.Dma.Channel = ioDesc->u.Dma.MinimumChannel;
cmDesc->u.Dma.Port = 0;
break;
default:
case CmResourceTypeDevicePrivate:
cmDesc->u.DevicePrivate.Data[0] = ioDesc->u.DevicePrivate.Data[0];
cmDesc->u.DevicePrivate.Data[1] = ioDesc->u.DevicePrivate.Data[1];
cmDesc->u.DevicePrivate.Data[2] = ioDesc->u.DevicePrivate.Data[2];
break;
}
}
//
// Let the caller know he has a good list
//
*CmList = cmList;
return STATUS_SUCCESS;
}
NTSTATUS
PnpCmResourceListToIoResourceList(
IN PCM_RESOURCE_LIST CmList,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoList
)
/*++
Routine Description:
This routine generates an IO_RESOURCE_REQUIREMENTS_LIST and from a
CM_RESOURCE_LIST
Arguments:
CmList - The list to convert
IoList - Points to pointer of where to store the new list. The caller is
responsible for freeing this
Return Value:
NTSTATUS
--*/
{
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
PCM_PARTIAL_RESOURCE_LIST cmPartialList;
PIO_RESOURCE_DESCRIPTOR ioDesc;
PIO_RESOURCE_LIST ioResList;
PIO_RESOURCE_REQUIREMENTS_LIST ioList;
ULONG size;
ULONG count;
PAGED_CODE();
*IoList = NULL;
//
// As a trivial check, if there are no lists, than we can simply return
//
if (CmList == NULL || CmList->List == NULL ||
CmList->List[0].PartialResourceList.Count == 0) {
return STATUS_INVALID_DEVICE_REQUEST;
}
//
// Grab the partial list to make walking it easier
//
cmPartialList = &(CmList->List[0].PartialResourceList);
//
// How much space do we need for the IO list?
//
size = (cmPartialList->Count - 1) * sizeof( IO_RESOURCE_DESCRIPTOR ) +
sizeof( IO_RESOURCE_REQUIREMENTS_LIST );
//
// Now, allocate this block of memory
//
ioList = ExAllocatePoolWithTag( NonPagedPool, size, ACPI_RESOURCE_POOLTAG );
if (ioList == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( ioList, size );
//
// Setup the initial values for the IoList
//
ioList->ListSize = size;
ioList->AlternativeLists = 1;
ioList->InterfaceType = CmList->List[0].InterfaceType;
ioList->BusNumber = CmList->List[0].BusNumber;
//
// Setup the initialize value for the ioResList
//
ioResList = &(ioList->List[0]);
ioResList->Count = cmPartialList->Count;
ioResList->Version = cmPartialList->Version;
ioResList->Revision = cmPartialList->Revision;
//
// Loop for all the elements in the partial list
//
for (count = 0; count < ioResList->Count; count++) {
//
// Grab the current CmDescriptor and IoDescriptor
//
cmDesc = &(cmPartialList->PartialDescriptors[count]);
ioDesc = &(ioResList->Descriptors[count]);
//
// Now, copy the information from one descriptor to another
//
ioDesc->Type = cmDesc->Type;
ioDesc->ShareDisposition = cmDesc->ShareDisposition;
ioDesc->Flags = cmDesc->Flags;
switch (cmDesc->Type) {
case CmResourceTypeMemory:
case CmResourceTypePort:
ioDesc->u.Port.Length = cmDesc->u.Port.Length;
ioDesc->u.Port.MinimumAddress = cmDesc->u.Port.Start;
ioDesc->u.Port.MaximumAddress = cmDesc->u.Port.Start;
ioDesc->u.Port.MaximumAddress.LowPart += cmDesc->u.Port.Length - 1;
ioDesc->u.Port.Alignment = 1;
break;
case CmResourceTypeInterrupt:
ioDesc->u.Interrupt.MinimumVector = cmDesc->u.Interrupt.Vector;
ioDesc->u.Interrupt.MaximumVector = cmDesc->u.Interrupt.Vector;
break;
case CmResourceTypeDma:
ioDesc->u.Dma.MinimumChannel = cmDesc->u.Dma.Channel;
ioDesc->u.Dma.MaximumChannel = cmDesc->u.Dma.Channel;
break;
case CmResourceTypeBusNumber:
ioDesc->u.BusNumber.MinBusNumber = cmDesc->u.BusNumber.Start;
ioDesc->u.BusNumber.MaxBusNumber = cmDesc->u.BusNumber.Length +
cmDesc->u.BusNumber.Start;
ioDesc->u.BusNumber.Length = cmDesc->u.BusNumber.Length;
break;
default:
case CmResourceTypeDevicePrivate:
ioDesc->u.DevicePrivate.Data[0] = cmDesc->u.DevicePrivate.Data[0];
ioDesc->u.DevicePrivate.Data[1] = cmDesc->u.DevicePrivate.Data[1];
ioDesc->u.DevicePrivate.Data[2] = cmDesc->u.DevicePrivate.Data[2];
break;
}
}
*IoList = ioList;
return STATUS_SUCCESS;
}