/*++ 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; }