blob: 6f101fb37618331e872ec88f1fe7007e2c84cb66 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "resources.h"
bool resource_is_memory(ACPI_RESOURCE* res) {
return res->Type == ACPI_RESOURCE_TYPE_MEMORY24 || res->Type == ACPI_RESOURCE_TYPE_MEMORY32 ||
res->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32;
}
bool resource_is_address(ACPI_RESOURCE* res) {
return res->Type == ACPI_RESOURCE_TYPE_ADDRESS16 || res->Type == ACPI_RESOURCE_TYPE_ADDRESS32 ||
res->Type == ACPI_RESOURCE_TYPE_ADDRESS64 ||
res->Type == ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64;
}
bool resource_is_io(ACPI_RESOURCE* res) {
return res->Type == ACPI_RESOURCE_TYPE_IO || res->Type == ACPI_RESOURCE_TYPE_FIXED_IO;
}
bool resource_is_irq(ACPI_RESOURCE* res) {
return res->Type == ACPI_RESOURCE_TYPE_IRQ || res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ;
}
zx_status_t resource_parse_memory(ACPI_RESOURCE* res, resource_memory_t* out) {
switch (res->Type) {
case ACPI_RESOURCE_TYPE_MEMORY24: {
ACPI_RESOURCE_MEMORY24* m24 = &res->Data.Memory24;
out->writeable = !m24->WriteProtect;
out->minimum = (uint32_t)m24->Minimum << 8;
out->maximum = (uint32_t)m24->Maximum << 8;
out->alignment = m24->Alignment ? m24->Alignment : 1U << 16;
out->address_length = (uint32_t)m24->AddressLength << 8;
break;
}
case ACPI_RESOURCE_TYPE_MEMORY32: {
ACPI_RESOURCE_MEMORY32* m32 = &res->Data.Memory32;
out->writeable = !m32->WriteProtect;
out->minimum = m32->Minimum;
out->maximum = m32->Maximum;
out->alignment = m32->Alignment;
out->address_length = m32->AddressLength;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
ACPI_RESOURCE_FIXED_MEMORY32* m32 = &res->Data.FixedMemory32;
out->writeable = !m32->WriteProtect;
out->minimum = m32->Address;
out->maximum = m32->Address;
out->alignment = 1;
out->address_length = m32->AddressLength;
break;
}
default:
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
#define EXTRACT_ADDRESS_FIELDS(src, out) \
do { \
(out)->minimum = (src)->Address.Minimum; \
(out)->maximum = (src)->Address.Maximum; \
(out)->address_length = (src)->Address.AddressLength; \
(out)->translation_offset = (src)->Address.TranslationOffset; \
(out)->granularity = (src)->Address.Granularity; \
(out)->consumed_only = ((src)->ProducerConsumer == ACPI_CONSUMER); \
(out)->subtractive_decode = ((src)->Decode == ACPI_SUB_DECODE); \
(out)->min_address_fixed = (src)->MinAddressFixed; \
(out)->max_address_fixed = (src)->MaxAddressFixed; \
} while (0)
zx_status_t resource_parse_address(ACPI_RESOURCE* res, resource_address_t* out) {
uint8_t resource_type;
switch (res->Type) {
case ACPI_RESOURCE_TYPE_ADDRESS16: {
ACPI_RESOURCE_ADDRESS16* a16 = &res->Data.Address16;
EXTRACT_ADDRESS_FIELDS(a16, out);
resource_type = a16->ResourceType;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS32: {
ACPI_RESOURCE_ADDRESS32* a32 = &res->Data.Address32;
EXTRACT_ADDRESS_FIELDS(a32, out);
resource_type = a32->ResourceType;
break;
}
case ACPI_RESOURCE_TYPE_ADDRESS64: {
ACPI_RESOURCE_ADDRESS64* a64 = &res->Data.Address64;
EXTRACT_ADDRESS_FIELDS(a64, out);
resource_type = a64->ResourceType;
break;
}
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: {
ACPI_RESOURCE_EXTENDED_ADDRESS64* a64 = &res->Data.ExtAddress64;
EXTRACT_ADDRESS_FIELDS(a64, out);
resource_type = a64->ResourceType;
break;
}
default:
return ZX_ERR_INVALID_ARGS;
}
switch (resource_type) {
case ACPI_MEMORY_RANGE:
out->resource_type = RESOURCE_ADDRESS_MEMORY;
break;
case ACPI_IO_RANGE:
out->resource_type = RESOURCE_ADDRESS_IO;
break;
case ACPI_BUS_NUMBER_RANGE:
out->resource_type = RESOURCE_ADDRESS_BUS_NUMBER;
break;
default:
out->resource_type = RESOURCE_ADDRESS_UNKNOWN;
}
return ZX_OK;
}
zx_status_t resource_parse_io(ACPI_RESOURCE* res, resource_io_t* out) {
switch (res->Type) {
case ACPI_RESOURCE_TYPE_IO: {
ACPI_RESOURCE_IO* io = &res->Data.Io;
out->decodes_full_space = (io->IoDecode == ACPI_DECODE_16);
out->alignment = io->Alignment;
out->address_length = io->AddressLength;
out->minimum = io->Minimum;
out->maximum = io->Maximum;
break;
}
case ACPI_RESOURCE_TYPE_FIXED_IO: {
ACPI_RESOURCE_FIXED_IO* io = &res->Data.FixedIo;
out->decodes_full_space = false;
out->alignment = 1;
out->address_length = io->AddressLength;
out->minimum = io->Address;
out->maximum = io->Address;
break;
}
default:
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}
zx_status_t resource_parse_irq(ACPI_RESOURCE* res, resource_irq_t* out) {
switch (res->Type) {
case ACPI_RESOURCE_TYPE_IRQ: {
ACPI_RESOURCE_IRQ* irq = &res->Data.Irq;
out->trigger = irq->Triggering;
out->polarity = irq->Polarity;
out->sharable = irq->Shareable;
out->wake_capable = irq->WakeCapable;
out->pin_count = irq->InterruptCount;
if (irq->InterruptCount > countof(out->pins)) {
return ZX_ERR_OUT_OF_RANGE;
}
for (uint8_t i = 0; (i < irq->InterruptCount) && (i < countof(out->pins)); i++) {
out->pins[i] = irq->Interrupts[i];
}
break;
}
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: {
ACPI_RESOURCE_EXTENDED_IRQ* irq = &res->Data.ExtendedIrq;
out->trigger = irq->Triggering;
out->polarity = irq->Polarity;
out->sharable = irq->Shareable;
out->wake_capable = irq->WakeCapable;
out->pin_count = irq->InterruptCount;
if (irq->InterruptCount > countof(out->pins)) {
return ZX_ERR_OUT_OF_RANGE;
}
for (uint8_t i = 0; (i < irq->InterruptCount) && (i < countof(out->pins)); i++) {
out->pins[i] = irq->Interrupts[i];
}
break;
}
default:
return ZX_ERR_INVALID_ARGS;
}
return ZX_OK;
}