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