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
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;
|
|
}
|