1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "resources.h"
6 
resource_parse_memory(ACPI_RESOURCE * res,resource_memory_t * out)7 zx_status_t resource_parse_memory(ACPI_RESOURCE* res, resource_memory_t* out) {
8     switch (res->Type) {
9         case ACPI_RESOURCE_TYPE_MEMORY24: {
10             ACPI_RESOURCE_MEMORY24* m24 = &res->Data.Memory24;
11             out->writeable = !m24->WriteProtect;
12             out->minimum = (uint32_t)m24->Minimum << 8;
13             out->maximum = (uint32_t)m24->Maximum << 8;
14             out->alignment = m24->Alignment ? m24->Alignment : 1U<<16;
15             out->address_length = (uint32_t)m24->AddressLength << 8;
16             break;
17         }
18         case ACPI_RESOURCE_TYPE_MEMORY32: {
19             ACPI_RESOURCE_MEMORY32* m32 = &res->Data.Memory32;
20             out->writeable = !m32->WriteProtect;
21             out->minimum = m32->Minimum;
22             out->maximum = m32->Maximum;
23             out->alignment = m32->Alignment;
24             out->address_length = m32->AddressLength;
25             break;
26         }
27         case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: {
28             ACPI_RESOURCE_FIXED_MEMORY32* m32 = &res->Data.FixedMemory32;
29             out->writeable = !m32->WriteProtect;
30             out->minimum = m32->Address;
31             out->maximum = m32->Address;
32             out->alignment = 1;
33             out->address_length = m32->AddressLength;
34             break;
35         }
36         default: return ZX_ERR_INVALID_ARGS;
37     }
38 
39     return ZX_OK;
40 }
41 
42 #define EXTRACT_ADDRESS_FIELDS(src, out) do { \
43             (out)->minimum = (src)->Address.Minimum; \
44             (out)->maximum = (src)->Address.Maximum; \
45             (out)->address_length = (src)->Address.AddressLength; \
46             (out)->translation_offset = (src)->Address.TranslationOffset; \
47             (out)->granularity = (src)->Address.Granularity; \
48             (out)->consumed_only = ((src)->ProducerConsumer == ACPI_CONSUMER); \
49             (out)->subtractive_decode = ((src)->Decode == ACPI_SUB_DECODE); \
50             (out)->min_address_fixed = (src)->MinAddressFixed; \
51             (out)->max_address_fixed = (src)->MaxAddressFixed; \
52 } while (0)
53 
resource_parse_address(ACPI_RESOURCE * res,resource_address_t * out)54 zx_status_t resource_parse_address(ACPI_RESOURCE* res, resource_address_t* out) {
55     uint8_t resource_type;
56     switch (res->Type) {
57         case ACPI_RESOURCE_TYPE_ADDRESS16: {
58             ACPI_RESOURCE_ADDRESS16* a16 = &res->Data.Address16;
59             EXTRACT_ADDRESS_FIELDS(a16, out);
60             resource_type = a16->ResourceType;
61             break;
62         }
63         case ACPI_RESOURCE_TYPE_ADDRESS32: {
64             ACPI_RESOURCE_ADDRESS32* a32 = &res->Data.Address32;
65             EXTRACT_ADDRESS_FIELDS(a32, out);
66             resource_type = a32->ResourceType;
67             break;
68         }
69         case ACPI_RESOURCE_TYPE_ADDRESS64: {
70             ACPI_RESOURCE_ADDRESS64* a64 = &res->Data.Address64;
71             EXTRACT_ADDRESS_FIELDS(a64, out);
72             resource_type = a64->ResourceType;
73             break;
74         }
75         case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: {
76             ACPI_RESOURCE_EXTENDED_ADDRESS64* a64 = &res->Data.ExtAddress64;
77             EXTRACT_ADDRESS_FIELDS(a64, out);
78             resource_type = a64->ResourceType;
79             break;
80         }
81         default: return ZX_ERR_INVALID_ARGS;
82     }
83 
84     switch (resource_type) {
85         case ACPI_MEMORY_RANGE: out->resource_type = RESOURCE_ADDRESS_MEMORY; break;
86         case ACPI_IO_RANGE: out->resource_type = RESOURCE_ADDRESS_IO; break;
87         case ACPI_BUS_NUMBER_RANGE: out->resource_type = RESOURCE_ADDRESS_BUS_NUMBER; break;
88         default: out->resource_type = RESOURCE_ADDRESS_UNKNOWN;
89     }
90 
91     return ZX_OK;
92 }
93 
resource_parse_io(ACPI_RESOURCE * res,resource_io_t * out)94 zx_status_t resource_parse_io(ACPI_RESOURCE* res, resource_io_t* out) {
95     switch (res->Type) {
96         case ACPI_RESOURCE_TYPE_IO: {
97             ACPI_RESOURCE_IO* io = &res->Data.Io;
98             out->decodes_full_space = (io->IoDecode == ACPI_DECODE_16);
99             out->alignment = io->Alignment;
100             out->address_length = io->AddressLength;
101             out->minimum = io->Minimum;
102             out->maximum = io->Maximum;
103             break;
104         }
105         case ACPI_RESOURCE_TYPE_FIXED_IO: {
106             ACPI_RESOURCE_FIXED_IO* io = &res->Data.FixedIo;
107             out->decodes_full_space = false;
108             out->alignment = 1;
109             out->address_length = io->AddressLength;
110             out->minimum = io->Address;
111             out->maximum = io->Address;
112             break;
113         }
114         default: return ZX_ERR_INVALID_ARGS;
115     }
116 
117     return ZX_OK;
118 }
119 
resource_parse_irq(ACPI_RESOURCE * res,resource_irq_t * out)120 zx_status_t resource_parse_irq(ACPI_RESOURCE* res, resource_irq_t* out) {
121     switch (res->Type) {
122         case ACPI_RESOURCE_TYPE_IRQ: {
123             ACPI_RESOURCE_IRQ* irq = &res->Data.Irq;
124             out->trigger = irq->Triggering;
125             out->polarity = irq->Polarity;
126             out->sharable = irq->Sharable;
127             out->wake_capable = irq->WakeCapable;
128             out->pin_count = irq->InterruptCount;
129             if (irq->InterruptCount > countof(out->pins)) {
130                 return ZX_ERR_OUT_OF_RANGE;
131             }
132             for (uint8_t i = 0;
133                  (i < irq->InterruptCount) && (i < countof(out->pins)); i++) {
134                 out->pins[i] = irq->Interrupts[i];
135             }
136             break;
137         }
138         case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: {
139             ACPI_RESOURCE_EXTENDED_IRQ* irq = &res->Data.ExtendedIrq;
140             out->trigger = irq->Triggering;
141             out->polarity = irq->Polarity;
142             out->sharable = irq->Sharable;
143             out->wake_capable = irq->WakeCapable;
144             out->pin_count = irq->InterruptCount;
145             if (irq->InterruptCount > countof(out->pins)) {
146                 return ZX_ERR_OUT_OF_RANGE;
147             }
148             for (uint8_t i = 0;
149                  (i < irq->InterruptCount) && (i < countof(out->pins)); i++) {
150                 out->pins[i] = irq->Interrupts[i];
151             }
152             break;
153         }
154         default: return ZX_ERR_INVALID_ARGS;
155     }
156 
157     return ZX_OK;
158 }
159