Message ID | 1461242050-19663-1-git-send-email-alex.hung@canonical.com |
---|---|
State | Accepted |
Headers | show |
On 21/04/16 13:34, Alex Hung wrote: > Signed-off-by: Alex Hung <alex.hung@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/einj/einj.c | 167 ++++++++++++++++++++++++++++++++++++++++++++ > src/lib/include/fwts_acpi.h | 11 +++ > 3 files changed, 179 insertions(+) > create mode 100644 src/acpi/einj/einj.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index bf415fd..3369568 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -53,6 +53,7 @@ fwts_SOURCES = main.c \ > acpi/dbg2/dbg2.c \ > acpi/dmar/dmar.c \ > acpi/ecdt/ecdt.c \ > + acpi/einj/einj.c \ > acpi/erst/erst.c \ > acpi/facs/facs.c \ > acpi/fadt/fadt.c \ > diff --git a/src/acpi/einj/einj.c b/src/acpi/einj/einj.c > new file mode 100644 > index 0000000..4efd71a > --- /dev/null > +++ b/src/acpi/einj/einj.c > @@ -0,0 +1,167 @@ > +/* > + * Copyright (C) 2016 Canonical > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > +#include "fwts.h" > +#include "fwts_acpi_object_eval.h" > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > +#include <ctype.h> > + > +static fwts_acpi_table_info *table; > + > +static int einj_init(fwts_framework *fw) > +{ > + if (fwts_acpi_find_table(fw, "EINJ", 0, &table) != FWTS_OK) { > + fwts_log_error(fw, "Cannot read ACPI tables."); > + return FWTS_ERROR; > + } > + if (table == NULL || (table && table->length == 0)) { > + fwts_log_error(fw, "ACPI EINJ table does not exist, skipping test"); > + return FWTS_SKIP; > + } > + return FWTS_OK; > +} > + > +/* > + * EINJ Error Injection Table > + */ > +static int einj_test1(fwts_framework *fw) > +{ > + fwts_acpi_table_einj *einj = (fwts_acpi_table_einj *) table->data; > + fwts_acpi_serialization_instruction_entries *entry; > + uint32_t reserved, i; > + bool passed = true; > + > + reserved = einj->reserved[0] + (einj->reserved[1] << 4) + > + (einj->reserved[2] << 8); > + > + fwts_log_info_verbatum(fw, "EINJ Error Injection Table:"); > + fwts_log_info_verbatum(fw, " Injection Header Size: 0x%8.8" PRIx32, > + einj->header_size); > + fwts_log_info_verbatum(fw, " Injection Flags: 0x%8.8" PRIx32, > + einj->flags); > + fwts_log_info_verbatum(fw, " Reserved: 0x%8.8" PRIx32, > + reserved); > + fwts_log_info_verbatum(fw, " Injection Entry Count: 0x%8.8" PRIx32, > + einj->count); > + > + if (einj->flags) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJFlagNonZero", > + "EINJ Injection Flags field must be zero, got 0x%" > + PRIx8 " instead", einj->flags); > + passed = false; > + } > + > + if (reserved) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJReservedNonZero", > + "EINJ Reserved field must be zero, got 0x%" > + PRIx32 " instead", reserved); > + passed = false; > + } > + > + fwts_log_nl(fw); > + > + entry = (fwts_acpi_serialization_instruction_entries *) > + (char *) einj + 48; > + for (i = 0; i < einj->count; i++, entry++) { > + fwts_acpi_gas gas = entry->register_region; > + fwts_log_info_verbatum(fw, " Injection Instruction Entry %2.2" > + PRId8, i); > + fwts_log_info_verbatum(fw, " Injection Action : 0x%2.2" > + PRIx8, entry->serialization_action); > + fwts_log_info_verbatum(fw, " Instruction : 0x%2.2" > + PRIx8, entry->instruction); > + fwts_log_info_verbatum(fw, " Flags : 0x%2.2" > + PRIx8, entry->flags); > + fwts_log_info_verbatum(fw, " Reserved : 0x%2.2" > + PRIx8, entry->reserved); > + fwts_log_info_verbatum(fw, " Address Space ID : 0x%2.2" > + PRIx8, gas.address_space_id); > + fwts_log_info_verbatum(fw, " Register Bit Width : 0x%2.2" > + PRIx8, gas.register_bit_width); > + fwts_log_info_verbatum(fw, " Register Bit Offset : 0x%2.2" > + PRIx8, gas.register_bit_offset); > + fwts_log_info_verbatum(fw, " Access Size : 0x%2.2" > + PRIx8, gas.access_width); > + fwts_log_info_verbatum(fw, " Address : 0x%16.16" > + PRIx64, gas.address); > + fwts_log_info_verbatum(fw, " Value : 0x%16.16" > + PRIx64, entry->value); > + fwts_log_info_verbatum(fw, " Mask : 0x%16.16" > + PRIx64, entry->mask); > + > + if (entry->serialization_action > 0x8 && > + entry->serialization_action != 0xFF) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadInjectionAction", > + "EINJ Injection Action must be within 0~8 " > + "or 0xFF got 0x%" PRIx8 " instead", > + entry->serialization_action); > + passed = false; > + } > + > + if (entry->instruction > 0x4) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadInstruction", > + "EINJ Instruction must be within 0~4, got " > + "0x%" PRIx8 " instead", entry->instruction); > + passed = false; > + } > + > + if (entry->reserved != 0) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJReservedNonZero", > + "EINJ Reserved field must be zero, got 0x%" > + PRIx32 " instead", entry->reserved); > + passed = false; > + } > + > + if (gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && > + gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadSpaceId", > + "EINJ Address_Space_ID must be within 0 or " > + "1, got 0x%" PRIx8 " instead", > + gas.address_space_id); > + passed = false; > + } > + > + fwts_log_nl(fw); > + } > + > + if (passed) > + fwts_passed(fw, "No issues found in EINJ table."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test einj_tests[] = { > + { einj_test1, "EINJ Error Injection Table test." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops einj_ops = { > + .description = "EINJ Error Injection Table test.", > + .init = einj_init, > + .minor_tests = einj_tests > +}; > + > +FWTS_REGISTER("einj", &einj_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | > + FWTS_FLAG_TEST_ACPI) > diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h > index 666b6cd..8b50517 100644 > --- a/src/lib/include/fwts_acpi.h > +++ b/src/lib/include/fwts_acpi.h > @@ -445,6 +445,17 @@ typedef struct { > fwts_acpi_serialization_instruction_entries entries[0]; > } __attribute__ ((packed)) fwts_acpi_table_erst; > > +/* > + * ACPI EINJ (Error Injection Table), 18.6 > + */ > +typedef struct { > + fwts_acpi_table_header header; > + uint32_t header_size; > + uint8_t flags; > + uint8_t reserved[3]; > + uint32_t count; > + fwts_acpi_serialization_instruction_entries entries[0]; > +} __attribute__ ((packed)) fwts_acpi_table_einj; > > /* > * ACPI MADT (Multiple APIC Description Table), 5.2.12 > Acked-by: Colin Ian King <colin.king@canonical.com>
On 04/21/2016 08:34 PM, Alex Hung wrote: > Signed-off-by: Alex Hung <alex.hung@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/einj/einj.c | 167 ++++++++++++++++++++++++++++++++++++++++++++ > src/lib/include/fwts_acpi.h | 11 +++ > 3 files changed, 179 insertions(+) > create mode 100644 src/acpi/einj/einj.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index bf415fd..3369568 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -53,6 +53,7 @@ fwts_SOURCES = main.c \ > acpi/dbg2/dbg2.c \ > acpi/dmar/dmar.c \ > acpi/ecdt/ecdt.c \ > + acpi/einj/einj.c \ > acpi/erst/erst.c \ > acpi/facs/facs.c \ > acpi/fadt/fadt.c \ > diff --git a/src/acpi/einj/einj.c b/src/acpi/einj/einj.c > new file mode 100644 > index 0000000..4efd71a > --- /dev/null > +++ b/src/acpi/einj/einj.c > @@ -0,0 +1,167 @@ > +/* > + * Copyright (C) 2016 Canonical > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version 2 > + * of the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > +#include "fwts.h" > +#include "fwts_acpi_object_eval.h" > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > +#include <ctype.h> > + > +static fwts_acpi_table_info *table; > + > +static int einj_init(fwts_framework *fw) > +{ > + if (fwts_acpi_find_table(fw, "EINJ", 0, &table) != FWTS_OK) { > + fwts_log_error(fw, "Cannot read ACPI tables."); > + return FWTS_ERROR; > + } > + if (table == NULL || (table && table->length == 0)) { > + fwts_log_error(fw, "ACPI EINJ table does not exist, skipping test"); > + return FWTS_SKIP; > + } > + return FWTS_OK; > +} > + > +/* > + * EINJ Error Injection Table > + */ > +static int einj_test1(fwts_framework *fw) > +{ > + fwts_acpi_table_einj *einj = (fwts_acpi_table_einj *) table->data; > + fwts_acpi_serialization_instruction_entries *entry; > + uint32_t reserved, i; > + bool passed = true; > + > + reserved = einj->reserved[0] + (einj->reserved[1] << 4) + > + (einj->reserved[2] << 8); > + > + fwts_log_info_verbatum(fw, "EINJ Error Injection Table:"); > + fwts_log_info_verbatum(fw, " Injection Header Size: 0x%8.8" PRIx32, > + einj->header_size); > + fwts_log_info_verbatum(fw, " Injection Flags: 0x%8.8" PRIx32, > + einj->flags); > + fwts_log_info_verbatum(fw, " Reserved: 0x%8.8" PRIx32, > + reserved); > + fwts_log_info_verbatum(fw, " Injection Entry Count: 0x%8.8" PRIx32, > + einj->count); > + > + if (einj->flags) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJFlagNonZero", > + "EINJ Injection Flags field must be zero, got 0x%" > + PRIx8 " instead", einj->flags); > + passed = false; > + } > + > + if (reserved) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJReservedNonZero", > + "EINJ Reserved field must be zero, got 0x%" > + PRIx32 " instead", reserved); > + passed = false; > + } > + > + fwts_log_nl(fw); > + > + entry = (fwts_acpi_serialization_instruction_entries *) > + (char *) einj + 48; > + for (i = 0; i < einj->count; i++, entry++) { > + fwts_acpi_gas gas = entry->register_region; > + fwts_log_info_verbatum(fw, " Injection Instruction Entry %2.2" > + PRId8, i); > + fwts_log_info_verbatum(fw, " Injection Action : 0x%2.2" > + PRIx8, entry->serialization_action); > + fwts_log_info_verbatum(fw, " Instruction : 0x%2.2" > + PRIx8, entry->instruction); > + fwts_log_info_verbatum(fw, " Flags : 0x%2.2" > + PRIx8, entry->flags); > + fwts_log_info_verbatum(fw, " Reserved : 0x%2.2" > + PRIx8, entry->reserved); > + fwts_log_info_verbatum(fw, " Address Space ID : 0x%2.2" > + PRIx8, gas.address_space_id); > + fwts_log_info_verbatum(fw, " Register Bit Width : 0x%2.2" > + PRIx8, gas.register_bit_width); > + fwts_log_info_verbatum(fw, " Register Bit Offset : 0x%2.2" > + PRIx8, gas.register_bit_offset); > + fwts_log_info_verbatum(fw, " Access Size : 0x%2.2" > + PRIx8, gas.access_width); > + fwts_log_info_verbatum(fw, " Address : 0x%16.16" > + PRIx64, gas.address); > + fwts_log_info_verbatum(fw, " Value : 0x%16.16" > + PRIx64, entry->value); > + fwts_log_info_verbatum(fw, " Mask : 0x%16.16" > + PRIx64, entry->mask); > + > + if (entry->serialization_action > 0x8 && > + entry->serialization_action != 0xFF) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadInjectionAction", > + "EINJ Injection Action must be within 0~8 " > + "or 0xFF got 0x%" PRIx8 " instead", > + entry->serialization_action); > + passed = false; > + } > + > + if (entry->instruction > 0x4) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadInstruction", > + "EINJ Instruction must be within 0~4, got " > + "0x%" PRIx8 " instead", entry->instruction); > + passed = false; > + } > + > + if (entry->reserved != 0) { > + fwts_failed(fw, LOG_LEVEL_LOW, > + "EINJReservedNonZero", > + "EINJ Reserved field must be zero, got 0x%" > + PRIx32 " instead", entry->reserved); > + passed = false; > + } > + > + if (gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && > + gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "EINJBadSpaceId", > + "EINJ Address_Space_ID must be within 0 or " > + "1, got 0x%" PRIx8 " instead", > + gas.address_space_id); > + passed = false; > + } > + > + fwts_log_nl(fw); > + } > + > + if (passed) > + fwts_passed(fw, "No issues found in EINJ table."); > + > + return FWTS_OK; > +} > + > +static fwts_framework_minor_test einj_tests[] = { > + { einj_test1, "EINJ Error Injection Table test." }, > + { NULL, NULL } > +}; > + > +static fwts_framework_ops einj_ops = { > + .description = "EINJ Error Injection Table test.", > + .init = einj_init, > + .minor_tests = einj_tests > +}; > + > +FWTS_REGISTER("einj", &einj_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | > + FWTS_FLAG_TEST_ACPI) > diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h > index 666b6cd..8b50517 100644 > --- a/src/lib/include/fwts_acpi.h > +++ b/src/lib/include/fwts_acpi.h > @@ -445,6 +445,17 @@ typedef struct { > fwts_acpi_serialization_instruction_entries entries[0]; > } __attribute__ ((packed)) fwts_acpi_table_erst; > > +/* > + * ACPI EINJ (Error Injection Table), 18.6 > + */ > +typedef struct { > + fwts_acpi_table_header header; > + uint32_t header_size; > + uint8_t flags; > + uint8_t reserved[3]; > + uint32_t count; > + fwts_acpi_serialization_instruction_entries entries[0]; > +} __attribute__ ((packed)) fwts_acpi_table_einj; > > /* > * ACPI MADT (Multiple APIC Description Table), 5.2.12 Acked-by: Ivan Hu <ivan.hu@canonical.com>
diff --git a/src/Makefile.am b/src/Makefile.am index bf415fd..3369568 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,6 +53,7 @@ fwts_SOURCES = main.c \ acpi/dbg2/dbg2.c \ acpi/dmar/dmar.c \ acpi/ecdt/ecdt.c \ + acpi/einj/einj.c \ acpi/erst/erst.c \ acpi/facs/facs.c \ acpi/fadt/fadt.c \ diff --git a/src/acpi/einj/einj.c b/src/acpi/einj/einj.c new file mode 100644 index 0000000..4efd71a --- /dev/null +++ b/src/acpi/einj/einj.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include "fwts.h" +#include "fwts_acpi_object_eval.h" + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <string.h> +#include <ctype.h> + +static fwts_acpi_table_info *table; + +static int einj_init(fwts_framework *fw) +{ + if (fwts_acpi_find_table(fw, "EINJ", 0, &table) != FWTS_OK) { + fwts_log_error(fw, "Cannot read ACPI tables."); + return FWTS_ERROR; + } + if (table == NULL || (table && table->length == 0)) { + fwts_log_error(fw, "ACPI EINJ table does not exist, skipping test"); + return FWTS_SKIP; + } + return FWTS_OK; +} + +/* + * EINJ Error Injection Table + */ +static int einj_test1(fwts_framework *fw) +{ + fwts_acpi_table_einj *einj = (fwts_acpi_table_einj *) table->data; + fwts_acpi_serialization_instruction_entries *entry; + uint32_t reserved, i; + bool passed = true; + + reserved = einj->reserved[0] + (einj->reserved[1] << 4) + + (einj->reserved[2] << 8); + + fwts_log_info_verbatum(fw, "EINJ Error Injection Table:"); + fwts_log_info_verbatum(fw, " Injection Header Size: 0x%8.8" PRIx32, + einj->header_size); + fwts_log_info_verbatum(fw, " Injection Flags: 0x%8.8" PRIx32, + einj->flags); + fwts_log_info_verbatum(fw, " Reserved: 0x%8.8" PRIx32, + reserved); + fwts_log_info_verbatum(fw, " Injection Entry Count: 0x%8.8" PRIx32, + einj->count); + + if (einj->flags) { + fwts_failed(fw, LOG_LEVEL_LOW, + "EINJFlagNonZero", + "EINJ Injection Flags field must be zero, got 0x%" + PRIx8 " instead", einj->flags); + passed = false; + } + + if (reserved) { + fwts_failed(fw, LOG_LEVEL_LOW, + "EINJReservedNonZero", + "EINJ Reserved field must be zero, got 0x%" + PRIx32 " instead", reserved); + passed = false; + } + + fwts_log_nl(fw); + + entry = (fwts_acpi_serialization_instruction_entries *) + (char *) einj + 48; + for (i = 0; i < einj->count; i++, entry++) { + fwts_acpi_gas gas = entry->register_region; + fwts_log_info_verbatum(fw, " Injection Instruction Entry %2.2" + PRId8, i); + fwts_log_info_verbatum(fw, " Injection Action : 0x%2.2" + PRIx8, entry->serialization_action); + fwts_log_info_verbatum(fw, " Instruction : 0x%2.2" + PRIx8, entry->instruction); + fwts_log_info_verbatum(fw, " Flags : 0x%2.2" + PRIx8, entry->flags); + fwts_log_info_verbatum(fw, " Reserved : 0x%2.2" + PRIx8, entry->reserved); + fwts_log_info_verbatum(fw, " Address Space ID : 0x%2.2" + PRIx8, gas.address_space_id); + fwts_log_info_verbatum(fw, " Register Bit Width : 0x%2.2" + PRIx8, gas.register_bit_width); + fwts_log_info_verbatum(fw, " Register Bit Offset : 0x%2.2" + PRIx8, gas.register_bit_offset); + fwts_log_info_verbatum(fw, " Access Size : 0x%2.2" + PRIx8, gas.access_width); + fwts_log_info_verbatum(fw, " Address : 0x%16.16" + PRIx64, gas.address); + fwts_log_info_verbatum(fw, " Value : 0x%16.16" + PRIx64, entry->value); + fwts_log_info_verbatum(fw, " Mask : 0x%16.16" + PRIx64, entry->mask); + + if (entry->serialization_action > 0x8 && + entry->serialization_action != 0xFF) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "EINJBadInjectionAction", + "EINJ Injection Action must be within 0~8 " + "or 0xFF got 0x%" PRIx8 " instead", + entry->serialization_action); + passed = false; + } + + if (entry->instruction > 0x4) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "EINJBadInstruction", + "EINJ Instruction must be within 0~4, got " + "0x%" PRIx8 " instead", entry->instruction); + passed = false; + } + + if (entry->reserved != 0) { + fwts_failed(fw, LOG_LEVEL_LOW, + "EINJReservedNonZero", + "EINJ Reserved field must be zero, got 0x%" + PRIx32 " instead", entry->reserved); + passed = false; + } + + if (gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && + gas.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "EINJBadSpaceId", + "EINJ Address_Space_ID must be within 0 or " + "1, got 0x%" PRIx8 " instead", + gas.address_space_id); + passed = false; + } + + fwts_log_nl(fw); + } + + if (passed) + fwts_passed(fw, "No issues found in EINJ table."); + + return FWTS_OK; +} + +static fwts_framework_minor_test einj_tests[] = { + { einj_test1, "EINJ Error Injection Table test." }, + { NULL, NULL } +}; + +static fwts_framework_ops einj_ops = { + .description = "EINJ Error Injection Table test.", + .init = einj_init, + .minor_tests = einj_tests +}; + +FWTS_REGISTER("einj", &einj_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | + FWTS_FLAG_TEST_ACPI) diff --git a/src/lib/include/fwts_acpi.h b/src/lib/include/fwts_acpi.h index 666b6cd..8b50517 100644 --- a/src/lib/include/fwts_acpi.h +++ b/src/lib/include/fwts_acpi.h @@ -445,6 +445,17 @@ typedef struct { fwts_acpi_serialization_instruction_entries entries[0]; } __attribute__ ((packed)) fwts_acpi_table_erst; +/* + * ACPI EINJ (Error Injection Table), 18.6 + */ +typedef struct { + fwts_acpi_table_header header; + uint32_t header_size; + uint8_t flags; + uint8_t reserved[3]; + uint32_t count; + fwts_acpi_serialization_instruction_entries entries[0]; +} __attribute__ ((packed)) fwts_acpi_table_einj; /* * ACPI MADT (Multiple APIC Description Table), 5.2.12
Signed-off-by: Alex Hung <alex.hung@canonical.com> --- src/Makefile.am | 1 + src/acpi/einj/einj.c | 167 ++++++++++++++++++++++++++++++++++++++++++++ src/lib/include/fwts_acpi.h | 11 +++ 3 files changed, 179 insertions(+) create mode 100644 src/acpi/einj/einj.c