[PATCH 11/12] sbbr/method: Add initial tests to acpi method tests as per sbbr.
Colin Ian King
colin.king at canonical.com
Thu Mar 2 23:57:29 UTC 2017
This is duplication of the fwts method test. What's the justification?
Cut-n-paste duplication makes maintenance really hard work.
On 02/03/17 22:26, Supreeth Venkatesh wrote:
> Server Base Boot Requirements (SBBR) specification is intended for SBSA-
> compliant 64-bit ARMv8 servers.
> It defines the base firmware requirements for out-of-box support of any
> ARM SBSA-compatible Operating System or hypervisor.
> The requirements in this specification are expected to be minimal yet
> complete for booting a multi-core ARMv8 server platform, while leaving
> plenty of room for OEM or ODM innovations and design details.
> For more information, download the SBBR specification here:
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0044b/index.html
>
> This change introduces test cases as per SBBR specification to acpi
> method tests. These test cases may be subset/superset of acpi method
> tests already existing. However, to preserve "sbbr" classification, new
> file is created, even when most of the code is re-used from acpi/method.
>
> Signed-off-by: Supreeth Venkatesh <supreeth.venkatesh at arm.com>
> ---
> src/sbbr/method/method.c | 7333 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 7333 insertions(+)
> create mode 100644 src/sbbr/method/method.c
>
> diff --git a/src/sbbr/method/method.c b/src/sbbr/method/method.c
> new file mode 100644
> index 0000000..3b4dbc3
> --- /dev/null
> +++ b/src/sbbr/method/method.c
> @@ -0,0 +1,7333 @@
> +/*
> + * Copyright (C) 2010-2017 Canonical
> + * Copyright (C) 2017 ARM Ltd
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#include "fwts.h"
> +
> +#if defined(FWTS_HAS_SBBR)
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <signal.h>
> +#include <unistd.h>
> +#include <ctype.h>
> +#include <inttypes.h>
> +#include "fwts_acpi_object_eval.h"
> +
> +/*
> + * ACPI methods + objects used in Linux ACPI driver:
> + *
> + * Name Tested
> + * _ACx Y
> + * _ADR Y
> + * _AEI Y
> + * _ALC Y
> + * _ALI Y
> + * _ALP Y
> + * _ALR Y
> + * _ALT Y
> + * _ALx N
> + * _ART Y
> + * _BBN Y
> + * _BCL Y
> + * _BCM Y
> + * _BCT Y
> + * _BDN Y
> + * _BFS deprecated
> + * _BIF Y
> + * _BIX Y
> + * _BLT N not easily tested
> + * _BMA Y
> + * _BMC Y
> + * _BMD Y
> + * _BMS Y
> + * _BQC Y
> + * _BST Y
> + * _BTH Y
> + * _BTM Y
> + * _BTP Y
> + * _CBA Y
> + * _CCA Y
> + * _CDM Y
> + * _CID Y
> + * _CLS N requires PCI SIG class info
> + * _CPC Y
> + * _CR3 Y
> + * _CRS Y
> + * _CRT Y
> + * _CSD Y
> + * _CST Y
> + * _CWS Y
> + * _DCK Y
> + * _DCS Y
> + * _DDC Y
> + * _DDN Y
> + * _DEP Y
> + * _DGS Y
> + * _DIS Y
> + * _DLM Y
> + * _DMA Y
> + * _DOD Y
> + * _DOS Y
> + * _DSD Y
> + * _DSM N
> + * _DSS Y
> + * _DSW Y
> + * _DTI Y
> + * _Exx n/a
> + * _EC_ Y
> + * _EDL Y
> + * _EJD Y
> + * _EJx Y
> + * _EVT Y
> + * _FDE N (floppy controller, ignore)
> + * _FDI N (floppy controller, ignore)
> + * _FDM N (floppy controller, ignore)
> + * _FIF Y
> + * _FIT Y
> + * _FIX Y
> + * _FPS Y
> + * _FSL Y
> + * _FST Y
> + * _GAI Y
> + * _GCP Y
> + * _GHL Y
> + * _GL n/a
> + * _GLK Y
> + * _GPD Y
> + * _GPE Y
> + * _GRT Y
> + * _GSB Y
> + * _GTF Y
> + * _GTM Y
> + * _GTS deprecated
> + * _GWS Y
> + * _HID Y
> + * _HOT Y
> + * _HPP Y
> + * _HPX N
> + * _HRV Y
> + * _IFT Y
> + * _INI Y
> + * _IRC Y
> + * _Lxx n/a
> + * _LCK Y
> + * _LID Y
> + * _LPI Y
> + * _MAT N
> + * _MBM Y
> + * _MLS Y
> + * _MSG Y
> + * _MSM N
> + * _MTL Y
> + * _NTT Y
> + * _OFF Y
> + * _ON_ Y
> + * _OSC n/a
> + * _OST n/a
> + * _PAI n/a
> + * _PCL Y
> + * _PCT Y
> + * _PDC deprecated
> + * _PDL Y
> + * _PIC Y
> + * _PIF Y
> + * _PLD Y
> + * _PMC Y
> + * _PMD Y
> + * _PMM Y
> + * _PPC Y
> + * _PPE Y
> + * _PR0 Y
> + * _PR1 Y
> + * _PR2 Y
> + * _PR3 Y
> + * _PRE Y
> + * _PRL Y
> + * _PRR Y
> + * _PRS Y
> + * _PRT Y
> + * _PRW Y
> + * _PS0 Y
> + * _PS1 Y
> + * _PS2 Y
> + * _PS3 Y
> + * _PSC Y
> + * _PSD Y
> + * _PSE Y
> + * _PSL Y
> + * _PSR Y
> + * _PSS Y
> + * _PSV Y
> + * _PSW Y
> + * _PTC Y
> + * _PTP n/a
> + * _PTS Y
> + * _PUR Y
> + * _PXM Y
> + * _Qxx n/a
> + * _RDI Y
> + * _REG n/a
> + * _RMV Y
> + * _ROM Y
> + * _RST Y
> + * _RTV Y
> + * _S0_ Y
> + * _S1_ Y
> + * _S2_ Y
> + * _S3_ Y
> + * _S4_ Y
> + * _S5_ Y
> + * _S1D Y
> + * _S2D Y
> + * _S3D Y
> + * _S4D Y
> + * _S0W Y
> + * _S1W Y
> + * _S2W Y
> + * _S3W Y
> + * _S4W Y
> + * _SBS Y
> + * _SCP Y
> + * _SDD n/a
> + * _SEG Y
> + * _SHL n/a
> + * _SLI N
> + * _SPD Y
> + * _SRS n/a
> + * _SRT Y
> + * _SRV Y
> + * _SST Y
> + * _STA Y
> + * _STM n/a
> + * _STP Y
> + * _STR Y
> + * _STV Y
> + * _SUB Y
> + * _SUN Y
> + * _SWS Y
> + * _T_x n/a
> + * _TC1 Y
> + * _TC2 Y
> + * _TDL Y
> + * _TFP Y
> + * _TIP Y
> + * _TIV Y
> + * _TMP Y
> + * _TPC Y
> + * _TPT Y
> + * _TRT Y
> + * _TSD Y
> + * _TSN Y
> + * _TSP Y
> + * _TSS Y
> + * _TST Y
> + * _TTS Y
> + * _TZD Y
> + * _TZM Y
> + * _TZP Y
> + * _UID Y
> + * _UPC Y
> + * _UPD Y
> + * _UPP Y
> + * _VPO Y
> + * _WAK Y
> + * _WPC Y
> + * _WPP Y
> + * _Wxx n/a
> + * _WDG N
> + * _WED N
> + */
> +
> +/* Test types */
> +#define METHOD_MANDATORY 1
> +#define METHOD_OPTIONAL 2
> +#define METHOD_MOBILE 4
> +#define METHOD_SILENT 8
> +
> +#define ACPI_TYPE_INTBUF (ACPI_TYPE_INVALID + 1)
> +
> +#define method_check_type(fw, name, buf, type) \
> + method_check_type__(fw, name, buf, type, #type)
> +
> +static bool fadt_mobile_platform; /* True if a mobile platform */
> +
> +#define method_test_integer(name, type) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + return method_evaluate_method(fw, type, # name, \
> + NULL, 0, method_test_integer_return, # name); \
> +}
> +
> +typedef void (*method_test_return)(fwts_framework *fw, char *name,
> + ACPI_BUFFER *ret_buff, ACPI_OBJECT *ret_obj, void *private);
> +
> +/*
> + * Helper functions to facilitate the evaluations
> + */
> +
> +/****************************************************************************/
> +
> +static bool method_type_matches(ACPI_OBJECT_TYPE t1, ACPI_OBJECT_TYPE t2)
> +{
> + if (t1 == ACPI_TYPE_INTBUF &&
> + (t2 == ACPI_TYPE_INTEGER || t2 == ACPI_TYPE_BUFFER))
> + return true;
> +
> + if (t2 == ACPI_TYPE_INTBUF &&
> + (t1 == ACPI_TYPE_INTEGER || t1 == ACPI_TYPE_BUFFER))
> + return true;
> +
> + return t1 == t2;
> +}
> +
> +/*
> + * method_passed_sane()
> + * helper function to report often used passed messages
> + */
> +static void method_passed_sane(
> + fwts_framework *fw,
> + const char *name,
> + const char *type)
> +{
> + fwts_passed(fw, "%s correctly returned a sane looking %s.", name, type);
> +}
> +
> +/*
> + * method_passed_sane_uint64()
> + * helper function to report often used passed uint64 values
> + */
> +static void method_passed_sane_uint64(
> + fwts_framework *fw,
> + const char *name,
> + const uint64_t value)
> +{
> + fwts_passed(fw, "%s correctly returned sane looking "
> + "value 0x%8.8" PRIx64 ".", name, value);
> +}
> +
> +/*
> + * method_failed_null_return()
> + * helper function to report often used failed NULL object return
> + */
> +static void method_failed_null_object(
> + fwts_framework *fw,
> + const char *name,
> + const char *type)
> +{
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnNullObj",
> + "%s returned a NULL object, and did not "
> + "return %s.", name, type);
> +}
> +
> +/*
> + * method_package_count_min()
> + * check that an ACPI package has at least 'min' elements
> + */
> +static int method_package_count_min(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const ACPI_OBJECT *obj,
> + const uint32_t min)
> +{
> + if (obj->Package.Count < min) {
> + char tmp[128];
> +
> + snprintf(tmp, sizeof(tmp), "Method%sElementCount", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s should return package of at least %" PRIu32
> + " element%s, got %" PRIu32 " element%s instead.",
> + name, min, min == 1 ? "" : "s",
> + obj->Package.Count, obj->Package.Count == 1 ? "" : "s");
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
> +
> +/*
> + * method_package_count_equal()
> + * check that an ACPI package has exactly 'count' elements
> + */
> +static int method_package_count_equal(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const ACPI_OBJECT *obj,
> + const uint32_t count)
> +{
> + if (obj->Package.Count != count) {
> + char tmp[128];
> +
> + snprintf(tmp, sizeof(tmp), "Method%sElementCount", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s should return package of %" PRIu32
> + " element%s, got %" PRIu32 " element%s instead.",
> + name, count, count == 1 ? "" : "s",
> + obj->Package.Count, obj->Package.Count == 1 ? "" : "s");
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
> +
> +/*
> + * method_init()
> + * initialize ACPI
> + */
> +static int sbbr_method_init(fwts_framework *fw)
> +{
> + fwts_acpi_table_info *info;
> + int i;
> + bool got_fadt = false;
> +
> + fadt_mobile_platform = false;
> +
> + /* Some systems have multiple FADTs, sigh */
> + for (i = 0; i < 256; i++) {
> + fwts_acpi_table_fadt *fadt;
> + int ret = fwts_acpi_find_table(fw, "FACP", i, &info);
> + if (ret == FWTS_NULL_POINTER || info == NULL)
> + break;
> + fadt = (fwts_acpi_table_fadt*)info->data;
> + got_fadt = true;
> + if (fadt->preferred_pm_profile == 2) {
> + fadt_mobile_platform = true;
> + break;
> + }
> + }
> +
> + if (got_fadt && !fadt_mobile_platform) {
> + fwts_log_info(fw,
> + "FADT Preferred PM profile indicates this is not "
> + "a Mobile Platform.");
> + }
> +
> + if (fwts_acpi_init(fw) != FWTS_OK) {
> + fwts_log_error(fw, "Cannot initialise ACPI.");
> + return FWTS_ERROR;
> + }
> +
> + return FWTS_OK;
> +}
> +
> +/*
> + * method_deinit
> + * de-intialize ACPI
> + */
> +static int sbbr_method_deinit(fwts_framework *fw)
> +{
> + return fwts_acpi_deinit(fw);
> +}
> +
> +/*
> + * method_evaluate_found_method
> + * find a given object name and evaluate it
> + */
> +static void method_evaluate_found_method(
> + fwts_framework *fw,
> + char *name,
> + method_test_return check_func,
> + void *private,
> + ACPI_OBJECT_LIST *arg_list)
> +{
> + ACPI_BUFFER buf;
> + ACPI_STATUS ret;
> + int sem_acquired;
> + int sem_released;
> +
> + fwts_acpica_sem_count_clear();
> +
> + ret = fwts_acpi_object_evaluate(fw, name, arg_list, &buf);
> +
> + if (ACPI_FAILURE(ret) != AE_OK) {
> + fwts_acpi_object_evaluate_report_error(fw, name, ret);
> + } else {
> + if (check_func != NULL) {
> + ACPI_OBJECT *obj = buf.Pointer;
> + check_func(fw, name, &buf, obj, private);
> + }
> + }
> + free(buf.Pointer);
> +
> + fwts_acpica_sem_count_get(&sem_acquired, &sem_released);
> + if (sem_acquired != sem_released) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired",
> + "%s left %d locks in an acquired state.",
> + name, sem_acquired - sem_released);
> + fwts_advice(fw,
> + "Locks left in an acquired state generally indicates "
> + "that the AML code is not releasing a lock. This can "
> + "sometimes occur when a method hits an error "
> + "condition and exits prematurely without releasing an "
> + "acquired lock. It may be occurring in the method "
> + "being tested or other methods used while evaluating "
> + "the method.");
> + }
> +}
> +
> +/*
> + * method_evaluate_method
> + * find all matching object names and evaluate them,
> + * also run the callback check_func to sanity check
> + * any returned values
> + */
> +static int method_evaluate_method(fwts_framework *fw,
> + int test_type, /* Manditory or optional */
> + char *name,
> + ACPI_OBJECT *args,
> + int num_args,
> + method_test_return check_func,
> + void *private)
> +{
> + fwts_list *methods;
> + size_t name_len = strlen(name);
> + bool found = false;
> +
> +
> + if ((methods = fwts_acpi_object_get_names()) != NULL) {
> + fwts_list_link *item;
> +
> + fwts_list_foreach(item, methods) {
> + char *method_name = fwts_list_data(char*, item);
> + ACPI_HANDLE method_handle;
> + ACPI_OBJECT_TYPE type;
> + ACPI_STATUS status;
> +
> + size_t len = strlen(method_name);
> + if (strncmp(name, method_name + len - name_len, name_len) == 0) {
> + ACPI_OBJECT_LIST arg_list;
> +
> + status = AcpiGetHandle (NULL, method_name, &method_handle);
> + if (ACPI_FAILURE(status)) {
> + fwts_warning(fw, "Failed to get handle for object %s.", name);
> + }
> + status = AcpiGetType(method_handle, &type);
> + if (ACPI_FAILURE(status)) {
> + fwts_warning(fw, "Failed to get object type for %s.",name);
> + }
> +
> + if (type == ACPI_TYPE_LOCAL_SCOPE)
> + continue;
> +
> + found = true;
> + arg_list.Count = num_args;
> + arg_list.Pointer = args;
> + method_evaluate_found_method(fw, method_name,
> + check_func, private, &arg_list);
> + }
> + }
> + }
> +
> + if (found) {
> + if ((test_type & METHOD_MOBILE) && (!fadt_mobile_platform)) {
> + fwts_warning(fw,
> + "The FADT indictates that this machine is not "
> + "a mobile platform, however it has a mobile "
> + "platform specific object %s defined. "
> + "Either the FADT referred PM profile is "
> + "incorrect or this machine has mobile "
> + "platform objects defined when it should not.",
> + name);
> + }
> + return FWTS_OK;
> + } else {
> + if (!(test_type & METHOD_SILENT)) {
> + /* Mandatory not-found test are a failure */
> + if (test_type & METHOD_MANDATORY) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodNotExist",
> + "Object %s did not exist.", name);
> + }
> +
> + /* Mobile specific tests on non-mobile platform? */
> + if ((test_type & METHOD_MOBILE) && (!fadt_mobile_platform)) {
> + fwts_skipped(fw,
> + "Machine is not a mobile platform, skipping "
> + "test for non-existent mobile platform "
> + "related object %s.", name);
> + } else {
> + fwts_skipped(fw,
> + "Skipping test for non-existent object %s.",
> + name);
> + }
> + }
> + return FWTS_NOT_EXIST;
> +
> + }
> +}
> +
> +/*
> + * method_name_check
> + * sanity check object name conforms to ACPI specification
> + */
> +static int method_name_check(fwts_framework *fw)
> +{
> + fwts_list *methods;
> +
> + if ((methods = fwts_acpi_object_get_names()) != NULL) {
> + fwts_list_link *item;
> + bool failed = false;
> +
> + fwts_log_info(fw, "Found %d Objects\n", methods->len);
> +
> + fwts_list_foreach(item, methods) {
> + char *ptr;
> +
> + for (ptr = fwts_list_data(char *, item); *ptr; ptr++) {
> + if (!((*ptr == '\\') ||
> + (*ptr == '.') ||
> + (*ptr == '_') ||
> + (isdigit(*ptr)) ||
> + (isupper(*ptr))) ) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "MethodIllegalName",
> + "Method %s contains an illegal "
> + "character: '%c'. This should "
> + "be corrected.",
> + fwts_list_data(char *, item),
> + *ptr);
> + failed = true;
> + break;
> + }
> + }
> + }
> + if (!failed)
> + fwts_passed(fw, "Method names contain legal characters.");
> + }
> +
> + return FWTS_OK;
> +}
> +
> +/*
> + * method_check_type__
> + * check returned object type
> + */
> +static int method_check_type__(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT_TYPE type,
> + char *type_name)
> +{
> + ACPI_OBJECT *obj;
> +
> + if ((buf == NULL) || (buf->Pointer == NULL)) {
> + method_failed_null_object(fw, name, type_name);
> + return FWTS_ERROR;
> + }
> +
> + obj = buf->Pointer;
> +
> + if (!method_type_matches(obj->Type, type)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodReturnBadType",
> + "Method %s did not return %s.", name, type_name);
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
> +
> +/*
> + * method_test_buffer_return
> + * check if a buffer object was returned
> + */
> +static void method_test_buffer_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) == FWTS_OK)
> + fwts_passed(fw, "%s correctly returned a buffer of %" PRIu32 " elements.",
> + name, obj->Buffer.Length);
> +}
> +
> +/*
> + * method_test_integer_return
> + * check if an integer object was returned
> + */
> +static void method_test_integer_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(obj);
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK)
> + fwts_passed(fw, "%s correctly returned an integer.", name);
> +}
> +
> +/*
> + * method_test_string_return
> + * check if an string object was returned
> + */
> +static void method_test_string_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(obj);
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_STRING) == FWTS_OK)
> + fwts_passed(fw, "%s correctly returned a string.", name);
> +}
> +
> +/*
> + * method_test_reference_return
> + * check if a reference object was returned
> + */
> +static void method_test_reference_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(obj);
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_LOCAL_REFERENCE) == FWTS_OK)
> + fwts_passed(fw, "%s correctly returned a reference.", name);
> +}
> +
> +/*
> + * method_test_NULL_return
> + * check if no object was retuned
> + */
> +static void method_test_NULL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + /*
> + * In ACPICA SLACK mode null returns can be actually
> + * forced to return ACPI integers. Blame an errata
> + * and Windows compatibility for this mess.
> + */
> + if (fw->acpica_mode & FWTS_ACPICA_MODE_SLACK) {
> + if ((buf != NULL) && (buf->Pointer != NULL)) {
> + ACPI_OBJECT *objtmp = buf->Pointer;
> + if (method_type_matches(objtmp->Type, ACPI_TYPE_INTEGER)) {
> + fwts_passed(fw, "%s returned an ACPI_TYPE_INTEGER as expected in slack mode.",
> + name);
> + return;
> + }
> + }
> + }
> +
> + if (buf && buf->Length && buf->Pointer) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "MethodShouldReturnNothing", "%s returned values, but was expected to return nothing.", name);
> + fwts_log_info(fw, "Object returned:");
> + fwts_acpi_object_dump(fw, obj);
> + fwts_advice(fw,
> + "This probably won't cause any errors, but it should "
> + "be fixed as the AML code is not conforming to the "
> + "expected behaviour as described in the ACPI "
> + "specification.");
> + } else
> + fwts_passed(fw, "%s returned no values as expected.", name);
> +}
> +
> +/*
> + * method_test_passed_failed_return
> + * check if 0 or 1 (false/true) integer is returned
> + */
> +static void method_test_passed_failed_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + char *method = (char *)private;
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) {
> + uint32_t val = (uint32_t)obj->Integer.Value;
> + if ((val == 0) || (val == 1))
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> + else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodReturnZeroOrOne",
> + "%s returned 0x%8.8" PRIx32 ", should return 1 "
> + "(success) or 0 (failed).", method, val);
> + fwts_advice(fw,
> + "Method %s should be returning the correct "
> + "1/0 success/failed return values. "
> + "Unexpected behaviour may occur becauses of "
> + "this error, the AML code does not conform to "
> + "the ACPI specification and should be fixed.",
> + method);
> + }
> + }
> +}
> +
> +/*
> + * method_test_polling_return
> + * check if a returned polling time is valid
> + */
> +static void method_test_polling_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK) {
> + char *method = (char *)private;
> + if (obj->Integer.Value < 36000) {
> + fwts_passed(fw,
> + "%s correctly returned sane looking value "
> + "%f seconds", method,
> + (float)obj->Integer.Value / 10.0);
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodPollTimeTooLong",
> + "%s returned a value %f seconds > (1 hour) "
> + "which is probably incorrect.",
> + method, (float)obj->Integer.Value / 10.0);
> + fwts_advice(fw,
> + "The method is returning a polling interval "
> + "which is very long and hence most probably "
> + "incorrect.");
> + }
> + }
> +}
> +
> +
> +/*
> + * Common types that can be returned. This is not a complete
> + * list but it does cover the types we expect to return from
> + * an ACPI evaluation.
> + */
> +static const char *method_type_name(const ACPI_OBJECT_TYPE type)
> +{
> + switch (type) {
> + case ACPI_TYPE_INTEGER:
> + return "integer";
> + case ACPI_TYPE_STRING:
> + return "string";
> + case ACPI_TYPE_BUFFER:
> + return "buffer";
> + case ACPI_TYPE_PACKAGE:
> + return "package";
> + case ACPI_TYPE_BUFFER_FIELD:
> + return "buffer_field";
> + case ACPI_TYPE_LOCAL_REFERENCE:
> + return "reference";
> + case ACPI_TYPE_INTBUF:
> + return "integer or buffer";
> + default:
> + return "unknown";
> + }
> +}
> +
> +/*
> + * method_package_elements_all_type()
> + * sanity check fields in a package that all have
> + * the same type
> + */
> +static int method_package_elements_all_type(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const ACPI_OBJECT *obj,
> + const ACPI_OBJECT_TYPE type)
> +{
> + uint32_t i;
> + bool failed = false;
> + char tmp[128];
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (!method_type_matches(obj->Package.Elements[i].Type, type)) {
> + snprintf(tmp, sizeof(tmp), "Method%sElementType", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s package element %" PRIu32 " was not the expected "
> + "type '%s', was instead type '%s'.",
> + name, i,
> + method_type_name(type),
> + method_type_name(obj->Package.Elements[i].Type));
> + failed = true;
> + }
> + }
> +
> + return failed ? FWTS_ERROR: FWTS_OK;
> +}
> +
> +typedef struct {
> + ACPI_OBJECT_TYPE type; /* Type */
> + const char *name; /* Field name */
> +} fwts_package_element;
> +
> +/*
> + * method_package_elements_type()
> + * sanity check fields in a package that all have
> + * the same type
> + */
> +static int method_package_elements_type(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const ACPI_OBJECT *obj,
> + const fwts_package_element *info,
> + const uint32_t count)
> +{
> + uint32_t i;
> + bool failed = false;
> + char tmp[128];
> +
> + if (obj->Package.Count != count)
> + return FWTS_ERROR;
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (!method_type_matches(obj->Package.Elements[i].Type, info[i].type)) {
> + snprintf(tmp, sizeof(tmp), "Method%sElementType", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s package element %" PRIu32 " (%s) was not the expected "
> + "type '%s', was instead type '%s'.",
> + name, i, info[i].name,
> + method_type_name(info[i].type),
> + method_type_name(obj->Package.Elements[i].Type));
> + failed = true;
> + }
> + }
> +
> + return failed ? FWTS_ERROR: FWTS_OK;
> +}
> +
> +/****************************************************************************/
> +
> +/*
> + * Section 5.6 ACPI Event Programming Model
> + */
> +static void method_test_AEI_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + ACPI_STATUS status;
> + ACPI_RESOURCE *resource;
> + ACPI_RESOURCE_GPIO* gpio;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + status = AcpiBufferToResource(obj->Buffer.Pointer, obj->Buffer.Length, &resource);
> + if (ACPI_FAILURE(status))
> + return;
> +
> + do {
> + if (resource->Type == ACPI_RESOURCE_TYPE_GPIO) {
> + gpio = &resource->Data.Gpio;
> + if (gpio->ConnectionType != ACPI_RESOURCE_GPIO_TYPE_INT) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_AEIBadGpioElement",
> + "%s should contain only GPIO Connection Type 0, got %" PRIu32,
> + name, gpio->ConnectionType);
> + }
> + } else {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_AEIBadElement",
> + "%s should contain only Resource Type 17, got%" PRIu32,
> + name, resource->Type);
> + }
> +
> + resource = ACPI_NEXT_RESOURCE(resource);
> + } while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG);
> +
> + if (!failed)
> + method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_AEI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_AEI", NULL, 0, method_test_AEI_return, NULL);
> +}
> +
> +static void check_evt_event (
> + fwts_framework *fw,
> + ACPI_RESOURCE_GPIO *gpio)
> +{
> + ACPI_OBJECT arg[1];
> + ACPI_HANDLE evt_handle;
> + ACPI_STATUS status;
> + char path[256];
> + uint16_t i;
> +
> + /* Skip the leading spaces in ResourceSource. */
> + for (i = 0; i < gpio->ResourceSource.StringLength; i++) {
> + if (gpio->ResourceSource.StringPtr[i] != ' ')
> + break;
> + }
> +
> + if (i == gpio->ResourceSource.StringLength) {
> + fwts_log_warning(fw, "Invalid ResourceSource");
> + return;
> + }
> +
> + /* Get the handle of return;the _EVT method. */
> + snprintf (path, 251, "%s._EVT", &gpio->ResourceSource.StringPtr[i]);
> +
> + status = AcpiGetHandle (NULL, path, &evt_handle);
> + if (ACPI_FAILURE(status)) {
> + fwts_log_warning(fw, "Failed to find valid handle for _EVT method (0x%x), %s", status, path);
> + return;
> + }
> +
> + /* Call the _EVT method with all the pins defined for the GpioInt */
> + for (i = 0; i < gpio->PinTableLength; i++) {
> + ACPI_OBJECT_LIST arg_list;
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = gpio->PinTable[i];
> + arg_list.Count = 1;
> + arg_list.Pointer = arg;
> +
> + method_evaluate_found_method(fw, path, method_test_NULL_return, NULL, &arg_list);
> + }
> +}
> +
> +static void method_test_EVT_return (
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + ACPI_RESOURCE *resource;
> + ACPI_STATUS status;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + status = AcpiBufferToResource(obj->Buffer.Pointer, obj->Buffer.Length, &resource);
> + if (ACPI_FAILURE(status))
> + return;
> +
> + do {
> + if (!resource->Length) {
> + fwts_log_warning(fw, "Invalid zero length descriptor in resource list\n");
> + break;
> + }
> +
> + if (resource->Type == ACPI_RESOURCE_TYPE_GPIO &&
> + resource->Data.Gpio.ConnectionType == ACPI_RESOURCE_GPIO_TYPE_INT)
> + check_evt_event(fw, &resource->Data.Gpio);
> +
> + resource = ACPI_NEXT_RESOURCE(resource);
> + } while (resource->Type != ACPI_RESOURCE_TYPE_END_TAG);
> +}
> +
> +static int method_test_EVT(fwts_framework *fw)
> +{
> + int ret;
> +
> + /* Only test the _EVT method with pins defined in AEI. */
> + ret = method_evaluate_method(fw, METHOD_OPTIONAL | METHOD_SILENT,
> + "_AEI", NULL, 0, method_test_EVT_return, NULL);
> +
> + if (ret == FWTS_NOT_EXIST)
> + fwts_skipped(fw, "Skipping test for non-existant object _EVT.");
> +
> + return ret;
> +}
> +
> +/*
> + * Section 5.7 Predefined Objects
> + */
> +
> +static void method_test_DLM_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_DLM", obj, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg = &obj->Package.Elements[i];
> +
> + if (pkg->Package.Count != 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_DLMSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 2 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + if (pkg->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_DLMBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 0 is not a reference.",
> + name, i);
> + failed = true;
> + }
> +
> + if (pkg->Package.Elements[1].Type != ACPI_TYPE_LOCAL_REFERENCE &&
> + pkg->Package.Elements[1].Type != ACPI_TYPE_BUFFER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_DLMBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 1 is not a reference or a buffer.",
> + name, i);
> + failed = true;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_DLM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DLM", NULL, 0, method_test_DLM_return, NULL);
> +}
> +
> +/*
> + * Section 5.8 System Configuration Objects
> + */
> +static int method_test_PIC(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + int i, ret;
> + arg[0].Type = ACPI_TYPE_INTEGER;
> +
> + for (i = 0; i < 3; i++) {
> + arg[0].Integer.Value = i;
> + ret = method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PIC", arg, 1, method_test_NULL_return, NULL);
> +
> + if (ret != FWTS_OK)
> + break;
> + }
> + return ret;
> +}
> +
> +
> +/*
> + * Section 6.1 Device Identification Objects
> + */
> +static int method_test_DDN(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DDN", NULL, 0, method_test_string_return, NULL);
> +}
> +
> +static bool method_valid_HID_string(char *str)
> +{
> + if (strlen(str) == 7) {
> + /* PNP ID, must be 3 capitals followed by 4 hex */
> + if (!isupper(str[0]) ||
> + !isupper(str[1]) ||
> + !isupper(str[2])) return false;
> + if (!isxdigit(str[3]) ||
> + !isxdigit(str[4]) ||
> + !isxdigit(str[5]) ||
> + !isxdigit(str[6])) return false;
> + return true;
> + }
> +
> + if (strlen(str) == 8) {
> + /* ACPI ID, must be 4 capitals or digits followed by 4 hex */
> + if ((!isupper(str[0]) && !isdigit(str[0])) ||
> + (!isupper(str[1]) && !isdigit(str[1])) ||
> + (!isupper(str[2]) && !isdigit(str[2])) ||
> + (!isupper(str[3]) && !isdigit(str[3]))) return false;
> + if (!isxdigit(str[4]) ||
> + !isxdigit(str[5]) ||
> + !isxdigit(str[6]) ||
> + !isxdigit(str[7])) return false;
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static bool method_valid_EISA_ID(uint32_t id, char *buf, size_t buf_len)
> +{
> + snprintf(buf, buf_len, "%c%c%c%02" PRIX32 "%02" PRIX32,
> + 0x40 + ((id >> 2) & 0x1f),
> + 0x40 + ((id & 0x3) << 3) + ((id >> 13) & 0x7),
> + 0x40 + ((id >> 8) & 0x1f),
> + (id >> 16) & 0xff, (id >> 24) & 0xff);
> +
> + /* 3 chars in EISA ID must be upper case */
> + if (!isupper(buf[0]) ||
> + !isupper(buf[1]) ||
> + !isupper(buf[2])) return false;
> +
> + /* Last 4 digits are always going to be hex, so pass */
> + return true;
> +}
> +
> +static void method_test_HID_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + char tmp[8];
> +
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(private);
> +
> + if (obj == NULL) {
> + method_failed_null_object(fw, name, "a buffer or integer");
> + return;
> + }
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_STRING:
> + if (obj->String.Pointer) {
> + if (method_valid_HID_string(obj->String.Pointer))
> + fwts_passed(fw,
> + "%s returned a string '%s' "
> + "as expected.",
> + name, obj->String.Pointer);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodHIDInvalidString",
> + "%s returned a string '%s' "
> + "but it was not a valid PNP ID or a "
> + "valid ACPI ID.",
> + name, obj->String.Pointer);
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_HIDNullString",
> + "%s returned a NULL string.", name);
> + }
> + break;
> + case ACPI_TYPE_INTEGER:
> + if (method_valid_EISA_ID((uint32_t)obj->Integer.Value,
> + tmp, sizeof(tmp)))
> + fwts_passed(fw, "%s returned an integer "
> + "0x%8.8" PRIx64 " (EISA ID %s).",
> + name, (uint64_t)obj->Integer.Value, tmp);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodHIDInvalidInteger",
> + "%s returned a integer 0x%8.8" PRIx64 " "
> + "(EISA ID %s) but the this is not a valid "
> + "EISA ID encoded PNP ID.",
> + name, (uint64_t)obj->Integer.Value, tmp);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_HIDBadReturnType",
> + "%s did not return a string or an integer.", name);
> + break;
> + }
> +}
> +
> +static int method_test_HID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_HID", NULL, 0, method_test_HID_return, NULL);
> +}
> +
> +static void method_valid_CID_Type(
> + fwts_framework *fw,
> + char *name,
> + ACPI_OBJECT *obj)
> +{
> + char tmp[8];
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_STRING:
> + if (obj->String.Pointer) {
> + if (method_valid_HID_string(obj->String.Pointer))
> + fwts_passed(fw,
> + "%s returned a string '%s' "
> + "as expected.",
> + name, obj->String.Pointer);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodCIDInvalidString",
> + "%s returned a string '%s' "
> + "but it was not a valid PNP ID or a "
> + "valid ACPI ID.",
> + name, obj->String.Pointer);
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CIDNullString",
> + "%s returned a NULL string.", name);
> + }
> + break;
> + case ACPI_TYPE_INTEGER:
> + if (method_valid_EISA_ID((uint32_t)obj->Integer.Value,
> + tmp, sizeof(tmp)))
> + fwts_passed(fw, "%s returned an integer "
> + "0x%8.8" PRIx64 " (EISA ID %s).",
> + name, (uint64_t)obj->Integer.Value, tmp);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodCIDInvalidInteger",
> + "%s returned a integer 0x%8.8" PRIx64 " "
> + "(EISA ID %s) but the this is not a valid "
> + "EISA ID encoded PNP ID.",
> + name, (uint64_t)obj->Integer.Value, tmp);
> + break;
> + }
> +}
> +
> +static void method_test_CID_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> +
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(private);
> +
> + if (obj == NULL) {
> + method_failed_null_object(fw, name, "a buffer or integer");
> + return;
> + }
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_STRING:
> + case ACPI_TYPE_INTEGER:
> + method_valid_CID_Type(fw, name, obj);
> + break;
> + case ACPI_TYPE_PACKAGE:
> + if (method_package_count_min(fw, name, "_CID", obj, 1) != FWTS_OK)
> + return;
> +
> + for (i = 0; i < obj->Package.Count; i++){
> + ACPI_OBJECT *pkg = &obj->Package.Elements[i];
> + method_valid_CID_Type(fw, name, pkg);
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_CIDBadReturnType",
> + "%s did not return a string or an integer.", name);
> + break;
> + }
> +}
> +
> +static int method_test_CID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CID", NULL, 0, method_test_CID_return, NULL);
> +}
> +
> +static void method_test_MLS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_MLS", obj, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg = &obj->Package.Elements[i];
> +
> + if (pkg->Package.Count != 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_MLSSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 2 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + if (pkg->Package.Elements[0].Type != ACPI_TYPE_STRING) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_MLSBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 0 is not a string.",
> + name, i);
> + failed = true;
> + }
> +
> + if (pkg->Package.Elements[1].Type != ACPI_TYPE_BUFFER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_MLSBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 1 is not a buffer.",
> + name, i);
> + failed = true;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_MLS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_MLS", NULL, 0, method_test_MLS_return, NULL);
> +}
> +static int method_test_HRV(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_HRV", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_STR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_STR", NULL, 0, method_test_buffer_return, NULL);
> +}
> +
> +static void method_test_PLD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* All elements in the package must be buffers */
> + if (method_package_elements_all_type(fw, name, "_PLD", obj, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PLD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PLD", NULL, 0, method_test_PLD_return, NULL);
> +}
> +
> +static void method_test_SUB_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(private);
> +
> + if (obj == NULL) {
> + method_failed_null_object(fw, name, "a buffer or integer");
> + return;
> + }
> +
> + if (obj->Type == ACPI_TYPE_STRING)
> + if (obj->String.Pointer) {
> + if (method_valid_HID_string(obj->String.Pointer))
> + fwts_passed(fw,
> + "%s returned a string '%s' "
> + "as expected.",
> + name, obj->String.Pointer);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodSUBInvalidString",
> + "%s returned a string '%s' "
> + "but it was not a valid PNP ID or a "
> + "valid ACPI ID.",
> + name, obj->String.Pointer);
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SUBNullString",
> + "%s returned a NULL string.", name);
> + }
> + else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType",
> + "Method _SUB did not return a string or an integer.");
> + }
> +}
> +
> +
> +static int method_test_SUB(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SUB", NULL, 0, method_test_SUB_return, NULL);
> +}
> +
> +static int method_test_SUN(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SUN", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_UID_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(private);
> +
> + if (obj == NULL) {
> + method_failed_null_object(fw, name, "a buffer or integer");
> + return;
> + }
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_STRING:
> + if (obj->String.Pointer)
> + fwts_passed(fw,
> + "%s returned a string '%s' as expected.",
> + name, obj->String.Pointer);
> + else
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_UIDNullString",
> + "%s returned a NULL string.", name);
> + break;
> + case ACPI_TYPE_INTEGER:
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UIDBadReturnType",
> + "Method %s did not return a string or an integer.", name);
> + break;
> + }
> +}
> +
> +static int method_test_UID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_UID", NULL, 0, method_test_UID_return, NULL);
> +}
> +
> +/*
> + * Section 6.2 Device Configurations Objects
> + */
> +static void method_test_CRS_size(
> + fwts_framework *fw,
> + const char *name, /* full _CRS or _PRS path name */
> + const char *objname, /* name of _CRS or _PRS object */
> + const char *tag, /* error log tag */
> + const size_t crs_length, /* size of _CRS buffer */
> + const size_t hdr_length, /* size of _CRS header */
> + const size_t data_length, /* length of _CRS data w/o header */
> + const size_t min, /* minimum allowed _CRS data size */
> + const size_t max, /* maximum allowed _CRS data size */
> + bool *passed) /* pass/fail flag */
> +{
> + if (crs_length < data_length + hdr_length) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, tag,
> + "%s Resource size is %zd bytes long but "
> + "the size stated in the %s buffer header "
> + "is %zd and hence is longer. The resource "
> + "buffer is too short.",
> + name, crs_length, objname, data_length);
> + *passed = false;
> + return;
> + }
> +
> + if ((data_length < min) || (data_length > max)) {
> + if (min != max) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tag,
> + "%s Resource data size was %zd bytes long, "
> + "expected it to be between %zd and %zd bytes",
> + name, data_length, min, max);
> + *passed = false;
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tag,
> + "%s Resource data size was %zd bytes long, "
> + "expected it to be %zd bytes",
> + name, data_length, min);
> + *passed = false;
> + }
> + }
> +}
> +
> +static void method_test_CRS_small_size(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const uint8_t *data,
> + const size_t crs_length,
> + const size_t min,
> + const size_t max,
> + bool *passed)
> +{
> + size_t data_length = data[0] & 7;
> + char tmp[128];
> +
> + snprintf(tmp, sizeof(tmp), "Method%sSmallResourceSize", objname);
> +
> + method_test_CRS_size(fw, name, objname, tmp,
> + crs_length, 1, data_length, min, max, passed);
> +}
> +
> +
> +/*
> + * CRS small resource checks, simple checking
> + */
> +static void method_test_CRS_small_resource_items(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const uint8_t *data,
> + const size_t length,
> + bool *passed,
> + const char **tag)
> +{
> + uint8_t tag_item = (data[0] >> 3) & 0xf;
> + char tmp[128];
> +
> + static const char *types[] = {
> + "Reserved",
> + "Reserved",
> + "Reserved",
> + "Reserved",
> + "IRQ Descriptor",
> + "DMA Descriptor",
> + "Start Dependent Functions Descriptor",
> + "End Dependent Functions Descriptor",
> + "I/O Port Descriptor",
> + "Fixed Location I/O Port Descriptor",
> + "Fixed DMA Descriptor",
> + "Reserved",
> + "Reserved",
> + "Reserved",
> + "Vendor Defined Descriptor",
> + "End Tag Descriptor"
> + };
> +
> + switch (tag_item) {
> + case 0x4: /* 6.4.2.1 IRQ Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 2, 3, passed);
> + break;
> + case 0x5: /* 6.4.2.2 DMA Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 2, 2, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + if ((data[2] & 3) == 3) {
> + snprintf(tmp, sizeof(tmp), "Method%sDmaDescriptor", objname);
> + fwts_failed(fw, LOG_LEVEL_HIGH, tmp,
> + "%s DMA transfer type preference is 0x%" PRIx8
> + " which is reserved and invalid. See "
> + "Section 6.4.2.2 of the ACPI specification.",
> + name, data[2] & 3);
> + *passed = false;
> + }
> + break;
> + case 0x6: /* 6.4.2.3 Start Dependent Functions Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 0, 1, passed);
> + break;
> + case 0x7: /* 6.4.2.4 End Dependent Functions Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 0, 0, passed);
> + break;
> + case 0x8: /* 6.4.2.5 I/O Port Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 7, 7, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + if (data[1] & 0xfe) {
> + snprintf(tmp, sizeof(tmp), "Method%sIoPortInfoReservedNonZero", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s I/O Port Descriptor Information field "
> + "has reserved bits that are non-zero, got "
> + "0x%" PRIx8 " and expected 0 or 1 for this "
> + "field. ", name, data[1]);
> + *passed = false;
> + }
> + if (((data[1] & 1) == 0) && (data[3] > 3)) {
> + snprintf(tmp, sizeof(tmp), "Method%sIoPortInfoMinBase10BitAddr", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s I/O Port Descriptor range minimum "
> + "base address is more than 10 bits however "
> + "the Information field indicates that only "
> + "a 10 bit address is being used.", name);
> + *passed = false;
> + }
> + if (((data[1] & 1) == 0) && (data[5] > 3)) {
> + snprintf(tmp, sizeof(tmp), "Method%sIoPortInfoMaxBase10BitAddr", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s I/O Port Descriptor range maximum "
> + "base address is more than 10 bits however "
> + "the Information field indicates that only "
> + "a 10 bit address is being used.", name);
> + *passed = false;
> + }
> + break;
> + case 0x9: /* 6.4.2.6 Fixed Location I/O Port Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 3, 3, passed);
> + break;
> + case 0xa: /* 6.4.2.7 Fixed DMA Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 5, 5, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + if (data[5] > 5) {
> + snprintf(tmp, sizeof(tmp), "Method%sFixedDmaTransferWidth", objname);
> + fwts_failed(fw, LOG_LEVEL_HIGH, tmp,
> + "%s DMA transfer width is 0x%" PRIx8
> + " which is reserved and invalid. See "
> + "Section 6.4.2.7 of the ACPI specification.",
> + name, data[5]);
> + *passed = false;
> + }
> + break;
> + case 0xe: /* 6.4.2.8 Vendor-Defined Descriptor */
> + method_test_CRS_small_size(fw, name, objname, data, length, 1, 7, passed);
> + break;
> + case 0xf: /* 6.4.2.9 End Tag */
> + method_test_CRS_small_size(fw, name, objname, data, length, 1, 1, passed);
> + break;
> + default:
> + snprintf(tmp, sizeof(tmp), "Method%sUnkownSmallResourceItem", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s tag bits 6:3 is an undefined "
> + "small tag item name, value 0x%" PRIx8 ".",
> + name, tag_item);
> + fwts_advice(fw,
> + "A small resource data type tag (byte 0, "
> + "bits 6:3 of the %s buffer) contains "
> + "an undefined small tag item 'name'. "
> + "The %s buffer is therefore undefined "
> + "and can't be used. See section "
> + "'6.4.2 Small Resource Data Type' of the ACPI "
> + "specification, and also table 6-161.",
> + objname, objname);
> + *passed = false;
> + break;
> + }
> +
> + *tag = types[tag_item];
> +}
> +
> +static void method_test_CRS_large_size(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const uint8_t *data,
> + const size_t crs_length,
> + const size_t min,
> + const size_t max,
> + bool *passed)
> +{
> + size_t data_length;
> + char tmp[128];
> +
> + /* Small _CRS resources have a 3 byte header */
> + if (crs_length < 3) {
> + snprintf(tmp, sizeof(tmp), "Method%sBufferTooSmall", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s should return a buffer of at least three bytes in length.", name);
> + *passed = false;
> + return;
> + }
> +
> + data_length = (size_t)data[1] + ((size_t)data[2] << 8);
> +
> + snprintf(tmp, sizeof(tmp), "Method%sLargeResourceSize",objname);
> + method_test_CRS_size(fw, name, objname, tmp,
> + crs_length, 3, data_length, min, max, passed);
> +}
> +
> +/*
> + * Some CRS value fetching helper functions. We handle all the
> + * addresses and lengths in 64 bits to make life easier
> + */
> +static uint64_t method_CRS_val64(const uint8_t *data)
> +{
> + uint64_t val =
> + ((uint64_t)data[7] << 56) | ((uint64_t)data[6] << 48) |
> + ((uint64_t)data[5] << 40) | ((uint64_t)data[4] << 32) |
> + ((uint64_t)data[3] << 24) | ((uint64_t)data[2] << 16) |
> + ((uint64_t)data[1] << 8) | (uint64_t)data[0];
> +
> + return val;
> +}
> +
> +static uint64_t method_CRS_val32(const uint8_t *data)
> +{
> + uint64_t val =
> + ((uint64_t)data[3] << 24) | ((uint64_t)data[2] << 16) |
> + ((uint64_t)data[1] << 8) | (uint64_t)data[0];
> +
> + return val;
> +}
> +
> +static uint64_t method_CRS_val24(const uint8_t *data)
> +{
> + /* 24 bit values assume lower 8 bits are zero */
> + uint64_t val =
> + ((uint64_t)data[1] << 16) | ((uint64_t)data[0] << 8);
> +
> + return val;
> +}
> +
> +static uint64_t method_CRS_val16(const uint8_t *data)
> +{
> + uint64_t val =
> + ((uint64_t)data[1] << 8) | (uint64_t)data[0];
> +
> + return val;
> +}
> +
> +/*
> + * Sanity check addresses according to table 6-179 of ACPI spec
> + */
> +static void method_test_CRS_mif_maf(
> + fwts_framework *fw,
> + const char *name, /* Full _CRS or _PRS path name */
> + const char *objname, /* _CRS or _PRS name */
> + const uint8_t flag, /* _MIF _MAF flag field */
> + const uint64_t min, /* Min address */
> + const uint64_t max, /* Max address */
> + const uint64_t len, /* Range length */
> + const uint64_t granularity, /* Address granularity */
> + const char *tag, /* failed error tag */
> + const char *type, /* Resource type */
> + bool *passed)
> +{
> + char tmp[128];
> + uint8_t mif = (flag >> 2) & 1;
> + uint8_t maf = (flag >> 3) & 1;
> +
> + static char *mif_maf_advice =
> + "See section '6.4.3.5 Address Space Resource Descriptors' "
> + "table 6-179 of the ACPI specification for more details "
> + "about how the _MIF, _MAF and memory range and granularity "
> + "rules apply. Typically the kernel does not care about these "
> + "being correct, so this is a minor issue.";
> +
> + /* Table 6-179 Valid combination of Address Space Descriptors fields */
> + if (len == 0) {
> + if ((mif == 1) && (maf == 1)) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sMifMafBothOne", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s _MIF and _MAF flags are both "
> + "set to one which is invalid when "
> + "the length field is 0.",
> + name, type);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if ((mif == 1) && (min % (granularity + 1) != 0)) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sMinNotMultipleOfGran", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s _MIN address is not a multiple "
> + "of the granularity when _MIF is 1.",
> + name, type);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if ((maf == 1) && (max % (granularity - 1) != 0)) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sMaxNotMultipleOfGran", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s _MAX address is not a multiple "
> + "of the granularity when _MAF is 1.",
> + name, type);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + } else {
> + if ((mif == 0) && (maf == 0) &&
> + (len % (granularity + 1) != 0)) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sLenNotMultipleOfGran", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s length is not a multiple "
> + "of the granularity when _MIF "
> + "and _MIF are 0.",
> + name, type);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if (((mif == 0) && (maf == 1)) ||
> + ((mif == 1) && (maf == 0))) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sMifMafInvalid", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s _MIF and _MAF flags are either "
> + "0 and 1 or 1 and 0 which is invalid when "
> + "the length field is non-zero.",
> + name, type);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if ((mif == 1) && (maf == 1)) {
> + if (granularity != 0) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sGranularityNotZero", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s granularity 0x%" PRIx64
> + " is not zero as expected when "
> + "_MIF and _MAF are both 1.",
> + name, type, granularity);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if (min > max) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sMaxLessThanMin", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s minimum address range 0x%" PRIx64
> + " is greater than the maximum address "
> + "range 0x%" PRIx64 ".",
> + name, type, min, max);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + if (max - min + 1 != len) {
> + snprintf(tmp, sizeof(tmp), "Method%s%sLengthInvalid", objname, tag);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + tmp,
> + "%s %s length 0x%" PRIx64
> + " does not match the difference between "
> + "the minimum and maximum address ranges "
> + "0x%" PRIx64 "-0x%" PRIx64 ".",
> + name, type, len, min, max);
> + fwts_advice(fw, "%s", mif_maf_advice);
> + *passed = false;
> + }
> + }
> + }
> +}
> +
> +/*
> + * CRS large resource checks, simple checking
> + */
> +static void method_test_CRS_large_resource_items(
> + fwts_framework *fw,
> + const char *name,
> + const char *objname,
> + const uint8_t *data,
> + const uint64_t length,
> + bool *passed,
> + const char **tag)
> +{
> + uint64_t min, max, len, gra;
> + uint8_t tag_item = data[0] & 0x7f;
> + char tmp[128];
> +
> + static const char *types[] = {
> + "Reserved",
> + "24-bit Memory Range Descriptor",
> + "Generic Register Descriptor",
> + "Reserved",
> + "Vendor Defined Descriptor",
> + "32-bit Memory Range Descriptor",
> + "32-bit Fixed Location Memory Range Descriptor",
> + "DWORD Address Space Descriptor",
> + "WORD Address Space Descriptor",
> + "Extended IRQ Descriptor",
> + "QWORD Address Space Descriptor",
> + "Extended Addresss Space Descriptor",
> + "GPIO Connection Descriptor",
> + "Reserved",
> + "Generic Serial Bus Connection Descriptor",
> + "Reserved",
> + };
> +
> + switch (tag_item) {
> + case 0x1: /* 6.4.3.1 24-Bit Memory Range Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 9, 9, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + min = method_CRS_val24(&data[4]);
> + max = method_CRS_val24(&data[6]);
> + len = method_CRS_val16(&data[10]);
> + if (max < min) {
> + snprintf(tmp, sizeof(tmp), "Method%s24BitMemRangeMaxLessThanMin", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s 24-Bit Memory Range Descriptor minimum "
> + "address range 0x%" PRIx64 " is greater than "
> + "the maximum address range 0x%" PRIx64 ".",
> + name, min, max);
> + *passed = false;
> + }
> + if (len > max + 1 - min) {
> + snprintf(tmp, sizeof(tmp), "Method%s24BitMemRangeLengthTooLarge", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s 24-Bit Memory Range Descriptor length "
> + "0x%" PRIx64 " is greater than size between the "
> + "the minimum and maximum address ranges "
> + "0x%" PRIx64 "-0x%" PRIx64 ".",
> + name, len, min, max);
> + *passed = false;
> + }
> + break;
> + case 0x2: /* 6.4.3.7 Generic Register Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 12, 12, passed);
> + if (!*passed)
> + break;
> + switch (data[3]) {
> + case 0x00 ... 0x04:
> + case 0x0a:
> + case 0x7f:
> + /* Valid values */
> + break;
> + default:
> + snprintf(tmp, sizeof(tmp), "Method%sGenericRegAddrSpaceIdInvalid", objname);
> + fwts_failed(fw, LOG_LEVEL_HIGH, tmp,
> + "%s Generic Register Descriptor has an invalid "
> + "Address Space ID 0x%" PRIx8 ".",
> + name, data[3]);
> + *passed = false;
> + }
> + if (data[6] > 4) {
> + snprintf(tmp, sizeof(tmp), "Method%sGenericRegAddrSizeInvalid", objname);
> + fwts_failed(fw, LOG_LEVEL_HIGH, tmp,
> + "%s Generic Register Descriptor has an invalid "
> + "Address Access Size 0x%" PRIx8 ".",
> + name, data[6]);
> + *passed = false;
> + }
> + break;
> + case 0x4: /* 6.4.3.2 Vendor-Defined Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 0, 65535, passed);
> + break;
> + case 0x5: /* 6.4.3.3 32-Bit Memory Range Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 17, 17, passed);
> + if (!*passed)
> + break;
> + min = method_CRS_val32(&data[4]);
> + max = method_CRS_val32(&data[8]);
> + len = method_CRS_val32(&data[16]);
> + if (max < min) {
> + snprintf(tmp, sizeof(tmp), "Method%s32BitMemRangeMaxLessThanMin", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s 32-Bit Memory Range Descriptor minimum "
> + "address range 0x%" PRIx64 " is greater than "
> + "the maximum address range 0x%" PRIx64 ".",
> + name, min, max);
> + *passed = false;
> + }
> + if (len > max + 1 - min) {
> + snprintf(tmp, sizeof(tmp), "Method%s32BitMemRangeLengthTooLarge", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s 32-Bit Memory Range Descriptor length "
> + "0x%" PRIx64 " is greater than size between the "
> + "the minimum and maximum address ranges "
> + "0x%" PRIx64 "-0x%" PRIx64 ".",
> + name, len, min, max);
> + *passed = false;
> + }
> + break;
> + case 0x6: /* 6.4.3.4 32-Bit Fixed Memory Range Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 9, 9, passed);
> + /* Not much can be checked for this descriptor */
> + break;
> + case 0x7: /* 6.4.3.5.2 DWord Address Space Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 23, 65535, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + gra = method_CRS_val32(&data[6]);
> + min = method_CRS_val32(&data[10]);
> + max = method_CRS_val32(&data[14]);
> + len = method_CRS_val32(&data[22]);
> +
> + method_test_CRS_mif_maf(fw, name, objname, data[4],
> + min, max, len, gra,
> + "64BitDWordAddrSpace",
> + types[0x7], passed);
> + break;
> + case 0x8: /* 6.4.3.5.3 Word Address Space Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 13, 65535, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + gra = method_CRS_val16(&data[6]);
> + min = method_CRS_val16(&data[8]);
> + max = method_CRS_val16(&data[10]);
> + len = method_CRS_val16(&data[14]);
> +
> + method_test_CRS_mif_maf(fw, name, objname, data[4],
> + min, max, len, gra,
> + "64BitWordAddrSpace",
> + types[0x8], passed);
> + break;
> + case 0x9: /* 6.4.3.6 Extended Interrupt Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 6, 65535, passed);
> + /* Not much can be checked for this descriptor */
> + break;
> + case 0xa: /* 6.4.3.5.1 QWord Address Space Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 43, 65535, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + gra = method_CRS_val64(&data[6]);
> + min = method_CRS_val64(&data[14]);
> + max = method_CRS_val64(&data[22]);
> + len = method_CRS_val64(&data[38]);
> +
> + method_test_CRS_mif_maf(fw, name, objname, data[4],
> + min, max, len, gra,
> + "64BitQWordAddrSpace",
> + types[0xa], passed);
> + break;
> + case 0xb: /* 6.4.3.5.4 Extended Address Space Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 53, 53, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + gra = method_CRS_val64(&data[8]);
> + min = method_CRS_val64(&data[16]);
> + max = method_CRS_val64(&data[24]);
> + len = method_CRS_val64(&data[40]);
> +
> + method_test_CRS_mif_maf(fw, name, objname, data[4],
> + min, max, len, gra,
> + "64BitExtAddrSpace",
> + types[0xb], passed);
> + break;
> + case 0xc: /* 6.4.3.8.1 GPIO Connection Descriptor */
> + method_test_CRS_large_size(fw, name, objname, data, length, 22, 65535, passed);
> + if (!*passed) /* Too short, abort */
> + break;
> + if (data[4] > 2) {
> + snprintf(tmp, sizeof(tmp), "Method%sGpioConnTypeInvalid", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s GPIO Connection Descriptor has an invalid "
> + "Connection Type 0x%" PRIx8 ".",
> + name, data[2]);
> + *passed = false;
> + fwts_advice(fw,
> + "The GPIO pin connection type is "
> + "not recognised. It should be either "
> + "0x00 (interrupt connection) or "
> + "0x01 (I/O connection). See table "
> + "6-189 in section 6.4.3.8.1 of the ACPI "
> + "specification.");
> + }
> + if ((data[9] > 0x03) && (data[9] < 0x80)) {
> + snprintf(tmp, sizeof(tmp), "Method%sGpioConnTypeInvalid", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s GPIO Connection Descriptor has an invalid "
> + "Pin Configuration Type 0x%" PRIx8 ".",
> + name, data[9]);
> + *passed = false;
> + fwts_advice(fw,
> + "The GPIO pin configuration type "
> + "is not recognised. It should be one of:"
> + "0x00 (default), 0x01 (pull-up), "
> + "0x02 (pull-down), 0x03 (no-pull), "
> + "0x80-0xff (vendor defined). See table "
> + "6-189 in section 6.4.3.8.1 of the ACPI "
> + "specification.");
> + }
> + break;
> + case 0xe: /* 6.4.3.8.2 Serial Bus Connection Descriptors */
> + method_test_CRS_large_size(fw, name, objname, data, length, 11, 65535, passed);
> + /* Don't care */
> + break;
> + default:
> + snprintf(tmp, sizeof(tmp), "Method%sUnkownLargeResourceItem", objname);
> + fwts_failed(fw, LOG_LEVEL_LOW, tmp,
> + "%s tag bits 6:0 is an undefined "
> + "large tag item name, value 0x%" PRIx8 ".",
> + name, tag_item);
> + fwts_advice(fw,
> + "A large resource data type tag (byte 0 of the "
> + "%s buffer) contains an undefined large tag "
> + "item 'name'. The %s buffer is therefore "
> + "undefined and can't be used. See section "
> + "'6.4.3 Large Resource Data Type' of the ACPI "
> + "specification, and also table 6-173.",
> + objname, objname);
> + *passed = false;
> + break;
> + }
> +
> + *tag = types[tag_item < 16 ? tag_item : 0];
> +}
> +
> +static void method_test_CRS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint8_t *data;
> + bool passed = true;
> + const char *tag = "Unknown";
> + char *objname = (char*)private;
> + char tmp[128];
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> + if (obj->Buffer.Pointer == NULL) {
> + snprintf(tmp, sizeof(tmp), "Method%sNullBuffer", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s returned a NULL buffer pointer.", name);
> + return;
> + }
> + if (obj->Buffer.Length < 1) {
> + snprintf(tmp, sizeof(tmp), "Method%sBufferTooSmall", objname);
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, tmp,
> + "%s should return a buffer of at least one byte in length.", name);
> + return;
> + }
> +
> + data = (uint8_t*)obj->Buffer.Pointer;
> +
> + if (data[0] & 128)
> + method_test_CRS_large_resource_items(fw, name, objname, data, obj->Buffer.Length, &passed, &tag);
> + else
> + method_test_CRS_small_resource_items(fw, name, objname, data, obj->Buffer.Length, &passed, &tag);
> +
> + if (passed)
> + fwts_passed(fw, "%s (%s) looks sane.", name, tag);
> +}
> +
> +static int method_test_CRS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_CRS", NULL, 0, method_test_CRS_return, "_CRS");
> +}
> +
> +static int method_test_PRS(fwts_framework *fw)
> +{
> + /* Re-use the _CRS checking on the returned buffer */
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PRS", NULL, 0, method_test_CRS_return, "_PRS");
> +}
> +
> +static void method_test_PRT_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i, j;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PRT", obj, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + ACPI_OBJECT *element;
> + pkg = &obj->Package.Elements[i];
> +
> + /* check size of sub-packages */
> + if (pkg->Package.Count != 4) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "Method_PRTSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to have 4"
> + "elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + /* check types of sub-packages' elements */
> + for (j = 0; j < 4; j++) {
> + element = &pkg->Package.Elements[j];
> +
> + if (j == 2) {
> + if (element->Type != ACPI_TYPE_INTEGER && element->Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "Method_PRTBadSubElementType",
> + "%s element %" PRIu32 " is not an integer or a NamePath.", name, j);
> + failed = true;
> + }
> + continue;
> + }
> +
> + if (element->Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "Method_PRTBadSubElementType",
> + "%s element %" PRIu32 " is not an integer.", name, j);
> + failed = true;
> + }
> + }
> +
> + /* check sub-packages's PCI address */
> + element = &pkg->Package.Elements[0];
> + if ((element->Integer.Value & 0xFFFF) != 0xFFFF) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "Method_PRTBadSubElement",
> + "%s element 0 is expected to end with 0xFFFF, got 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + /* check sub-packages's PCI pin number */
> + element = &pkg->Package.Elements[1];
> + if (element->Integer.Value > 3) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL,
> + "Method_PRTBadSubElement",
> + "%s element 1 is expected to be 0..3, got 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PRT(fwts_framework *fw)
> +{
> + /* Re-use the _CRS checking on the returned buffer */
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PRT", NULL, 0, method_test_PRT_return, "_PRT");
> +}
> +
> +static int method_test_DMA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DMA", NULL, 0, method_test_buffer_return, NULL);
> +}
> +
> +static void method_test_FIX_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + char tmp[8];
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* All elements in the package must be integers */
> + if (method_package_elements_all_type(fw, name, "_FIX", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + /* And they need to be valid IDs */
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (!method_valid_EISA_ID(
> + (uint32_t)obj->Package.Elements[i].Integer.Value,
> + tmp, sizeof(tmp))) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FIXInvalidElementValue",
> + "%s returned an integer "
> + "0x%8.8" PRIx64 " in package element "
> + "%" PRIu32 " that is not a valid "
> + "EISA ID.", name,
> + (uint64_t)obj->Integer.Value, i);
> + failed = true;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_FIX(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FIX", NULL, 0, method_test_FIX_return, NULL);
> +}
> +
> +/*
> + * Section 6.2.5 _DSD Device Specific Data, ACPI 5.1
> + */
> +static void method_test_DSD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Must be an even number of items in package */
> + if (obj->Package.Count & 1) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_DSDElementCount",
> + "There must be an even number of items in the %s "
> + "package, instead, got %" PRIu32 " elements.",
> + name, obj->Package.Count);
> + return;
> + }
> + for (i = 0; i < obj->Package.Count; i += 2) {
> + /* UUID should be a buffer */
> + if (!method_type_matches(obj->Package.Elements[i].Type, ACPI_TYPE_BUFFER)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DSDElementBuffer",
> + "%s package element %" PRIu32 " was not the expected "
> + "type '%s', was instead type '%s'.",
> + name, i,
> + method_type_name(ACPI_TYPE_BUFFER),
> + method_type_name(obj->Package.Elements[i].Type));
> + }
> +
> + /* Data should be a package */
> + if (!method_type_matches(obj->Package.Elements[i + 1].Type, ACPI_TYPE_PACKAGE)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DSDElementPackage",
> + "%s package element %" PRIu32 " was not the expected "
> + "type '%s', was instead type '%s'.",
> + name, i + 1,
> + method_type_name(ACPI_TYPE_PACKAGE),
> + method_type_name(obj->Package.Elements[i + 1].Type));
> + }
> + }
> +}
> +
> +static int method_test_DSD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DSD", NULL, 0, method_test_DSD_return, NULL);
> +}
> +
> +static int method_test_DIS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DIS", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_GSB(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GSB", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_HPP_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Must be 4 elements in the package */
> + if (method_package_count_equal(fw, name, "_HPP", obj, 4) != FWTS_OK)
> + return;
> +
> + /* All 4 elements in the package must be integers */
> + if (method_package_elements_all_type(fw, name, "_HPP", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_HPP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_HPP", NULL, 0, method_test_HPP_return, NULL);
> +}
> +
> +static int method_test_PXM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PXM", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/* Section 6.2.17 _CCA */
> +static int method_test_CCA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CCA", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 6.3 Device Insertion, Removal and Status Objects
> + */
> +static void method_test_EDL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_EDL",
> + obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_EDL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_EDL", NULL, 0, method_test_EDL_return, NULL);
> +}
> +
> +static int method_test_EJD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_EJD", NULL, 0, method_test_string_return, NULL);
> +}
> +
> +#define method_test_EJx(name) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + ACPI_OBJECT arg[1]; \
> + \
> + arg[0].Type = ACPI_TYPE_INTEGER; \
> + arg[0].Integer.Value = 1; \
> + \
> + return method_evaluate_method(fw, METHOD_OPTIONAL, \
> + # name, arg, 1, method_test_NULL_return, # name); \
> +}
> +
> +method_test_EJx(_EJ0)
> +method_test_EJx(_EJ1)
> +method_test_EJx(_EJ2)
> +method_test_EJx(_EJ3)
> +method_test_EJx(_EJ4)
> +
> +static int method_test_LCK(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_LCK", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_RMV(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_RMV",
> + NULL, 0, method_test_passed_failed_return, "_RMV");
> +}
> +
> +static void method_test_STA_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if ((obj->Integer.Value & 3) == 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_STAEnabledNotPresent",
> + "%s indicates that the device is enabled "
> + "but not present, which is impossible.", name);
> + failed = true;
> + }
> + if ((obj->Integer.Value & ~0x1f) != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_STAReservedBitsSet",
> + "%s is returning non-zero reserved "
> + "bits 5-31. These should be zero.", name);
> + failed = true;
> + }
> +
> + if (!failed)
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_STA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_STA",
> + NULL, 0, method_test_STA_return, "_STA");
> +}
> +
> +
> +/*
> + * Section 6.5 Other Objects and Controls
> + */
> +static int method_test_BBN(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_BBN",
> + NULL, 0, method_test_integer_return, "_BBN");
> +}
> +
> +static int method_test_BDN(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE, "_BDN",
> + NULL, 0, method_test_integer_return, "_BDN");
> +}
> +
> +static void method_test_DEP_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_DEP", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_DEP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DEP", NULL, 0, method_test_DEP_return, NULL);
> +}
> +
> +static int method_test_FIT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FIT", NULL, 0, method_test_buffer_return, NULL);
> +}
> +
> +static int method_test_DCK(fwts_framework *fw)
> +{
> + int i;
> +
> + for (i = 0; i <= 1; i++) { /* Undock, Dock */
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i;
> + if (method_evaluate_method(fw, METHOD_MOBILE, "_DCK", arg,
> + 1, method_test_passed_failed_return, "_DCK") != FWTS_OK)
> + break;
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +static int method_test_INI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_INI", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_SEG_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if ((obj->Integer.Value & 0xffff0000)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SEGIllegalReserved",
> + "%s returned value 0x%8.8" PRIx64 " and some of the "
> + "upper 16 reserved bits are set when they "
> + "should in fact be zero.",
> + name, (uint64_t)obj->Integer.Value);
> + } else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_SEG(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_SEG",
> + NULL, 0, method_test_SEG_return, "_SEG");
> +}
> +
> +static void method_test_GLK_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(private);
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_INTEGER:
> + if (obj->Integer.Value == 0 || obj->Integer.Value == 1)
> + fwts_passed(fw, "%s returned an integer 0x%8.8" PRIx64,
> + name, (uint64_t)obj->Integer.Value);
> + else
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "MethodGLKInvalidInteger",
> + "%s returned an invalid integer 0x%8.8" PRIx64,
> + name, (uint64_t)obj->Integer.Value);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_GLKBadReturnType",
> + "%s did not return an integer.", name);
> + break;
> + }
> +}
> +
> +static int method_test_GLK(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_GLK",
> + NULL, 0, method_test_GLK_return, "_GLK");
> +}
> +
> +/*
> + * Section 7.1 Declaring a Power Resource Object
> + */
> +static int method_test_ON_(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ON_", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_OFF(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_OFF", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +
> +/*
> + * Section 7.2 Device Power Management Objects
> + */
> +static int method_test_DSW(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[3];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 0;
> + arg[2].Type = ACPI_TYPE_INTEGER;
> + arg[2].Integer.Value = 3;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_DSW",
> + arg, 3, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_PSx(fwts_framework *fw, char *name)
> +{
> + /*
> + * iASL (ACPICA commit 6922796cfdfca041fdb96dc9e3918cbc7f43d830)
> + * checks that _PS0 must exist if we have _PS1, _PS2, _PS3
> + * so check this here too.
> + */
> + if ((fwts_acpi_object_exists(name) != NULL) &&
> + (fwts_acpi_object_exists("_PS0") == NULL)) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_PSx",
> + "%s requires that the _PS0 "
> + "control method must also exist, however, "
> + "it was not found.", name);
> + }
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + name, NULL, 0, method_test_NULL_return, name);
> +}
> +
> +static void method_test_PRW_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_min(fw, name, "_PRW", obj, 2) != FWTS_OK)
> + return;
> +
> + if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER &&
> + obj->Package.Elements[0].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWBadPackageReturnType",
> + "%s element 0 is not an integer or an package.", name);
> + failed = true;
> + }
> +
> + if (obj->Package.Elements[0].Type == ACPI_TYPE_PACKAGE) {
> + ACPI_OBJECT *pkg;
> + pkg = &obj->Package.Elements[0];
> + if (pkg->Package.Count != 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWSubPackageElementCount",
> + "%s sub-package 0 was expected to have 2"
> + "elements, got %" PRIu32 " elements instead.",
> + name, pkg->Package.Count);
> + failed = true;
> + }
> +
> + if (pkg->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWBadSubPackageElementType",
> + "%s sub-package 0 element 0 is not "
> + "a reference.",name);
> + failed = true;
> + }
> +
> + if (pkg->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWBadSubPackageElementType",
> + "%s sub-package 0 element 0 is not "
> + "an integer.",name);
> + failed = true;
> + }
> + }
> +
> + if (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWBadPackageReturnType",
> + "%s element 1 is not an integer.", name);
> + failed = true;
> + }
> +
> + for (i = 2; i < obj->Package.Count - 1; i++) {
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRWBadPackageReturnType",
> + "%s package %" PRIu32
> + " element 0 is not a reference.",
> + name, i);
> + failed = true;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PRW(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PRW", NULL, 0, method_test_PRW_return, NULL);
> +}
> +
> +static int method_test_PS0(fwts_framework *fw)
> +{
> + /*
> + * iASL (ACPICA commit 6922796cfdfca041fdb96dc9e3918cbc7f43d830)
> + * checks that one of _PS1, _PS2, _PS3 must exist if _PS0 exists.
> + */
> + if (fwts_acpi_object_exists("_PS0") != NULL) {
> + bool ok = false;
> + int i;
> +
> + for (i = 1; i < 4; i++) {
> + char name[5];
> +
> + snprintf(name, sizeof(name), "_PS%1d", i);
> + if (fwts_acpi_object_exists(name) != NULL) {
> + ok = true;
> + break;
> + }
> + }
> + if (!ok) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_PS0",
> + "_PS0 requires that one of the _PS1, _PS2, _PS3 "
> + "control methods must also exist, however, "
> + "none were found.");
> + }
> + }
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_PS0",
> + NULL, 0, method_test_NULL_return, "_PS0");
> +}
> +
> +static int method_test_PS1(fwts_framework *fw)
> +{
> + return method_test_PSx(fw, "_PS1");
> +}
> +
> +static int method_test_PS2(fwts_framework *fw)
> +{
> + return method_test_PSx(fw, "_PS2");
> +}
> +
> +static int method_test_PS3(fwts_framework *fw)
> +{
> + return method_test_PSx(fw, "_PS3");
> +}
> +
> +static int method_test_PSC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSC", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_PSE(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSE", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_power_resources_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + char *objname = (char *)private;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, objname,
> + obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +#define method_test_POWER(name) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + return method_evaluate_method(fw, METHOD_OPTIONAL, \
> + # name, NULL, 0, method_test_power_resources_return, # name);\
> +}
> +
> +method_test_POWER(_PR0)
> +method_test_POWER(_PR1)
> +method_test_POWER(_PR2)
> +method_test_POWER(_PR3)
> +method_test_POWER(_PRE)
> +
> +static int method_test_PSW(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSW", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +#define method_test_SxD(name) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + return method_evaluate_method(fw, METHOD_OPTIONAL, \
> + # name, NULL, 0, method_test_integer_return, # name); \
> +}
> +
> +method_test_SxD(_S1D)
> +method_test_SxD(_S2D)
> +method_test_SxD(_S3D)
> +method_test_SxD(_S4D)
> +
> +#define method_test_SxW(name) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + return method_evaluate_method(fw, METHOD_OPTIONAL, \
> + # name, NULL, 0, method_test_integer_return, # name); \
> +}
> +
> +method_test_SxW(_S0W)
> +method_test_SxW(_S1W)
> +method_test_SxW(_S2W)
> +method_test_SxW(_S3W)
> +method_test_SxW(_S4W)
> +
> +static int method_test_RST(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_RST", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_PRR_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_PRR", obj, 1) != FWTS_OK)
> + return;
> +
> + if (obj->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PRRElementType",
> + "%s returned a package that does not contain "
> + "a reference.", name);
> + return;
> + }
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PRR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PRR", NULL, 0, method_test_PRR_return, NULL);
> +}
> +
> +static int method_test_IRC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_IRC", NULL, 0, method_test_NULL_return, NULL);
> +}
> +
> +/*
> + * Section 7.3 OEM Supplied System-Level Control Methods
> + */
> +static void method_test_Sx__return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /*
> + * The ACPI spec states it should have 1 integer, with the
> + * values packed into each byte. However, nearly all BIOS
> + * vendors don't do this, instead they return a package of
> + * 2 or more integers with each integer lower byte containing
> + * the data we are interested in. The kernel handles this
> + * the non-compliant way. Doh. See drivers/acpi/acpica/hwxface.c
> + * for the kernel implementation and also
> + * source/components/hardware/hwxface.c in the reference ACPICA
> + * sources.
> + */
> +
> + /* Something is really wrong if we don't have any elements in _Sx_ */
> + if (obj->Package.Count < 1) {
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_SxElementCount",
> + "The kernel expects a package of at least two "
> + "integers, and %s only returned %" PRIu32
> + " elements in the package.",
> + name, obj->Package.Count);
> + return;
> + }
> +
> + /*
> + * Oh dear, BIOS is conforming to the spec but won't work in
> + * Linux
> + */
> + if (obj->Package.Count == 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SxElementCount",
> + "The ACPI specification states that %s should "
> + "return a package of a single integer which "
> + "this firmware does do. However, nearly all of the "
> + "BIOS vendors return the values in the low 8 bits "
> + "in a package of 2 to 4 integers which is not "
> + "compliant with the specification BUT is the way "
> + "that the ACPICA reference engine and the kernel "
> + "expect. So, while this is conforming to the ACPI "
> + "specification it will in fact not work in the "
> + "Linux kernel.", name);
> + return;
> + }
> +
> + /* Yes, we really want integers! */
> + if ((obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) ||
> + (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SxElementType",
> + "%s returned a package that did not contain "
> + "an integer.", name);
> + return;
> + }
> +
> + if (obj->Package.Elements[0].Integer.Value & 0xffffff00) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SxElementValue",
> + "%s package element 0 had upper 24 bits "
> + "of bits that were non-zero.", name);
> + failed = true;
> + }
> +
> + if (obj->Package.Elements[1].Integer.Value & 0xffffff00) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SxElementValue",
> + "%s package element 1 had upper 24 bits "
> + "of bits that were non-zero.", name);
> + failed = true;
> + }
> +
> + fwts_log_info(fw, "%s PM1a_CNT.SLP_TYP value: 0x%8.8" PRIx64, name,
> + (uint64_t)obj->Package.Elements[0].Integer.Value);
> + fwts_log_info(fw, "%s PM1b_CNT.SLP_TYP value: 0x%8.8" PRIx64, name,
> + (uint64_t)obj->Package.Elements[1].Integer.Value);
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +#define method_test_Sx_(name) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + return method_evaluate_method(fw, METHOD_OPTIONAL, \
> + # name, NULL, 0, method_test_Sx__return, # name); \
> +}
> +
> +method_test_Sx_(_S0_)
> +method_test_Sx_(_S1_)
> +method_test_Sx_(_S2_)
> +method_test_Sx_(_S3_)
> +method_test_Sx_(_S4_)
> +method_test_Sx_(_S5_)
> +
> +static int method_test_SWS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SWS", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 8.4 Declaring Processors
> + */
> +static void method_test_CPC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint8_t revision;
> +
> + static fwts_package_element elementsv1[] = {
> + { ACPI_TYPE_INTEGER, "Number of Entries" },
> + { ACPI_TYPE_INTEGER, "Revision" },
> + { ACPI_TYPE_INTBUF, "Highest Performance" },
> + { ACPI_TYPE_INTBUF, "Nominal Performance" },
> + { ACPI_TYPE_INTBUF, "Lowest Non Linear Performance" },
> + { ACPI_TYPE_INTBUF, "Lowest Performance" },
> + { ACPI_TYPE_BUFFER, "Guaranteed Performance Register" },
> + { ACPI_TYPE_BUFFER, "Desired Performance Register" },
> + { ACPI_TYPE_BUFFER, "Minimum Performance Register" },
> + { ACPI_TYPE_BUFFER, "Maximum Performance Register" },
> + { ACPI_TYPE_BUFFER, "Performance Reduction Tolerance Register" },
> + { ACPI_TYPE_BUFFER, "Timed Window Register" },
> + { ACPI_TYPE_INTBUF, "Counter Wraparound Time" },
> + { ACPI_TYPE_BUFFER, "Nominal Counter Register" },
> + { ACPI_TYPE_BUFFER, "Delivered Counter Register" },
> + { ACPI_TYPE_BUFFER, "Performance Limited Register" },
> + { ACPI_TYPE_BUFFER, "Enable Register" }
> + };
> +
> + static fwts_package_element elementsv2[] = {
> + { ACPI_TYPE_INTEGER, "Number of Entries" },
> + { ACPI_TYPE_INTEGER, "Revision" },
> + { ACPI_TYPE_INTBUF, "Highest Performance" },
> + { ACPI_TYPE_INTBUF, "Nominal Performance" },
> + { ACPI_TYPE_INTBUF, "Lowest Non Linear Performance" },
> + { ACPI_TYPE_INTBUF, "Lowest Performance" },
> + { ACPI_TYPE_BUFFER, "Guaranteed Performance Register" },
> + { ACPI_TYPE_BUFFER, "Desired Performance Register" },
> + { ACPI_TYPE_BUFFER, "Minimum Performance Register" },
> + { ACPI_TYPE_BUFFER, "Maximum Performance Register" },
> + { ACPI_TYPE_BUFFER, "Performance Reduction Tolerance Register" },
> + { ACPI_TYPE_BUFFER, "Timed Window Register" },
> + { ACPI_TYPE_INTBUF, "Counter Wraparound Time" },
> + { ACPI_TYPE_BUFFER, "Reference Performance Counter Register" },
> + { ACPI_TYPE_BUFFER, "Delivered Performance Counter Register" },
> + { ACPI_TYPE_BUFFER, "Performance Limited Register" },
> + { ACPI_TYPE_BUFFER, "CPPC Enable Register" },
> + { ACPI_TYPE_INTBUF, "Autonomous Selection Enable" },
> + { ACPI_TYPE_BUFFER, "Autonomous Activity Window Register" },
> + { ACPI_TYPE_BUFFER, "Energy Performance Preference Register" },
> + { ACPI_TYPE_INTBUF, "Reference Performance" }
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + revision = obj->Package.Elements[1].Integer.Value;
> +
> + if (revision == 1) { // acpi 5.0
> + /* Something is really wrong if we don't have any elements in _CPC */
> + if (method_package_count_equal(fw, name, "_CPC", obj, 17) != FWTS_OK)
> + return;
> +
> + /* For now, just check types */
> + if (method_package_elements_type(fw, name, "_CPC", obj, elementsv1, 17) != FWTS_OK)
> + return;
> + } else if (revision == 2) { // acpi 5.1 and later
> + /* Something is really wrong if we don't have any elements in _CPC */
> + if (method_package_count_equal(fw, name, "_CPC", obj, 21) != FWTS_OK)
> + return;
> +
> + /* For now, just check types */
> + if (method_package_elements_type(fw, name, "_CPC", obj, elementsv2, 21) != FWTS_OK)
> + return;
> + } else {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_CPCBadRevision",
> + "_CPC's _REV is incorrect, "
> + "expecting 1 or 2, got 0x%" PRIx8 , revision);
> +
> + return;
> + }
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_CPC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_CPC", NULL,
> + 0, method_test_CPC_return, NULL);
> +}
> +
> +static void method_test_CSD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Something is really wrong if we don't have any elements in _CSD */
> + if (method_package_count_min(fw, name, "_CSD", obj, 1) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + if (method_package_elements_all_type(fw, name, "_CSD",
> + obj, ACPI_TYPE_PACKAGE) != FWTS_OK) {
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + /*
> + * Currently we expect a package of 6 integers.
> + */
> + if (pkg->Package.Count != 6) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSDSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 5 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + for (j = 0; j < 6; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSDSubPackageElementCount",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> +
> + /* Element 0 must equal the number elements in the package */
> + if (pkg->Package.Elements[0].Integer.Value != pkg->Package.Count) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSDSubPackageElement0",
> + "%s sub-package %d element 0 (NumEntries) "
> + "was expected to have value 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> + /* Element 1 should contain zero */
> + if (pkg->Package.Elements[1].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSDSubPackageElement1",
> + "%s sub-package %d element 1 (Revision) "
> + "was expected to have value 1, instead it "
> + "was 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[1].Integer.Value);
> + failed = true;
> + }
> + /* Element 3 should contain 0xfc..0xfe */
> + if ((pkg->Package.Elements[3].Integer.Value != 0xfc) &&
> + (pkg->Package.Elements[3].Integer.Value != 0xfd) &&
> + (pkg->Package.Elements[3].Integer.Value != 0xfe)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSDSubPackageElement1",
> + "%s sub-package %d element 3 (CoordType) "
> + "was expected to have value 0xfc (SW_ALL), "
> + "0xfd (SW_ANY) or 0xfe (HW_ALL), instead it "
> + "was 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[3].Integer.Value);
> + failed = true;
> + }
> + /* Element 4 number of processors, skip check */
> + /* Element 5 index, check */
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_CSD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CSD", NULL, 0, method_test_CSD_return, NULL);
> +}
> +
> +static void method_test_CST_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i, j;
> + bool failed = false;
> + bool *cst_elements_ok;
> + bool an_element_ok = false;
> +
> + typedef struct {
> + const uint32_t type;
> + const char *name;
> + } cstate_info;
> +
> + static const cstate_info cstate_types[] = {
> + { ACPI_TYPE_BUFFER, "buffer" },
> + { ACPI_TYPE_INTEGER, "integer" },
> + { ACPI_TYPE_INTEGER, "integer" },
> + { ACPI_TYPE_INTEGER, "integer" },
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (obj == NULL)
> + return;
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* _CST has at least two elements */
> + if (method_package_count_min(fw, name, "_CST", obj, 2) != FWTS_OK)
> + return;
> +
> + /* Element 1 must be an integer */
> + if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_CSTElement0NotInteger",
> + "%s should return package with element zero being an integer "
> + "count of the number of C state sub-packages.", name);
> + return;
> + }
> +
> + if (obj->Package.Elements[0].Integer.Value != obj->Package.Count - 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_CSTElement0CountMismatch",
> + "%s should return package with element zero containing "
> + "the number of C state sub-elements. However, _CST has "
> + "%" PRIu32 " returned C state sub-elements yet _CST "
> + "reports it has %" PRIu64 " C states.",
> + name, obj->Package.Count - 1,
> + (uint64_t)obj->Package.Elements[0].Integer.Value);
> + return;
> + }
> +
> + cst_elements_ok = calloc(obj->Package.Count, sizeof(bool));
> + if (cst_elements_ok == NULL) {
> + fwts_log_error(fw, "Cannot allocate an array. Test aborted.");
> + return;
> + }
> +
> + /* Could be one or more packages */
> + for (i = 1; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> +
> + cst_elements_ok[i] = true;
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSTElementType",
> + "%s package element %" PRIu32 " was not a package.",
> + name, i);
> + cst_elements_ok[i] = false;
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + pkg = &obj->Package.Elements[i];
> +
> + if (pkg->Package.Count != 4) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSTElementPackageCountInvalid",
> + "%s package element %" PRIu32 " should have "
> + "4 elements, instead it had %" PRIu32 ".",
> + name, i, pkg->Package.Count);
> + cst_elements_ok[i] = false;
> + failed = true;
> + continue;
> + }
> +
> + for (j = 0; j < 4; j++) {
> + if (pkg->Package.Elements[j].Type != cstate_types[j].type) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSTCStatePackageElementInvalidType",
> + "%s C-State package %" PRIu32 " element %" PRIu32
> + " was not a %s.",
> + name, i, j, cstate_types[j].name);
> + cst_elements_ok[i] = false;
> + failed = true;
> + }
> + }
> +
> + /* Some very simple sanity checks on Register Resource Buffer */
> + if (pkg->Package.Elements[0].Type == ACPI_TYPE_BUFFER) {
> + if (pkg->Package.Elements[0].Buffer.Pointer == NULL) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSTCStateRegisterResourceBufferNull",
> + "%s C-State package %" PRIu32 " has a NULL "
> + "Register Resource Buffer", name, i);
> + failed = true;
> + } else {
> + uint8_t *data = (uint8_t *)pkg->Package.Elements[0].Buffer.Pointer;
> + size_t length = (size_t)pkg->Package.Elements[0].Buffer.Length;
> +
> + if (data[0] != 0x82) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CSTCStateResourceBufferWrongType",
> + "%s C-State package %" PRIu32 " has a Resource "
> + "type 0x%2.2" PRIx8 ", however, was expecting a Register "
> + "Resource type 0x82.", name, i, data[0]);
> + failed = true;
> + }
> + else {
> + bool passed = true;
> + method_test_CRS_large_size(fw, name, "_CST", data, length, 12, 12, &passed);
> + if (!passed)
> + failed = true;
> + }
> + }
> + }
> +
> + if (cst_elements_ok[i])
> + an_element_ok = true;
> + }
> +
> + /* Now dump out per CPU C-state information */
> + if (an_element_ok) {
> + fwts_log_info_verbatim(fw, "%s values:", name);
> + fwts_log_info_verbatim(fw, "# C-State Latency Power");
> + fwts_log_info_verbatim(fw, " (us) (mW)");
> + for (i = 1; i < obj->Package.Count; i++){
> + if (cst_elements_ok[i]) {
> + ACPI_OBJECT *pkg = &obj->Package.Elements[i];
> + fwts_log_info_verbatim(fw,
> + "%2" PRIu32 " C%" PRIu64 " %6" PRIu64 " %6" PRIu64,
> + i,
> + (uint64_t)pkg->Package.Elements[1].Integer.Value,
> + (uint64_t)pkg->Package.Elements[2].Integer.Value,
> + (uint64_t)pkg->Package.Elements[3].Integer.Value);
> + } else {
> + fwts_log_info_verbatim(fw,
> + "%2" PRIu32 " -- ----- -----", i);
> + }
> + }
> + }
> +
> + free(cst_elements_ok);
> +
> + if (!failed)
> + method_passed_sane(fw, name, "values");
> +}
> +
> +static int method_test_CST(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CST", NULL, 0, method_test_CST_return, NULL);
> +}
> +
> +static void method_test_PCT_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Something is really wrong if we don't have any elements in _PCT */
> + if (method_package_count_min(fw, name, "_PCT", obj, 2) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PCT",
> + obj, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PCT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_PCT", NULL,
> + 0, method_test_PCT_return, NULL);
> +}
> +
> +static void method_test_PSS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> + uint32_t max_freq = 0;
> + uint32_t prev_power = 0;
> + bool max_freq_valid = false;
> + bool dump_elements = false;
> + bool *element_ok;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Something is really wrong if we don't have any elements in _PSS */
> + if (method_package_count_min(fw, name, "_PSS", obj, 1) != FWTS_OK)
> + return;
> +
> + element_ok = calloc(obj->Package.Count, sizeof(bool));
> + if (element_ok == NULL) {
> + fwts_log_error(fw, "Cannot allocate an array. Test aborted.");
> + return;
> + }
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pstate;
> +
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSSElementType",
> + "%s package element %" PRIu32
> + " was not a package.", name, i);
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + pstate = &obj->Package.Elements[i];
> + if (pstate->Package.Count != 6) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSSSubPackageElementCount",
> + "%s P-State sub-package %" PRIu32
> + " was expected to "
> + "have 6 elements, got %" PRIu32 " elements instead.",
> + name, i, obj->Package.Count);
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + /* Elements need to be all ACPI integer types */
> + if ((pstate->Package.Elements[0].Type != ACPI_TYPE_INTEGER) ||
> + (pstate->Package.Elements[1].Type != ACPI_TYPE_INTEGER) ||
> + (pstate->Package.Elements[2].Type != ACPI_TYPE_INTEGER) ||
> + (pstate->Package.Elements[3].Type != ACPI_TYPE_INTEGER) ||
> + (pstate->Package.Elements[4].Type != ACPI_TYPE_INTEGER) ||
> + (pstate->Package.Elements[5].Type != ACPI_TYPE_INTEGER)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSSSubPackageElementType",
> + "%s P-State sub-package %" PRIu32 " was expected to "
> + "have 6 Integer elements but didn't", name, i);
> + failed = true;
> + continue;
> + }
> +
> + /*
> + * Parses OK, so this element can be dumped out
> + */
> + element_ok[i] = true;
> + dump_elements = true;
> +
> + /*
> + * Collect maximum frequency. The sub-packages are sorted in
> + * descending power dissipation order, so one would assume that
> + * the highest frequency is first. However, it is not clear
> + * from the ACPI spec that this is necessarily an assumption we
> + * should make, so instead we should probably scan through all
> + * the valid sub-packages and find the highest frequency.
> + */
> + if (max_freq < pstate->Package.Elements[0].Integer.Value) {
> + max_freq = pstate->Package.Elements[0].Integer.Value;
> + max_freq_valid = true;
> + }
> +
> + /* Sanity check descending power dissipation levels */
> + if ((i > 0) && (prev_power != 0) &&
> + (pstate->Package.Elements[1].Integer.Value > prev_power)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSSSubPackagePowerNotDecending",
> + "%s P-State sub-package %" PRIu32 " has a larger "
> + "power dissipation setting than the previous "
> + "sub-package.", name, i);
> + fwts_advice(fw,
> + "_PSS P-States must be ordered in decending "
> + "order of power dissipation, so that the "
> + "zero'th entry has the highest power "
> + "dissipation level and the Nth has the "
> + "lowest.");
> + failed = true;
> + }
> + prev_power = pstate->Package.Elements[1].Integer.Value;
> + }
> +
> + /*
> + * If we have some valid data then dump it out, it is useful to see
> + */
> + if (dump_elements) {
> + fwts_log_info_verbatim(fw, "%s values:", name);
> + fwts_log_info_verbatim(fw, "P-State Freq Power Latency Bus Master");
> + fwts_log_info_verbatim(fw, " (MHz) (mW) (us) Latency (us)");
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pstate = &obj->Package.Elements[i];
> + if (element_ok[i]) {
> + fwts_log_info_verbatim(fw, " %3d %7" PRIu64 " %8" PRIu64
> + " %5" PRIu64 " %5" PRIu64,
> + i,
> + (uint64_t)pstate->Package.Elements[0].Integer.Value,
> + (uint64_t)pstate->Package.Elements[1].Integer.Value,
> + (uint64_t)pstate->Package.Elements[2].Integer.Value,
> + (uint64_t)pstate->Package.Elements[3].Integer.Value);
> + } else {
> + fwts_log_info_verbatim(fw,
> + " %3d ---- ----- -- -- (invalid)", i);
> + }
> + }
> + }
> +
> + free(element_ok);
> +
> + /*
> + * Sanity check maximum frequency. We could also check the DMI data
> + * for a BIOS date (but this can be wrong) or check the CPU identity
> + * (which requires adding in new CPU identity checks) to make a decision
> + * on when it is reasonable to assume a CPU is modern and hence clocked
> + * incorrectly. For now, just flag up a low level error that the
> + * frequency looks rather low rather than try to be intelligent (and
> + * possibly make a mistake). I'd rather flag up a few false positives
> + * on older machines than miss flagging up bad _PSS settings on new
> + * machines.
> + */
> + if (max_freq_valid && max_freq < 1000) {
> + fwts_failed(fw, LOG_LEVEL_LOW, "Method_PSSSubPackageLowFreq",
> + "Maximum CPU frequency is %dHz and this is low for "
> + "a modern processor. This may indicate the _PSS "
> + "P-States are incorrect\n", max_freq);
> + fwts_advice(fw,
> + "The _PSS P-States are used by the Linux CPU frequency "
> + "driver to set the CPU frequencies according to system "
> + "load. Sometimes the firmware sets these incorrectly "
> + "and the machine runs at a sub-optimal speed. One can "
> + "view the firmware defined CPU frequencies via "
> + "/sys/devices/system/cpu/cpu*/cpufreq/"
> + "scaling_available_frequencies");
> + failed = true;
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PSS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL, "_PSS", NULL, 0, method_test_PSS_return, NULL);
> +}
> +
> +static int method_test_PPC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PPC", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_PPE(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PPE", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_PSD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PSD", obj, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + pkg = &obj->Package.Elements[i];
> + if (pkg->Package.Count != 5) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSDSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 5 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + /* Elements in Sub-packages are integers */
> + for (j = 0; j < 5; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSDBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PSD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSD", NULL, 0, method_test_PSD_return, NULL);
> +}
> +
> +static int method_test_PDL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PDL", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +
> +static void method_test_PTC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PTC", obj, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_PTC", obj, 2) != FWTS_OK)
> + return;
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_RESOURCE *resource;
> + ACPI_STATUS status;
> + ACPI_OBJECT *element_buf = &obj->Package.Elements[i];
> +
> + status = AcpiBufferToResource(element_buf->Buffer.Pointer, element_buf->Buffer.Length, &resource);
> + if (ACPI_FAILURE(status)) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_PTCBadElement",
> + "%s should contain only Resource Descriptors", name);
> + continue;
> + }
> +
> + if (resource->Type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_PTCBadElement",
> + "%s should contain only Resource Type 16, got %" PRIu32 "\n",
> + name, resource->Type);
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PTC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PTC", NULL, 0, method_test_PTC_return, NULL);
> +}
> +
> +static int method_test_TDL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TDL", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_TPC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TPC", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_TSD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Something is really wrong if we don't have any elements in _TSD */
> + if (method_package_count_min(fw, name, "_TSD", obj, 1) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDElementType",
> + "%s package element %" PRIu32
> + " was not a package.", name, i);
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + /*
> + * Currently we expect a package of 5 integers.
> + */
> + if (pkg->Package.Count != 5) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 5 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + for (j = 0; j < 5; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElementCount",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.", name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> +
> + /* Element 0 must equal the number elements in the package */
> + if (pkg->Package.Elements[0].Integer.Value != pkg->Package.Count) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElement0",
> + "%s sub-package %" PRIu32
> + " element 0 (NumEntries) "
> + "was expected to have value 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> + /* Element 1 should contain zero */
> + if (pkg->Package.Elements[1].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElement1",
> + "%s sub-package %" PRIu32
> + " element 1 (Revision) "
> + "was expected to have value 1, instead it "
> + "was 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[1].Integer.Value);
> + failed = true;
> + }
> + /* Element 3 should contain 0xfc..0xfe */
> + if ((pkg->Package.Elements[3].Integer.Value != 0xfc) &&
> + (pkg->Package.Elements[3].Integer.Value != 0xfd) &&
> + (pkg->Package.Elements[3].Integer.Value != 0xfe)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElement1",
> + "%s sub-package %" PRIu32
> + " element 3 (CoordType) "
> + "was expected to have value 0xfc (SW_ALL), "
> + "0xfd (SW_ANY) or 0xfe (HW_ALL), instead it "
> + "was 0x%" PRIx64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[3].Integer.Value);
> + failed = true;
> + }
> + /* Element 4 number of processors, skip check */
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_TSD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TSD", NULL, 0, method_test_TSD_return, NULL);
> +}
> +
> +static void method_test_TSS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> + bool *tss_elements_ok;
> + bool an_element_ok = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Something is really wrong if we don't have any elements in _TSS */
> + if (method_package_count_min(fw, name, "_TSS", obj, 1) != FWTS_OK)
> + return;
> +
> + tss_elements_ok = calloc(obj->Package.Count, sizeof(bool));
> + if (tss_elements_ok == NULL) {
> + fwts_log_error(fw, "Cannot allocate an array. Test aborted.");
> + return;
> + }
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> +
> + tss_elements_ok[i] = true;
> +
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSSElementType",
> + "%s package element %" PRIu32
> + " was not a package.", name, i);
> + tss_elements_ok[i] = false;
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + /*
> + * We expect a package of 5 integers.
> + */
> + if (pkg->Package.Count != 5) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSSSubPackageElementCount",
> + "%s sub-package %" PRIu32
> + " was expected to have 5 elements, "
> + "got %" PRIu32" elements instead.",
> + name, i, pkg->Package.Count);
> + tss_elements_ok[i] = false;
> + failed = true;
> + continue; /* Skip processing sub-package */
> + }
> +
> + for (j = 0; j < 5; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSSSubPackageElementCount",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.", name, i, j);
> + tss_elements_ok[i] = false;
> + }
> + }
> + if (!tss_elements_ok[i]) {
> + failed = true;
> + continue;
> + }
> +
> + /* At least one element is OK, so remember that */
> + an_element_ok = true;
> +
> + /* Element 0 must be 1..100 */
> + if ((pkg->Package.Elements[0].Integer.Value < 1) ||
> + (pkg->Package.Elements[0].Integer.Value > 100)) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TSDSubPackageElement0",
> + "%s sub-package %" PRIu32 " element 0"
> + "was expected to have value 1..100, instead "
> + "was %" PRIu64 ".",
> + name, i,
> + (uint64_t)pkg->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> + /* Skip checking elements 1..4 */
> + }
> +
> + /* Summary info */
> + if (an_element_ok) {
> + fwts_log_info_verbatim(fw, "%s values:", name);
> + fwts_log_info_verbatim(fw, "T-State CPU Power Latency Control Status");
> + fwts_log_info_verbatim(fw, " Freq (mW) (usecs)");
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (tss_elements_ok[i]) {
> + ACPI_OBJECT *pkg = &obj->Package.Elements[i];
> +
> + fwts_log_info_verbatim(fw,
> + " %3d %3" PRIu64 "%% %7" PRIu64 " %7" PRIu64
> + " %2.2" PRIx64 " %2.2" PRIx64, i,
> + (uint64_t)pkg->Package.Elements[0].Integer.Value,
> + (uint64_t)pkg->Package.Elements[1].Integer.Value,
> + (uint64_t)pkg->Package.Elements[2].Integer.Value,
> + (uint64_t)pkg->Package.Elements[3].Integer.Value,
> + (uint64_t)pkg->Package.Elements[4].Integer.Value);
> + } else {
> + fwts_log_info_verbatim(fw,
> + " %3d ---- ----- ----- -- -- (invalid)", i);
> + }
> + }
> + }
> + free(tss_elements_ok);
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_TSS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TSS", NULL, 0, method_test_TSS_return, NULL);
> +}
> +
> +/*
> + * Section 8.4.4 Lower Power Idle States
> +*/
> +
> +static void method_test_LPI_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i, j;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_min(fw, name, "_LPI", obj, 3) != FWTS_OK)
> + return;
> +
> + /* first 3 elements are integers, and rests are packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (i < 3) {
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadElementType",
> + "%s element %" PRIu32 " is not an integer.", name, i);
> + failed = true;
> + continue;
> + }
> +
> + if (i == 0) {
> + if (obj->Package.Elements[i].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadRevision",
> + "%s: Expected Revision to be 0, "
> + "got 0x%4.4" PRIx64 ".", name,
> + (uint64_t)obj->Package.Elements[i].Integer.Value);
> + failed = true;
> + }
> + } else if (i == 2) {
> + if (obj->Package.Elements[i].Integer.Value != obj->Package.Count - 3) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadCount",
> + "%s Count reports %" PRIu32 ", but there are %" PRIu32 " sub-packages.",
> + name, (uint32_t) obj->Package.Elements[i].Integer.Value,
> + obj->Package.Count - 3);
> + failed = true;
> + }
> + }
> + } else {
> + ACPI_OBJECT *pkg;
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadElementType",
> + "%s element %" PRIu32 " is not a package.", name, i);
> + failed = true;
> + continue;
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + for (j = 0; j < pkg->Package.Count; j++) {
> + switch (j) {
> + case 0 ... 5:
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadESublementType",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " is not "
> + "an integer.", name, i, j);
> + failed = true;
> + }
> + break;
> + case 6:
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER &&
> + pkg->Package.Elements[j].Type != ACPI_TYPE_BUFFER) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadESublementType",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " is not "
> + "a buffer or an integer.", name, i, j);
> + failed = true;
> + }
> + break;
> + case 7 ... 8:
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_BUFFER) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadESublementType",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " is not "
> + "a buffer.", name, i, j);
> + failed = true;
> + }
> + break;
> + case 9:
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_STRING) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadESublementType",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " is not "
> + "a string.", name, i, j);
> + failed = true;
> + }
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_LPIBadESublement",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " should have "
> + "9 elements, got .", name, i, j+1);
> + failed = true;
> + break;
> + }
> + }
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_LPI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_LPI", NULL, 0, method_test_LPI_return, NULL);
> +}
> +
> +static void method_test_RDI_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i, j;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* First element is Revision */
> + if (obj->Package.Elements[0].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_RDIBadID",
> + "%s: Expected Revision to be 0, "
> + "got 0x%4.4" PRIx64 ".", name,
> + (uint64_t)obj->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> +
> + /* The rest of elements are packages with references */
> + for (i = 1; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + pkg = &obj->Package.Elements[i];
> +
> + if (pkg->Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_RDIBadElementType",
> + "%s element %" PRIu32 " is not a package.", name, i);
> + failed = true;
> + continue;
> + }
> +
> + for (j = 0; j < pkg->Package.Count; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_RDIBadESublementType",
> + "%s sub-package %" PRIu32 " element %" PRIu32 " is not "
> + "a Reference.", name, i, j);
> + failed = true;
> + }
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_RDI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_RDI", NULL, 0, method_test_RDI_return, NULL);
> +}
> +
> +/*
> + * Section 8.5 Processor Aggregator Device
> + */
> +
> +static void method_test_PUR_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + static fwts_package_element elements[] = {
> + { ACPI_TYPE_INTEGER, "RevisionID" },
> + { ACPI_TYPE_INTEGER, "NumProcessors" },
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_PUR", obj, 2) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_type(fw, name, "_PUR", obj, elements, 2) != FWTS_OK)
> + return;
> +
> + /* RevisionID */
> + if (obj->Package.Elements[0].Integer.Value != 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PURBadID",
> + "%s: Expected RevisionID to be 1, "
> + "got 0x%8.8" PRIx64 ".", name,
> + (uint64_t)obj->Package.Elements[0].Integer.Value);
> + return;
> + }
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PUR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PUR", NULL, 0, method_test_PUR_return, NULL);
> +}
> +
> +/*
> + * Section 9.1 System Indicators
> + */
> +
> +static int method_test_SST(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + int ret, i;
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + for (i = 0; i <= 4; i++) {
> + arg[0].Integer.Value = i;
> + ret = method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SST", arg, 1, method_test_NULL_return, NULL);
> +
> + if (ret != FWTS_OK)
> + break;
> + }
> + return ret;
> +}
> +
> +static int method_test_MSG(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 0;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_MSG", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +/*
> + * Section 9.2 Ambient Light Sensor Device
> + */
> +method_test_integer(_ALC, METHOD_OPTIONAL)
> +method_test_integer(_ALI, METHOD_OPTIONAL)
> +method_test_integer(_ALT, METHOD_OPTIONAL)
> +
> +static void method_test_ALR_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> + uint32_t adjustment = 0, illuminance = 0;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Could be one or more sub-packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> +
> + pkg = &obj->Package.Elements[i];
> + if (pkg->Package.Count != 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ALRBadSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 2 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + } else {
> + /* elements should be listed in monotonically increasing order */
> + if (pkg->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
> + adjustment > pkg->Package.Elements[0].Integer.Value) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ALRBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 0 is an invalid integer.",
> + name, i);
> + failed = true;
> + }
> +
> + if (pkg->Package.Elements[1].Type != ACPI_TYPE_INTEGER ||
> + illuminance > pkg->Package.Elements[1].Integer.Value) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ALRBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element 1 is an invalid integer.",
> + name, i);
> + failed = true;
> + }
> + adjustment = pkg->Package.Elements[0].Integer.Value;
> + illuminance = pkg->Package.Elements[1].Integer.Value;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_ALR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ALR", NULL, 0, method_test_ALR_return, NULL);
> +}
> +
> +static int method_test_ALP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ALP", NULL, 0, method_test_polling_return, "_ALP");
> +}
> +
> +
> +/*
> + * Section 9.4 Lid control
> + */
> +static void method_test_LID_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK)
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_LID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_LID", NULL, 0, method_test_LID_return, NULL);
> +}
> +
> +
> +/*
> + * Section 9.8 ATA Controllers
> + */
> +
> +static void method_test_GTF_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + if (obj->Buffer.Length % 7)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_GTFBadBufferSize",
> + "%s should return a buffer with size of multiple of 7.",
> + name);
> + else
> + method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_GTF(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GTF", NULL, 0, method_test_GTF_return, NULL);
> +}
> +
> +static void method_test_GTM_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + if (obj->Buffer.Length != (5 * sizeof(uint32_t)))
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_GTMBadBufferSize",
> + "%s should return a buffer with size of 20.",
> + name);
> + else
> + method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_GTM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GTM", NULL, 0, method_test_GTM_return, NULL);
> +}
> +
> +/*
> + * Section 9.12 Memory Devices
> + */
> +
> +static void method_test_MBM_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + static fwts_package_element elements[] = {
> + { ACPI_TYPE_INTEGER, "Revision" },
> + { ACPI_TYPE_INTEGER, "Window Size" },
> + { ACPI_TYPE_INTEGER, "Sampling Interval" },
> + { ACPI_TYPE_INTEGER, "Maximum Bandwidth" },
> + { ACPI_TYPE_INTEGER, "Average Bandwidth" },
> + { ACPI_TYPE_INTEGER, "Low Bandwidth" },
> + { ACPI_TYPE_INTEGER, "Low Notification Threshold" },
> + { ACPI_TYPE_INTEGER, "High Notification Threshold" },
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_MBM", obj, 8) != FWTS_OK)
> + return;
> +
> + /* For now, just check types */
> + if (method_package_elements_type(fw, name, "_MBM", obj, elements, 8) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_MBM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_MBM", NULL, 0, method_test_MBM_return, NULL);
> +}
> +
> +/*
> + * Section 9.13 USB Port Capabilities
> + */
> +
> +static void method_test_UPC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i, connector_type;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_UPC", obj, 4) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_UPC", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + connector_type = obj->Package.Elements[1].Integer.Value;
> + if (connector_type > 0x0a && connector_type < 0xFF) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_UPCBadReturnType",
> + "%s element 1 returned reserved value.", name);
> + return;
> + }
> +
> + for (i = 2; i < 4; i++) {
> + if (obj->Package.Elements[i].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_UPCBadReturnType",
> + "%s element %" PRIu32 " is not zero.", name, i);
> + return;
> + }
> + }
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_UPC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_UPC", NULL, 0, method_test_UPC_return, NULL);
> +}
> +
> +/*
> + * Section 9.16 User Presence Detection Device
> + */
> +
> +static int method_test_UPD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_UPD", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_UPP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_UPP", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 9.18 Wake Alarm Device
> + */
> +static void method_test_GCP_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value & ~0x1f)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_GCPReturn",
> + "%s returned %" PRId64 ", should be between 0 and 31, "
> + "one or more of the reserved bits 5..31 seem "
> + "to be set.",
> + name, (uint64_t)obj->Integer.Value);
> + else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_GCP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GCP", NULL, 0, method_test_GCP_return, "_GCP");
> +}
> +
> +static void method_test_GRT_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> + return;
> +
> + if (obj->Buffer.Length != 16) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_GRTBadBufferSize",
> + "%s should return a buffer of 16 bytes, but "
> + "instead just returned %" PRIu32,
> + name, obj->Buffer.Length);
> + return;
> + }
> +
> + /*
> + * Should sanity check this, but we can't read the
> + * the data in this emulated mode, so ignore
> + */
> + method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_GRT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GRT", NULL, 0, method_test_GRT_return, NULL);
> +}
> +
> +static void method_test_GWS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value & ~0x3)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_GWSReturn",
> + "%s returned %" PRIu64 ", should be between 0 and 3, "
> + "one or more of the reserved bits 2..31 seem "
> + "to be set.",
> + name, (uint64_t)obj->Integer.Value);
> + else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_GWS(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1; /* DC timer */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GWS", arg, 1, method_test_GWS_return, "_GWS");
> +}
> +
> +static void method_test_CWS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value != 0 && obj->Integer.Value != 1)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_CWSInvalidInteger",
> + "%s returned %" PRIu64 ", should be 0 or 1.",
> + name, (uint64_t)obj->Integer.Value);
> + else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_CWS(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + int i, ret;
> + arg[0].Type = ACPI_TYPE_INTEGER;
> +
> + for (i = 0; i < 2; i++) {
> + arg[0].Integer.Value = i;
> + ret = method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CWS", arg, 1, method_test_CWS_return, NULL);
> +
> + if (ret != FWTS_OK)
> + break;
> + }
> + return ret;
> +}
> +
> +static void method_test_SRT_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value & ~0x1)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_SRTReturn",
> + "%s returned %" PRId64 ", should be between 0 and 1, "
> + "one or more of the reserved bits 1..31 seem "
> + "to be set.",
> + name, (uint64_t)obj->Integer.Value);
> + else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_SRT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SRT", NULL, 0, method_test_SRT_return, NULL);
> +}
> +
> +static int method_test_STP(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[2];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1; /* DC timer */
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 0; /* wake up instantly */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_STP", arg, 2, method_test_passed_failed_return, "_STP");
> +}
> +
> +static int method_test_STV(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[2];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1; /* DC timer */
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 100; /* timer value */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_STV", arg, 2, method_test_passed_failed_return, "_STV");
> +}
> +
> +static int method_test_TIP(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1; /* DC timer */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TIP", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_TIV(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1; /* DC timer */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TIV", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +
> +/*
> + * Section 10.1 Smart Battery
> + */
> +static void method_test_SBS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + static char *sbs_info[] = {
> + "Maximum 1 Smart Battery, system manager/selector not present",
> + "Maximum 1 Smart Battery, system manager/selector present",
> + "Maximum 2 Smart Batteries, system manager/selector present",
> + "Maximum 3 Smart Batteries, system manager/selector present",
> + "Maximum 4 Smart Batteries, system manager/selector present"
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + switch (obj->Integer.Value) {
> + case 0 ... 4:
> + fwts_passed(fw, "%s correctly returned value %" PRIu64 " %s",
> + name, (uint64_t)obj->Integer.Value,
> + sbs_info[obj->Integer.Value]);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_SBSReturn",
> + "%s returned %" PRIu64 ", should be between 0 and 4.",
> + name, (uint64_t)obj->Integer.Value);
> + fwts_advice(fw,
> + "Smart Battery %s is incorrectly informing "
> + "the OS about the smart battery "
> + "configuration. This is a bug and needs to be "
> + "fixed.", name);
> + break;
> + }
> +}
> +
> +static int method_test_SBS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_SBS", NULL, 0, method_test_SBS_return, NULL);
> +}
> +
> +
> +/*
> + * Section 10.2 Battery Control Methods
> + */
> +static int method_test_BCT(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 50; /* 50% */
> +
> + /*
> + * For now, just check that we get some integer back, values
> + * can be 0x00000000, 0x00000001-0xfffffffe and 0xffffffff,
> + * so anything is valid as long as it is an integer
> + */
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BCT", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_BIF_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + bool failed = false;
> +
> + static fwts_package_element elements[] = {
> + { ACPI_TYPE_INTEGER, "Power Unit" },
> + { ACPI_TYPE_INTEGER, "Design Capacity" },
> + { ACPI_TYPE_INTEGER, "Last Full Charge Capacity" },
> + { ACPI_TYPE_INTEGER, "Battery Technology" },
> + { ACPI_TYPE_INTEGER, "Design Voltage" },
> + { ACPI_TYPE_INTEGER, "Design Capacity of Warning" },
> + { ACPI_TYPE_INTEGER, "Design Capactty of Low" },
> + { ACPI_TYPE_INTEGER, "Battery Capacity Granularity 1" },
> + { ACPI_TYPE_INTEGER, "Battery Capacity Granularity 2" },
> + { ACPI_TYPE_STRING, "Model Number" },
> + { ACPI_TYPE_STRING, "Serial Number" },
> + { ACPI_TYPE_STRING, "Battery Type" },
> + { ACPI_TYPE_STRING, "OEM Information" }
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_BIF", obj, 13) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_type(fw, name, "_BIF", obj, elements, 13) != FWTS_OK)
> + return;
> +
> + /* Sanity check each field */
> + /* Power Unit */
> + if (obj->Package.Elements[0].Integer.Value > 0x00000002) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BIFBadUnits",
> + "%s: Expected Power Unit (Element 0) to be "
> + "0 (mWh) or 1 (mAh), got 0x%8.8" PRIx64 ".",
> + name, (uint64_t)obj->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> +#ifdef FWTS_METHOD_PEDANDTIC
> + /*
> + * Since this information may be evaluated by communicating with
> + * the EC we skip these checks as we can't do this from userspace
> + */
> + /* Design Capacity */
> + if (obj->Package.Elements[1].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIFBadCapacity",
> + "%s: Design Capacity (Element 1) is "
> + "unknown: 0x%8.8" PRIx64 ".",
> + name, obj->Package.Elements[1].Integer.Value);
> + failed = true;
> + }
> + /* Last Full Charge Capacity */
> + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIFChargeCapacity",
> + "%s: Last Full Charge Capacity (Element 2) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, obj->Package.Elements[2].Integer.Value);
> + failed = true;
> + }
> +#endif
> + /* Battery Technology */
> + if (obj->Package.Elements[3].Integer.Value > 0x00000002) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BIFBatTechUnit",
> + "%s: Expected Battery Technology Unit "
> + "(Element 3) to be 0 (Primary) or 1 "
> + "(Secondary), got 0x%8.8" PRIx64 ".",
> + name, (uint64_t)obj->Package.Elements[3].Integer.Value);
> + failed = true;
> + }
> +#ifdef FWTS_METHOD_PEDANDTIC
> + /*
> + * Since this information may be evaluated by communicating with
> + * the EC we skip these checks as we can't do this from userspace
> + */
> + /* Design Voltage */
> + if (obj->Package.Elements[4].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIFDesignVoltage",
> + "%s: Design Voltage (Element 4) is "
> + "unknown: 0x%8.8" PRIx64 ".",
> + name, obj->Package.Elements[4].Integer.Value);
> + failed = true;
> + }
> + /* Design capacity warning */
> + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIFDesignCapacityE5",
> + "%s: Design Capacity Warning (Element 5) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, obj->Package.Elements[5].Integer.Value);
> + failed = true;
> + }
> + /* Design capacity low */
> + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIFDesignCapacityE6",
> + "%s: Design Capacity Warning (Element 6) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, obj->Package.Elements[6].Integer.Value);
> + failed = true;
> + }
> +#endif
> + if (failed)
> + fwts_advice(fw,
> + "Battery %s package contains errors. It is "
> + "worth running the firmware test suite "
> + "interactive 'battery' test to see if this "
> + "is problematic. This is a bug an needs to "
> + "be fixed.", name);
> + else
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_BIF(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BIF", NULL, 0, method_test_BIF_return, NULL);
> +}
> +
> +static void method_test_BIX_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + bool failed = false;
> +
> + static fwts_package_element elements[] = {
> + { ACPI_TYPE_INTEGER, "Revision" },
> + { ACPI_TYPE_INTEGER, "Power Unit" },
> + { ACPI_TYPE_INTEGER, "Design Capacity" },
> + { ACPI_TYPE_INTEGER, "Last Full Charge Capacity" },
> + { ACPI_TYPE_INTEGER, "Battery Technology" },
> + { ACPI_TYPE_INTEGER, "Design Voltage" },
> + { ACPI_TYPE_INTEGER, "Design Capacity of Warning" },
> + { ACPI_TYPE_INTEGER, "Design Capactty of Low" },
> + { ACPI_TYPE_INTEGER, "Cycle Count" },
> + { ACPI_TYPE_INTEGER, "Measurement Accuracy" },
> + { ACPI_TYPE_INTEGER, "Max Sampling Time" },
> + { ACPI_TYPE_INTEGER, "Min Sampling Time" },
> + { ACPI_TYPE_INTEGER, "Max Averaging Interval" },
> + { ACPI_TYPE_INTEGER, "Min Averaging Interval" },
> + { ACPI_TYPE_INTEGER, "Battery Capacity Granularity 1" },
> + { ACPI_TYPE_INTEGER, "Battery Capacity Granularity 2" },
> + { ACPI_TYPE_STRING, "Model Number" },
> + { ACPI_TYPE_STRING, "Serial Number" },
> + { ACPI_TYPE_STRING, "Battery Type" },
> + { ACPI_TYPE_STRING, "OEM Information" }
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_BIX", obj, 20) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_type(fw, name, "_BIX", obj, elements, 20) != FWTS_OK)
> + return;
> +
> + /* Sanity check each field */
> + /* Power Unit */
> + if (obj->Package.Elements[1].Integer.Value > 0x00000002) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BIXPowerUnit",
> + "%s: Expected %s (Element 1) to be "
> + "0 (mWh) or 1 (mAh), got 0x%8.8" PRIx64 ".",
> + name, elements[1].name,
> + (uint64_t)obj->Package.Elements[1].Integer.Value);
> + failed = true;
> + }
> +#ifdef FWTS_METHOD_PEDANDTIC
> + /*
> + * Since this information may be evaluated by communicating with
> + * the EC we skip these checks as we can't do this from userspace
> + */
> + /* Design Capacity */
> + if (obj->Package.Elements[2].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIXDesignCapacity",
> + "%s: %s (Element 2) is "
> + "unknown: 0x%8.8" PRIx64 ".",
> + name, elements[2].name,
> + obj->Package.Elements[2].Integer.Value);
> + failed = true;
> + }
> + /* Last Full Charge Capacity */
> + if (obj->Package.Elements[3].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIXFullChargeCapacity",
> + "%s: %s (Element 3) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, elements[3].name,
> + obj->Package.Elements[3].Integer.Value);
> + failed = true;
> + }
> +#endif
> + /* Battery Technology */
> + if (obj->Package.Elements[4].Integer.Value > 0x00000002) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BIXBatteryTechUnit",
> + "%s: %s "
> + "(Element 4) to be 0 (Primary) or 1 "
> + "(Secondary), got 0x%8.8" PRIx64 ".",
> + name, elements[4].name,
> + (uint64_t)obj->Package.Elements[4].Integer.Value);
> + failed = true;
> + }
> +#ifdef FWTS_METHOD_PEDANDTIC
> + /*
> + * Since this information may be evaluated by communicating with
> + * the EC we skip these checks as we can't do this from userspace
> + */
> + /* Design Voltage */
> + if (obj->Package.Elements[5].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIXDesignVoltage",
> + "%s: %s (Element 5) is unknown: "
> + "0x%8.8" PRIx64 ".",
> + name, elements[5].name,
> + obj->Package.Elements[5].Integer.Value);
> + failed = true;
> + }
> + /* Design capacity warning */
> + if (obj->Package.Elements[6].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIXDesignCapacityE6",
> + "%s: %s (Element 6) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, elements[6].name,
> + obj->Package.Elements[6].Integer.Value);
> + failed = true;
> + }
> + /* Design capacity low */
> + if (obj->Package.Elements[7].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW,
> + "Method_BIXDesignCapacityE7",
> + "%s: %s (Element 7) "
> + "is unknown: 0x%8.8" PRIx64 ".",
> + name, elements[7].name,
> + obj->Package.Elements[7].Integer.Value);
> + failed = true;
> + }
> + /* Cycle Count */
> + if (obj->Package.Elements[8].Integer.Value > 0x7fffffff) {
> + fwts_failed(fw, LOG_LEVEL_LOW, "Method_BIXCyleCount",
> + "%s: %s (Element 8) is unknown: "
> + "0x%8.8" PRIx64 ".", Elements[8].name,
> + name, obj->Package.Elements[8].Integer.Value);
> + failed = true;
> + }
> +#endif
> + if (failed)
> + fwts_advice(fw,
> + "Battery %s package contains errors. It is "
> + "worth running the firmware test suite "
> + "interactive 'battery' test to see if this "
> + "is problematic. This is a bug an needs to "
> + "be fixed.", name);
> + else
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_BIX(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BIX", NULL, 0, method_test_BIX_return, NULL);
> +}
> +
> +static int method_test_BMA(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> +
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BMA", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_BMS(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 1;
> +
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BMS", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_BST_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_BST", obj, 4) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_BST", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + /* Sanity check each field */
> + /* Battery State */
> + if ((obj->Package.Elements[0].Integer.Value) > 7) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BSTBadState",
> + "%s: Expected Battery State (Element 0) to "
> + "be 0..7, got 0x%8.8" PRIx64 ".",
> + name, (uint64_t)obj->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> + /* Ensure bits 0 (discharging) and 1 (charging) are not both set, see 10.2.2.6 */
> + if (((obj->Package.Elements[0].Integer.Value) & 3) == 3) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BSTBadState",
> + "%s: Battery State (Element 0) is "
> + "indicating both charging and discharginng "
> + "which is not allowed. Got value 0x%8.8" PRIx64 ".",
> + name, (uint64_t)obj->Package.Elements[0].Integer.Value);
> + failed = true;
> + }
> + /* Battery Present Rate - cannot check, pulled from EC */
> + /* Battery Remaining Capacity - cannot check, pulled from EC */
> + /* Battery Present Voltage - cannot check, pulled from EC */
> + if (failed)
> + fwts_advice(fw,
> + "Battery %s package contains errors. It is "
> + "worth running the firmware test suite "
> + "interactive 'battery' test to see if this "
> + "is problematic. This is a bug an needs to "
> + "be fixed.", name);
> + else
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_BST(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BST", NULL, 0, method_test_BST_return, NULL);
> +}
> +
> +static int method_test_BTP(fwts_framework *fw)
> +{
> + static int values[] = { 0, 1, 100, 200, 0x7fffffff };
> + int i;
> +
> + for (i = 0; i < 5; i++) {
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = values[i];
> + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTP", arg, 1,
> + method_test_NULL_return, NULL) == FWTS_NOT_EXIST)
> + break;
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +static void method_test_PCL_return(fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(fw);
> + FWTS_UNUSED(name);
> + FWTS_UNUSED(buf);
> + FWTS_UNUSED(obj);
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PCL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count);
> +}
> +
> +static int method_test_PCL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_PCL", NULL, 0, method_test_PCL_return, "_PCL");
> +}
> +
> +static int method_test_BTH(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + int i, ret;
> + arg[0].Type = ACPI_TYPE_INTEGER;
> +
> + for (i = 0; i <= 100; i++) {
> + arg[0].Integer.Value = i;
> + ret = method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_BTH", arg, 1, method_test_NULL_return, NULL);
> +
> + if (ret != FWTS_OK)
> + break;
> + }
> + return ret;
> +}
> +
> +static int method_test_BTM(fwts_framework *fw)
> +{
> + static int values[] = { 0, 1, 100, 200, 0x7fffffff };
> + int i;
> +
> + for (i = 0 ; i < 5; i++) {
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = values[i];
> + if (method_evaluate_method(fw, METHOD_MOBILE, "_BTM", arg, 1,
> + method_test_NULL_return, NULL) == FWTS_NOT_EXIST)
> + break;
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +static void method_test_BMD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_BMD", obj, 5) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_BMD", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + fwts_acpi_object_dump(fw, obj);
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_BMD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MOBILE,
> + "_BMD", NULL, 0, method_test_BMD_return, NULL);
> +}
> +
> +static int method_test_BMC(fwts_framework *fw)
> +{
> + static int values[] = { 0, 1, 2, 4 };
> + int i;
> +
> + for (i = 0; i < 4; i++) {
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = values[i];
> + if (method_evaluate_method(fw, METHOD_MOBILE, "_BMC", arg, 1,
> + method_test_NULL_return, NULL) == FWTS_NOT_EXIST)
> + break;
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +
> +/*
> + * Section 10.3 AC Adapters and Power Sources Objects
> + */
> +static void method_test_PRL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PRL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PRL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PRL", NULL, 0, method_test_PRL_return, NULL);
> +}
> +
> +static void method_test_PSR_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value > 2) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PSRZeroOrOne",
> + "%s returned 0x%8.8" PRIx64 ", expected 0 "
> + "(offline) or 1 (online)",
> + name, (uint64_t)obj->Integer.Value);
> + } else
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_PSR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSR", NULL, 0, method_test_PSR_return, NULL);
> +}
> +
> +static void method_test_PIF_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + static fwts_package_element elements[] = {
> + { ACPI_TYPE_INTEGER, "Power Source State" },
> + { ACPI_TYPE_INTEGER, "Maximum Output Power" },
> + { ACPI_TYPE_INTEGER, "Maximum Input Power" },
> + { ACPI_TYPE_STRING, "Model Number" },
> + { ACPI_TYPE_STRING, "Serial Number" },
> + { ACPI_TYPE_STRING, "OEM Information" }
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_PIF", obj, 6) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_type(fw, name, "_PIF", obj, elements, 6) != FWTS_OK)
> + return;
> +
> + fwts_acpi_object_dump(fw, obj);
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PIF(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PIF", NULL, 0, method_test_PIF_return, NULL);
> +}
> +
> +/*
> + * Section 10.4 Power Meters
> + */
> +
> +static int method_test_GAI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GAI", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_GHL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GHL", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_PMC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> + ACPI_OBJECT *element;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_PMC", obj, 14) != FWTS_OK)
> + return;
> +
> + /* check element types */
> + for (i = 0; i < 14; i++) {
> + element = &obj->Package.Elements[i];
> + if (i > 10) {
> + if (element->Type != ACPI_TYPE_STRING) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElementType",
> + "%s element %" PRIu32 " is not a string.", name, i);
> + failed = true;
> + }
> + } else {
> + if (element->Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElementType",
> + "%s element %" PRIu32 " is not an integer.", name, i);
> + failed = true;
> + }
> + }
> + }
> +
> + /* check element's constraints */
> + element = &obj->Package.Elements[0];
> + if (element->Integer.Value & 0xFFFFFEF0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElement",
> + "%s element 0 has reserved bits that are non-zero, got "
> + "0x%" PRIx32 " and expected 0 for these field. ", name,
> + (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + element = &obj->Package.Elements[1];
> + if (element->Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElement",
> + "%s element 1 is expected to be 0, got 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + element = &obj->Package.Elements[2];
> + if (element->Integer.Value != 0 && element->Integer.Value != 1) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElement",
> + "%s element 2 is expected to be 0 or 1, got 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + element = &obj->Package.Elements[3];
> + if (element->Integer.Value > 100000) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElement",
> + "%s element 3 exceeds 100000 (100 percent) = 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + /* nothing to check for elements 4~7 */
> +
> + element = &obj->Package.Elements[8];
> + if (element->Integer.Value != 0 && element->Integer.Value != 0xFFFFFFFF) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_PMCBadElement",
> + "%s element 8 is expected to be 0 or 1, got 0x%" PRIx32 ".",
> + name, (uint32_t) element->Integer.Value);
> + failed = true;
> + }
> +
> + /* nothing to check for elements 9~13 */
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PMC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PMC", NULL, 0, method_test_PMC_return, NULL);
> +}
> +
> +static void method_test_PMD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PMD", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PMD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PMD", NULL, 0, method_test_PMD_return, NULL);
> +}
> +
> +static int method_test_PMM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PMM", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 10.5 Wireless Power Controllers
> + */
> +static void method_test_WPC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Integer.Value <= 0x02 || obj->Integer.Value == 0xff)
> + method_passed_sane(fw, name, "integer");
> + else
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "Method_WPCInvalidInteger",
> + "%s returned an invalid integer 0x%8.8" PRIx64,
> + name, (uint64_t)obj->Integer.Value);
> +}
> +
> +static int method_test_WPC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_WPC", NULL, 0, method_test_WPC_return, "_WPC");
> +}
> +
> +static int method_test_WPP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_WPP", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 11.3 Fan Devices
> + */
> +static void method_test_FIF_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_FIF", obj, 4) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_FIF",
> + obj, ACPI_TYPE_INTEGER) != FWTS_OK) {
> + fwts_advice(fw,
> + "%s is not returning the correct "
> + "fan information. It may be worth "
> + "running the firmware test suite "
> + "interactive 'fan' test to see if "
> + "this affects the control and "
> + "operation of the fan.", name);
> + return;
> + }
> +
> + fwts_acpi_object_dump(fw, obj);
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_FIF(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FIF", NULL, 0, method_test_FIF_return, NULL);
> +}
> +
> +static void method_test_FPS_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (obj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) {
> + if (obj->Package.Elements[0].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FPSBadRevision",
> + "%s element 0 is not revision 0.", name);
> + failed = true;
> + }
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FPSBadReturnType",
> + "%s element 0 is not an integer.", name);
> + failed = true;
> + }
> +
> + /* Could be one or more sub-packages */
> + for (i = 1; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FPSBadReturnType",
> + "%s element %" PRIu32 " is not a package.",
> + name, i);
> + failed = true;
> + continue;
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + if (pkg->Package.Count != 5) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FPSBadSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 5 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + for (j = 0; j < 5; j++) {
> + /* TODO - field 0 and 1 can be related to other control method */
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_FPSBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_FPS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FPS", NULL, 0, method_test_FPS_return, NULL);
> +}
> +
> +static int method_test_FSL(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 50;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FSL", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_FST_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_FST", obj, 3) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_FST",
> + obj, ACPI_TYPE_INTEGER) != FWTS_OK) {
> + fwts_advice(fw,
> + "%s is not returning the correct "
> + "fan status information. It may be "
> + "worth running the firmware test "
> + "suite interactive 'fan' test to see "
> + "if this affects the control and "
> + "operation of the fan.", name);
> + return;
> + }
> +
> + fwts_acpi_object_dump(fw, obj);
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_FST(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_FST", NULL, 0, method_test_FST_return, NULL);
> +}
> +
> +
> +/*
> + * Section 11.4 Thermal
> + */
> +static void method_test_THERM_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + char *method = (char*)private;
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (fwts_acpi_region_handler_called_get()) {
> + /*
> + * We accessed some memory or I/O region during the
> + * evaluation which returns spoofed values, so we
> + * should not test the value being returned. In this
> + * case, just pass this as a valid return type.
> + */
> + method_passed_sane(fw, name, "return type");
> + } else {
> + /*
> + * The evaluation probably was a hard-coded value,
> + * so sanity check it
> + */
> + if (obj->Integer.Value >= 2732) {
> + fwts_passed(fw,
> + "%s correctly returned sane looking "
> + "value 0x%8.8" PRIx64 " (%5.1f degrees K)",
> + method,
> + (uint64_t)obj->Integer.Value,
> + (float)((uint64_t)obj->Integer.Value) / 10.0);
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "MethodBadTemp",
> + "%s returned a dubious value below "
> + "0 degrees C: 0x%8.8" PRIx64 " (%5.1f "
> + "degrees K)",
> + method,
> + (uint64_t)obj->Integer.Value,
> + (float)((uint64_t)obj->Integer.Value) / 10.0);
> + fwts_advice(fw,
> + "The value returned was probably a "
> + "hard-coded thermal value which is "
> + "out of range because fwts did not "
> + "detect any ACPI region handler "
> + "accesses of I/O or system memeory "
> + "to evaluate the thermal value. "
> + "It is worth sanity checking these "
> + "values in "
> + "/sys/class/thermal/thermal_zone*.");
> + }
> + }
> +}
> +
> +#define method_test_THERM(name, type) \
> +static int method_test ## name(fwts_framework *fw) \
> +{ \
> + fwts_acpi_region_handler_called_set(false); \
> + return method_evaluate_method(fw, type, # name, \
> + NULL, 0, method_test_THERM_return, # name); \
> +}
> +
> +method_test_THERM(_CRT, METHOD_OPTIONAL)
> +method_test_THERM(_CR3, METHOD_OPTIONAL)
> +method_test_THERM(_HOT, METHOD_OPTIONAL)
> +method_test_THERM(_TMP, METHOD_OPTIONAL)
> +method_test_THERM(_NTT, METHOD_OPTIONAL)
> +method_test_THERM(_PSV, METHOD_OPTIONAL)
> +method_test_THERM(_TST, METHOD_OPTIONAL)
> +
> +static void method_test_MTL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint64_t val;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + val = (uint64_t) obj->Integer.Value;
> + if (val > 100) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_MTLBadReturnType",
> + "%s should return a percentage, got %" PRIu64 " instead", name, val);
> + }
> +
> + if (!failed)
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +
> + return;
> +}
> +
> +static int method_test_MTL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_MTL", NULL, 0, method_test_MTL_return, NULL);
> +}
> +
> +static void method_test_ART_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (obj->Package.Elements[0].Type == ACPI_TYPE_INTEGER) {
> + if (obj->Package.Elements[0].Integer.Value != 0) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadRevision",
> + "%s element 0 is not revision 0.", name);
> + failed = true;
> + }
> + } else {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadReturnType",
> + "%s element 0 is not an integer.", name);
> + failed = true;
> + }
> +
> + /* Could be one or more sub-packages */
> + for (i = 1; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_PACKAGE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadReturnType",
> + "%s element %" PRIu32 " is not a package.",
> + name, i);
> + failed = true;
> + continue;
> + }
> +
> + pkg = &obj->Package.Elements[i];
> + if (pkg->Package.Count != 13) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 13 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + /* First two elements are references, and rests are integers */
> + for (j = 0; j < 2; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "a reference.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + for (j = 2; j < 13; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_ARTBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_ART(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ART", NULL, 0, method_test_ART_return, "_ART");
> +}
> +
> +static void method_test_PSL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_PSL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_PSL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_PSL", NULL, 0, method_test_PSL_return, "_PSL");
> +}
> +
> +static void method_test_TRT_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_TRT", obj, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + /* Could be one or more packages */
> + for (i = 0; i < obj->Package.Count; i++) {
> + ACPI_OBJECT *pkg;
> + uint32_t j;
> + bool elements_ok = true;
> +
> + pkg = &obj->Package.Elements[i];
> + if (pkg->Package.Count != 8) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TRTSubPackageElementCount",
> + "%s sub-package %" PRIu32 " was expected to "
> + "have 8 elements, got %" PRIu32 " elements instead.",
> + name, i, pkg->Package.Count);
> + failed = true;
> + continue;
> + }
> +
> + /* First two elements are references, and rests are integers */
> + for (j = 0; j < 2; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TRTBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "a reference.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + for (j = 2; j < 8; j++) {
> + if (pkg->Package.Elements[j].Type != ACPI_TYPE_INTEGER) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_TRTBadSubPackageReturnType",
> + "%s sub-package %" PRIu32
> + " element %" PRIu32 " is not "
> + "an integer.",
> + name, i, j);
> + elements_ok = false;
> + }
> + }
> +
> + if (!elements_ok) {
> + failed = true;
> + continue;
> + }
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_TRT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TRT", NULL, 0, method_test_TRT_return, "_TRT");
> +}
> +
> +static int method_test_TSN(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TSN", NULL, 0, method_test_reference_return, "_TSN");
> +}
> +
> +static int method_test_TSP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TSP", NULL, 0, method_test_polling_return, "_TSP");
> +}
> +
> +static void method_test_TCx_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK)
> + method_passed_sane_uint64(fw, (char*)private, obj->Integer.Value);
> +}
> +
> +static int method_test_TC1(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TC1", NULL, 0, method_test_TCx_return, "_TC1");
> +}
> +
> +static int method_test_TC2(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TC2", NULL, 0, method_test_TCx_return, "_TC1");
> +}
> +
> +static int method_test_TFP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TFP", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_ACx(fwts_framework *fw)
> +{
> + int i;
> +
> + for (i = 0; i < 10; i++) {
> + char buffer[5];
> +
> + snprintf(buffer, sizeof(buffer), "_AC%d", i);
> + method_evaluate_method(fw, METHOD_OPTIONAL,
> + buffer, NULL, 0, method_test_THERM_return, buffer);
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +static int method_test_DTI(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 2732 + 800; /* 80 degrees C */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DTI", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_SCP(fwts_framework *fw)
> +{
> + int i;
> +
> + for (i = 0; i < 2; i++) {
> + ACPI_OBJECT arg[3];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i; /* Mode */
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 5; /* Acoustic limit */
> + arg[2].Type = ACPI_TYPE_INTEGER;
> + arg[2].Integer.Value = 5; /* Power limit */
> +
> + if (method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DTI", arg, 1, method_test_NULL_return,
> + NULL) == FWTS_NOT_EXIST)
> + break;
> + fwts_log_nl(fw);
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i; /* Mode */
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 1; /* Acoustic limit */
> + arg[2].Type = ACPI_TYPE_INTEGER;
> + arg[2].Integer.Value = 1; /* Power limit */
> +
> + if (method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DTI", arg, 1, method_test_NULL_return,
> + NULL) == FWTS_NOT_EXIST)
> + break;
> + }
> + return FWTS_OK;
> +}
> +
> +static void method_test_RTV_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) == FWTS_OK)
> + method_passed_sane_uint64(fw, name, obj->Integer.Value);
> +}
> +
> +static int method_test_RTV(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_RTV", NULL, 0, method_test_RTV_return, "_RTV");
> +}
> +
> +static int method_test_TPT(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 2732 + 900; /* 90 degrees C */
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TPT", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_TZD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_TZD", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK)
> + return;
> +
> + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count);
> +}
> +
> +static int method_test_TZD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TZD", NULL, 0, method_test_TZD_return, "_TZD");
> +}
> +
> +static int method_test_TZM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TZM", NULL, 0, method_test_reference_return, "_TZM");
> +}
> +
> +static int method_test_TZP(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_TZP", NULL, 0, method_test_polling_return, "_TZP");
> +}
> +
> +/*
> + * Section 12 Embedded Controller
> + */
> +
> +static void method_test_GPE_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> + FWTS_UNUSED(buf);
> + bool failed = false;
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_INTEGER:
> + if (obj->Integer.Value <= 255)
> + fwts_passed(fw, "%s returned an integer 0x%8.8" PRIx64,
> + name, (uint64_t)obj->Integer.Value);
> + else
> + fwts_failed(fw, LOG_LEVEL_HIGH,
> + "MethodGPEInvalidInteger",
> + "%s returned an invalid integer 0x%8.8" PRIx64,
> + name, (uint64_t)obj->Integer.Value);
> + break;
> + case ACPI_TYPE_PACKAGE:
> + if (obj->Package.Elements[0].Type != ACPI_TYPE_LOCAL_REFERENCE) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_GPEBadSubPackageReturnType",
> + "%s sub-package element 0 is not a reference.", name);
> + }
> +
> + if (obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER) {
> + failed = true;
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_GPEBadSubPackageReturnType",
> + "%s sub-package element 1 is not an integer.", name);
> + }
> +
> + if (!failed)
> + method_passed_sane(fw, name, "package");
> +
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH, "Method_GPEBadSubReturnType",
> + "%s did not return an integer or a package.", name);
> + break;
> + }
> +}
> +
> +static int method_test_GPE(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GPE", NULL, 0, method_test_GPE_return, "_GPE");
> +}
> +
> +static int method_test_EC_(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_EC_", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Section 16 Waking and Sleeping
> + */
> +static int method_test_PTS(fwts_framework *fw)
> +{
> + int i;
> +
> + for (i = 1; i < 6; i++) {
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i;
> +
> + fwts_log_info(fw, "Test _PTS(%d).", i);
> +
> + if (method_evaluate_method(fw, METHOD_MANDATORY, "_PTS", arg, 1,
> + method_test_NULL_return, NULL) == FWTS_NOT_EXIST) {
> + fwts_advice(fw,
> + "Could not find _PTS. This method provides a "
> + "mechanism to do housekeeping functions, such "
> + "as write sleep state to the embedded "
> + "controller before entering a sleep state. If "
> + "the machine cannot suspend (S3), "
> + "hibernate (S4) or shutdown (S5) then it "
> + "could be because _PTS is missing. Note that "
> + "ACPI 1.0 wants _PTS to be executed before "
> + "suspending devices.");
> + break;
> + }
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +static int method_test_TTS(fwts_framework *fw)
> +{
> + if (fwts_acpi_object_exists("_TTS") != NULL) {
> + int i;
> +
> + for (i = 1; i < 6; i++) {
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i;
> +
> + fwts_log_info(fw,
> + "Test _TTS(%d) Transition To State S%d.", i, i);
> +
> + if (method_evaluate_method(fw, METHOD_MANDATORY,
> + "_TTS", arg, 1, method_test_NULL_return,
> + NULL) == FWTS_NOT_EXIST) {
> + fwts_advice(fw,
> + "Could not find _TTS. This method is invoked "
> + "at the beginning of the the sleep transition "
> + "for S1, S2, S3, S4 and S5 shutdown. The Linux "
> + "kernel caters for firmware that does not implement "
> + "_TTS, however, it will issue a warning that this "
> + "control method is missing.");
> + break;
> + }
> + fwts_log_nl(fw);
> + }
> + }
> + else {
> + fwts_skipped(fw,
> + "Optional control method _TTS does not exist.");
> + }
> + return FWTS_OK;
> +}
> +
> +static void method_test_WAK_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_equal(fw, name, "_WAK", obj, 2) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_WAK", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_WAK(fwts_framework *fw)
> +{
> + uint32_t i;
> +
> + for (i = 1; i < 6; i++) {
> + ACPI_OBJECT arg[1];
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i;
> + fwts_log_info(fw, "Test _WAK(%d) System Wake, State S%d.", i, i);
> + if (method_evaluate_method(fw, METHOD_MANDATORY, "_WAK", arg, 1,
> + method_test_WAK_return, &i) == FWTS_NOT_EXIST) {
> + fwts_advice(fw,
> + "Section 7.3.7 states that a system that wakes "
> + "from a sleeping state will invoke the _WAK "
> + "control to issue device, thermal and other "
> + "notifications to ensure that the operating system "
> + "checks the states of various devices, thermal "
> + "zones, etc. The Linux kernel will report an "
> + "ACPI exception if _WAK is does not exist when "
> + "it returns from a sleep state.");
> + break;
> + }
> + fwts_log_nl(fw);
> + }
> + return FWTS_OK;
> +}
> +
> +
> +/*
> + * Appendix B ACPI Extensions for Display Adapters
> + */
> +static int method_test_DOS(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 0 << 2 | 1;
> +
> + /*
> + * BIOS should toggle active display, BIOS controls brightness of
> + * LCD on AC/DC power changes
> + */
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DOS", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static void method_test_DOD_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> +
> + static char *dod_type[] = {
> + "Other",
> + "VGA, CRT or VESA Compatible Analog Monitor",
> + "TV/HDTV or other Analog-Video Monitor",
> + "External Digital Monitor",
> +
> + "Internal/Integrated Digital Flat Panel",
> + "Reserved",
> + "Reserved",
> + "Reserved",
> +
> + "Reserved",
> + "Reserved",
> + "Reserved",
> + "Reserved",
> +
> + "Reserved",
> + "Reserved",
> + "Reserved",
> + "Reserved"
> + };
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + for (i = 0; i < obj->Package.Count; i++) {
> + if (obj->Package.Elements[i].Type != ACPI_TYPE_INTEGER)
> + failed = true;
> + else {
> + uint32_t val = obj->Package.Elements[i].Integer.Value;
> + fwts_log_info_verbatim(fw, "Device %" PRIu32 ":", i);
> + if ((val & 0x80000000)) {
> + fwts_log_info_verbatim(fw, " Video Chip Vendor Scheme %" PRIu32, val);
> + } else {
> + fwts_log_info_verbatim(fw, " Instance: %" PRIu32, val & 0xf);
> + fwts_log_info_verbatim(fw, " Display port attachment: %" PRIu32, (val >> 4) & 0xf);
> + fwts_log_info_verbatim(fw, " Type of display: %" PRIu32 " (%s)",
> + (val >> 8) & 0xf, dod_type[(val >> 8) & 0xf]);
> + fwts_log_info_verbatim(fw, " BIOS can detect device: %" PRIu32, (val >> 16) & 1);
> + fwts_log_info_verbatim(fw, " Non-VGA device: %" PRIu32, (val >> 17) & 1);
> + fwts_log_info_verbatim(fw, " Head or pipe ID: %" PRIu32, (val >> 18) & 0x7);
> + }
> + }
> + }
> +
> + if (failed)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_DODNoPackage",
> + "Method _DOD did not return a package of "
> + "%" PRIu32 " integers.", obj->Package.Count);
> + else
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_DOD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DOD", NULL, 0, method_test_DOD_return, NULL);
> +}
> +
> +static void method_test_ROM_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + FWTS_UNUSED(obj);
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) == FWTS_OK)
> + method_passed_sane(fw, name, "package");
> +}
> +
> +static int method_test_ROM(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[2];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 0;
> + arg[1].Type = ACPI_TYPE_INTEGER;
> + arg[1].Integer.Value = 4096;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ROM", arg, 2, method_test_ROM_return, NULL);
> +}
> +
> +static int method_test_GPD(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_GPD", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_SPD(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[2];
> + int i;
> +
> + for (i = 0; i < 4; i++) {
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = i; /* bits 00..11, post device */
> +
> + if (method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SPD", arg, 1, method_test_passed_failed_return, NULL) == FWTS_NOT_EXIST)
> + break;
> + }
> + return FWTS_OK;
> +}
> +
> +static int method_test_VPO(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_VPO", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_ADR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_ADR", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_BCL_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t i;
> + bool failed = false;
> + bool ascending_levels = false;
> + char *str = NULL;
> +
> + FWTS_UNUSED(private);
> +
> + if (method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK)
> + return;
> +
> + if (method_package_count_min(fw, name, "_BCL", obj, 3) != FWTS_OK)
> + return;
> +
> + if (method_package_elements_all_type(fw, name, "_BCL", obj, ACPI_TYPE_INTEGER) != FWTS_OK)
> + return;
> +
> + if (obj->Package.Elements[0].Integer.Value <
> + obj->Package.Elements[1].Integer.Value) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BCLMaxLevel",
> + "Brightness level when on full "
> + " power (%" PRIu64 ") is less than "
> + "brightness level when on "
> + "battery power (%" PRIu64 ").",
> + (uint64_t)obj->Package.Elements[0].Integer.Value,
> + (uint64_t)obj->Package.Elements[1].Integer.Value);
> + failed = true;
> + }
> +
> + for (i = 2; i < obj->Package.Count - 1; i++) {
> + if (obj->Package.Elements[i].Integer.Value >
> + obj->Package.Elements[i+1].Integer.Value) {
> + fwts_log_info(fw,
> + "Brightness level %" PRIu64
> + " (index %" PRIu32 ") is greater "
> + "than brightness level %" PRIu64
> + " (index %d" PRIu32 "), should "
> + "be in ascending order.",
> + (uint64_t)obj->Package.Elements[i].Integer.Value, i,
> + (uint64_t)obj->Package.Elements[i+1].Integer.Value, i+1);
> + ascending_levels = true;
> + failed = true;
> + }
> + }
> + if (ascending_levels) {
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_BCLAscendingOrder",
> + "Some or all of the brightness "
> + "level are not in ascending "
> + "order which should be fixed "
> + "in the firmware.");
> + failed = true;
> + }
> +
> + fwts_log_info(fw, "Brightness levels for %s:" ,name);
> + fwts_log_info_verbatim(fw, " Level on full power : %" PRIu64,
> + (uint64_t)obj->Package.Elements[0].Integer.Value);
> + fwts_log_info_verbatim(fw, " Level on battery power: %" PRIu64,
> + (uint64_t)obj->Package.Elements[1].Integer.Value);
> + for (i = 2; i < obj->Package.Count; i++) {
> + char tmp[12];
> +
> + snprintf(tmp, sizeof(tmp), "%s%" PRIu64,
> + i == 2 ? "" : ", ",
> + (uint64_t)obj->Package.Elements[i].Integer.Value);
> + str = fwts_realloc_strcat(str, tmp);
> + if (!str)
> + break;
> + }
> + if (str) {
> + fwts_log_info_verbatim(fw, " Brightness Levels : %s", str);
> + free(str);
> + }
> +
> + if (failed)
> + fwts_advice(fw,
> + "%s seems to be "
> + "misconfigured and is "
> + "returning incorrect "
> + "brightness levels."
> + "It is worth sanity checking "
> + "this with the firmware test "
> + "suite interactive test "
> + "'brightness' to see how "
> + "broken this is. As it is, "
> + "_BCL is broken and needs to "
> + "be fixed.", name);
> + else
> + fwts_passed(fw,
> + "%s returned a sane "
> + "package of %" PRIu32 " integers.",
> + name, obj->Package.Count);
> +}
> +
> +static int method_test_BCL(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_BCL", NULL, 0, method_test_BCL_return, NULL);
> +}
> +
> +static int method_test_BCM(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 0;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_BCM", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_BQC(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_BQC", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static void method_test_DDC_return(
> + fwts_framework *fw,
> + char *name,
> + ACPI_BUFFER *buf,
> + ACPI_OBJECT *obj,
> + void *private)
> +{
> + uint32_t requested = *(uint32_t*)private;
> +
> + FWTS_UNUSED(buf);
> +
> + if (obj == NULL) {
> + method_failed_null_object(fw, name, "a buffer or integer");
> + return;
> + }
> +
> + switch (obj->Type) {
> + case ACPI_TYPE_BUFFER:
> + if (requested != obj->Buffer.Length)
> + fwts_failed(fw, LOG_LEVEL_MEDIUM,
> + "Method_DDCElementCount",
> + "%s returned a buffer of %" PRIu32 " items, "
> + "expected %" PRIu32 ".",
> + name, obj->Buffer.Length, requested);
> + else
> + fwts_passed(fw,
> + "Method %s returned a buffer of %d items "
> + "as expected.",
> + name, obj->Buffer.Length);
> + break;
> + case ACPI_TYPE_INTEGER:
> + fwts_passed(fw,
> + "%s could not return a buffer of %d "
> + "items and instead returned an error "
> + "status.",
> + name, obj->Buffer.Length);
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "Method_DDCBadReturnType",
> + "%s did not return a buffer or an integer.", name);
> + break;
> + }
> +}
> +
> +static int method_test_DDC(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + uint32_t i;
> +
> + for (i = 128; i <= 256; i <<= 1) {
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 128;
> +
> + if (method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DDC", arg, 1, method_test_DDC_return,
> + &i) == FWTS_NOT_EXIST)
> + break;
> + }
> + return FWTS_OK;
> +}
> +
> +static int method_test_DCS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DCS", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_DGS(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DGS", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_DSS(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + arg[0].Integer.Value = 0;
> +
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_DSS", arg, 1, method_test_NULL_return, NULL);
> +}
> +
> +static int method_test_CBA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CBA", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_CDM(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_CDM", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/*
> + * Intelligent Platform Management Interface (IPMI) Specification
> + */
> +static int method_test_IFT(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_IFT", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int method_test_SRV(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_OPTIONAL,
> + "_SRV", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +/* ARM SBBR Test Definitions */
> +static int sbbr_method_test_ADR(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_ADR", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int sbbr_method_test_AEI(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_AEI", NULL, 0, method_test_AEI_return, NULL);
> +}
> +
> +static int sbbr_method_test_CCA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_CCA", NULL, 0, method_test_integer_return, NULL);
> +}
> +
> +static int sbbr_method_test_EVT(fwts_framework *fw)
> +{
> + int ret;
> +
> + /* Only test the _EVT method with pins defined in AEI. */
> + ret = method_evaluate_method(fw, METHOD_MANDATORY,
> + "_AEI", NULL, 0, method_test_EVT_return, NULL);
> +
> + if (ret == FWTS_NOT_EXIST)
> + fwts_failed(fw, LOG_LEVEL_HIGH, "SbbrAcpiEvtDoesNotExist", "Method _EVT does not exist.");
> +
> + return ret;
> +}
> +
> +static int sbbr_method_test_HID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_HID", NULL, 0, method_test_HID_return, NULL);
> +}
> +
> +static int sbbr_method_test_OSI(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> +
> + arg[0].Type = ACPI_TYPE_STRING;
> + arg[0].String.Pointer = "Linux";
> +
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_OSI", arg, 1, method_test_integer_return, NULL);
> +}
> +
> +static int sbbr_method_test_SST(fwts_framework *fw)
> +{
> + ACPI_OBJECT arg[1];
> + int ret, i;
> +
> + arg[0].Type = ACPI_TYPE_INTEGER;
> + for (i = 0; i <= 4; i++) {
> + arg[0].Integer.Value = i;
> + ret = method_evaluate_method(fw, METHOD_MANDATORY,
> + "_SST", arg, 1, method_test_NULL_return, NULL);
> +
> + if (ret != FWTS_OK)
> + break;
> + }
> + return ret;
> +}
> +
> +static int sbbr_method_test_STA(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_STA", NULL, 0, method_test_STA_return, "_STA");
> +}
> +
> +static int sbbr_method_test_UID(fwts_framework *fw)
> +{
> + return method_evaluate_method(fw, METHOD_MANDATORY,
> + "_UID", NULL, 0, method_test_UID_return, NULL);
> +}
> +
> +
> +/*
> + * Tests
> + */
> +static fwts_framework_minor_test sbbr_method_tests[] = {
> + { method_name_check, "Test Method Names." },
> +
> + /* Section 5.3 */
> + /* { method_test_PR , "Test _PR (Processor)." }, */
> +
> + /* Section 5.6 ACPI Event Programming Model */
> + /* { method_test_Wxx, "Test _Wxx (Wake Event)." }, */
> +
> + { method_test_AEI, "Test _AEI." },
> + { method_test_EVT, "Test _EVT (Event Method)." },
> +
> + /* Section 5.7 Predefined Objects */
> + { method_test_DLM, "Test _DLM (Device Lock Mutex)." },
> + /* { method_test_GL , "Test _GL (Global Lock)." }, */
> + /* { method_test_OS , "Test _OS (Operating System)." }, */
> + /* { method_test_REV, "Test _REV (Revision)." }, */
> +
> + /* Section 5.8 System Configuration Objects */
> + { method_test_PIC, "Test _PIC (Inform AML of Interrupt Model)." },
> +
> + /* Section 6.1 Device Identification Objects */
> +
> + { method_test_CID, "Test _CID (Compatible ID)." },
> + /* { method_test_CLS, "Test _CLS (Class Code)." }, */
> + { method_test_DDN, "Test _DDN (DOS Device Name)." },
> + { method_test_HID, "Test _HID (Hardware ID)." },
> + { method_test_HRV, "Test _HRV (Hardware Revision Number)." },
> + { method_test_MLS, "Test _MLS (Multiple Language String)." },
> + { method_test_PLD, "Test _PLD (Physical Device Location)." },
> + { method_test_SUB, "Test _SUB (Subsystem ID)." },
> + { method_test_SUN, "Test _SUN (Slot User Number)." },
> + { method_test_STR, "Test _STR (String)." },
> + { method_test_UID, "Test _UID (Unique ID)." },
> +
> + /* Section 6.2 Device Configurations Objects */
> +
> + { method_test_CDM, "Test _CDM (Clock Domain)." },
> + { method_test_CRS, "Test _CRS (Current Resource Settings)." },
> + { method_test_DSD, "Test _DSD (Device Specific Data)." },
> + { method_test_DIS, "Test _DIS (Disable)." },
> + { method_test_DMA, "Test _DMA (Direct Memory Access)." },
> + { method_test_FIX, "Test _FIX (Fixed Register Resource Provider)." },
> + { method_test_GSB, "Test _GSB (Global System Interrupt Base)." },
> + { method_test_HPP, "Test _HPP (Hot Plug Parameters)." },
> + /* { method_test_HPX, "Test _HPX (Hot Plug Extensions)." }, */
> + /* { method_test_MAT, "Test _MAT (Multiple APIC Table Entry)." }, */
> + { method_test_PRS, "Test _PRS (Possible Resource Settings)." },
> + { method_test_PRT, "Test _PRT (PCI Routing Table)." },
> + { method_test_PXM, "Test _PXM (Proximity)." },
> + /* { method_test_SLI, "Test _SLI (System Locality Information)." }, */
> + /* { method_test_SRS, "Test _SRS (Set Resource Settings)." }, */
> + { method_test_CCA, "Test _CCA (Cache Coherency Attribute)." },
> +
> + /* Section 6.3 Device Insertion, Removal and Status Objects */
> +
> + { method_test_EDL, "Test _EDL (Eject Device List)." },
> + { method_test_EJD, "Test _EJD (Ejection Dependent Device)." },
> + { method_test_EJ0, "Test _EJ0 (Eject)." },
> + { method_test_EJ1, "Test _EJ1 (Eject)." },
> + { method_test_EJ2, "Test _EJ2 (Eject)." },
> + { method_test_EJ3, "Test _EJ3 (Eject)." },
> + { method_test_EJ4, "Test _EJ4 (Eject)." },
> + { method_test_LCK, "Test _LCK (Lock)." },
> + /* { method_test_OST, "Test _OST (OSPM Status Indication)." }, */
> + { method_test_RMV, "Test _RMV (Remove)." },
> + { method_test_STA, "Test _STA (Status)." },
> +
> + /* Section 6.4 Resource Data Types for ACPI */
> +
> + /* Section 6.5 Other Objects and Controls */
> +
> + { method_test_DEP, "Test _DEP (Operational Region Dependencies)." },
> + { method_test_FIT, "Test _FIT (Firmware Interface Table)." },
> + { method_test_BDN, "Test _BDN (BIOS Dock Name)." },
> + { method_test_BBN, "Test _BBN (Base Bus Number)." },
> + { method_test_DCK, "Test _DCK (Dock)." },
> + { method_test_INI, "Test _INI (Initialize)." },
> + { method_test_GLK, "Test _GLK (Global Lock)." },
> + /* { method_test_REG, "Test _REG (Region)." }, */
> + { method_test_SEG, "Test _SEG (Segment)." },
> +
> + /* Section 7.1 Declaring a Power Resource Object */
> +
> + { method_test_OFF, "Test _OFF (Set resource off)." },
> + { method_test_ON_, "Test _ON_ (Set resource on)." },
> +
> + /* Section 7.2 Device Power Management Objects */
> +
> + { method_test_DSW, "Test _DSW (Device Sleep Wake)." },
> + { method_test_IRC, "Test _IRC (In Rush Current)." },
> + { method_test_PRE, "Test _PRE (Power Resources for Enumeration)." },
> + { method_test_PR0, "Test _PR0 (Power Resources for D0)." },
> + { method_test_PR1, "Test _PR1 (Power Resources for D1)." },
> + { method_test_PR2, "Test _PR2 (Power Resources for D2)." },
> + { method_test_PR3, "Test _PR3 (Power Resources for D3)." },
> + { method_test_PRW, "Test _PRW (Power Resources for Wake)." },
> + { method_test_PS0, "Test _PS0 (Power State 0)." },
> + { method_test_PS1, "Test _PS1 (Power State 1)." },
> + { method_test_PS2, "Test _PS2 (Power State 2)." },
> + { method_test_PS3, "Test _PS3 (Power State 3)." },
> + { method_test_PSC, "Test _PSC (Power State Current)." },
> + { method_test_PSE, "Test _PSE (Power State for Enumeration)." },
> + { method_test_PSW, "Test _PSW (Power State Wake)." },
> + { method_test_S1D, "Test _S1D (S1 Device State)." },
> + { method_test_S2D, "Test _S2D (S2 Device State)." },
> + { method_test_S3D, "Test _S3D (S3 Device State)." },
> + { method_test_S4D, "Test _S4D (S4 Device State)." },
> + { method_test_S0W, "Test _S0W (S0 Device Wake State)." },
> + { method_test_S1W, "Test _S1W (S1 Device Wake State)." },
> + { method_test_S2W, "Test _S2W (S2 Device Wake State)." },
> + { method_test_S3W, "Test _S3W (S3 Device Wake State)." },
> + { method_test_S4W, "Test _S4W (S4 Device Wake State)." },
> + { method_test_RST, "Test _RST (Device Reset)." },
> + { method_test_PRR, "Test _PRR (Power Resource for Reset)." },
> +
> + /* Section 7.3 OEM-Supplied System-Level Control Methods */
> + { method_test_S0_, "Test _S0_ (S0 System State)." },
> + { method_test_S1_, "Test _S1_ (S1 System State)." },
> + { method_test_S2_, "Test _S2_ (S2 System State)." },
> + { method_test_S3_, "Test _S3_ (S3 System State)." },
> + { method_test_S4_, "Test _S4_ (S4 System State)." },
> + { method_test_S5_, "Test _S5_ (S5 System State)." },
> + { method_test_SWS, "Test _SWS (System Wake Source)." },
> +
> + /* Section 8.4 Declaring Processors */
> +
> + { method_test_PSS, "Test _PSS (Performance Supported States)." },
> + { method_test_CPC, "Test _CPC (Continuous Performance Control)." },
> + { method_test_CSD, "Test _CSD (C State Dependencies)." },
> + { method_test_CST, "Test _CST (C States)." },
> + { method_test_PCT, "Test _PCT (Performance Control)." },
> + /* { method_test_PDC, "Test _PDC (Processor Driver Capabilities)." }, */
> + { method_test_PDL, "Test _PDL (P-State Depth Limit)." },
> + { method_test_PPC, "Test _PPC (Performance Present Capabilities)." },
> + { method_test_PPE, "Test _PPE (Polling for Platform Error)." },
> + { method_test_PSD, "Test _PSD (Power State Dependencies)." },
> + { method_test_PTC, "Test _PTC (Processor Throttling Control)." },
> + { method_test_TDL, "Test _TDL (T-State Depth Limit)." },
> + { method_test_TPC, "Test _TPC (Throttling Present Capabilities)." },
> + { method_test_TSD, "Test _TSD (Throttling State Dependencies)." },
> + { method_test_TSS, "Test _TSS (Throttling Supported States)." },
> +
> + /* Section 8.4.4 Lower Power Idle States */
> + { method_test_LPI, "Test _LPI (Low Power Idle States)." },
> + { method_test_RDI, "Test _RDI (Resource Dependencies for Idle)." },
> +
> + /* Section 8.5 Processor Aggregator Device */
> + { method_test_PUR, "Test _PUR (Processor Utilization Request)." },
> +
> + /* Section 9.1 System Indicators */
> + { method_test_MSG, "Test _MSG (Message)." },
> + { method_test_SST, "Test _SST (System Status)." },
> +
> + /* Section 9.2 Ambient Light Sensor Device */
> +
> + { method_test_ALC, "Test _ALC (Ambient Light Colour Chromaticity)." },
> + { method_test_ALI, "Test _ALI (Ambient Light Illuminance)." },
> + { method_test_ALT, "Test _ALT (Ambient Light Temperature)." },
> + { method_test_ALP, "Test _ALP (Ambient Light Polling)."},
> + { method_test_ALR, "Test _ALR (Ambient Light Response)."},
> +
> + /* Section 9.3 Battery Device */
> +
> + /* Section 9.4 Lid Device */
> +
> + { method_test_LID, "Test _LID (Lid Status)." },
> +
> + /* Section 9.8 ATA Controllers */
> + { method_test_GTF, "Test _GTF (Get Task File)." },
> + { method_test_GTM, "Test _GTM (Get Timing Mode)." },
> + /* { method_test_SDD, "Test _SDD (Set Device Data)." }, */
> + /* { method_test_STM, "Test _STM (Set Timing Mode)." }, */
> +
> + /* Section 9.9 Floppy Controllers */
> + /* { method_test_FDE, "Test _FDE (Floppy Disk Enumerate)." }, */
> + /* { method_test_FDI, "Test _FDI (Floppy Drive Information)." }, */
> + /* { method_test_FDM, "Test _FDM (Floppy Drive Mode)." }, */
> +
> + /* Section 9.12 Memory Devices */
> + { method_test_MBM, "Test _MBM (Memory Bandwidth Monitoring Data)." },
> + /* { method_test_MSM, "Test _MSM (Memory Set Monitoring)." }, */
> +
> + /* Section 9.13 USB Port Capabilities */
> + { method_test_UPC, "Test _UPC (USB Port Capabilities)." },
> +
> + /* Section 9.14 Device Object Name Collision */
> + /* { method_test_DSM, "Test _DSM (Device Specific Method)." }, */
> +
> + /* Section 9.16 User Presence Detection Device */
> + { method_test_UPD, "Test _UPD (User Presence Detect)." },
> + { method_test_UPP, "Test _UPP (User Presence Polling)." },
> +
> + /* Section 9.18 Wake Alarm Device */
> +
> + { method_test_GCP, "Test _GCP (Get Capabilities)." },
> + { method_test_GRT, "Test _GRT (Get Real Time)." },
> + { method_test_GWS, "Test _GWS (Get Wake Status)." },
> + { method_test_CWS, "Test _CWS (Clear Wake Status)." },
> + { method_test_SRT, "Test _SRT (Set Real Time)." },
> + { method_test_STP, "Test _STP (Set Expired Timer Wake Policy)." },
> + { method_test_STV, "Test _STV (Set Timer Value)." },
> + { method_test_TIP, "Test _TIP (Expired Timer Wake Policy)." },
> + { method_test_TIV, "Test _TIV (Timer Values)." },
> +
> + /* Section 10.1 Smart Battery */
> +
> + { method_test_SBS, "Test _SBS (Smart Battery Subsystem)." },
> +
> + /* Section 10.2 Battery Controls */
> +
> + { method_test_BCT, "Test _BCT (Battery Charge Time)." },
> + { method_test_BIF, "Test _BIF (Battery Information)." },
> + { method_test_BIX, "Test _BIX (Battery Information Extended)." },
> + { method_test_BMA, "Test _BMA (Battery Measurement Averaging)." },
> + { method_test_BMC, "Test _BMC (Battery Maintenance Control)." },
> + { method_test_BMD, "Test _BMD (Battery Maintenance Data)." },
> + { method_test_BMS, "Test _BMS (Battery Measurement Sampling Time)." },
> + { method_test_BST, "Test _BST (Battery Status)." },
> + { method_test_BTP, "Test _BTP (Battery Trip Point)." },
> + { method_test_BTH, "Test _BTH (Battery Throttle Limit)." },
> + { method_test_BTM, "Test _BTM (Battery Time)." },
> + /* { method_test_BLT, "Test _BLT (Battery Level Threshold)." }, */
> +
> + /* Section 10.3 AC Adapters and Power Source Objects */
> +
> + { method_test_PCL, "Test _PCL (Power Consumer List)." },
> + { method_test_PIF, "Test _PIF (Power Source Information)." },
> + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." },
> + { method_test_PSR, "Test _PSR (Power Source)." },
> +
> + /* Section 10.4 Power Meters */
> + { method_test_GAI, "Test _GAI (Get Averaging Level)." },
> + { method_test_GHL, "Test _GHL (Get Harware Limit)." },
> + /* { method_test_PAI, "Test _PAI (Power Averaging Interval)." }, */
> + { method_test_PMC, "Test _PMC (Power Meter Capabilities)." },
> + { method_test_PMD, "Test _PMD (Power Meter Devices)." },
> + { method_test_PMM, "Test _PMM (Power Meter Measurement)." },
> + /* { method_test_PTP, "Test _PTP (Power Trip Points)." }, */
> + /* { method_test_SHL, "Test _SHL (Set Hardware Limit)." }, */
> +
> + /* Section 10.5 Wireless Power Controllers */
> + { method_test_WPC, "Test _WPC (Wireless Power Calibration)." },
> + { method_test_WPP, "Test _WPP (Wireless Power Polling)." },
> +
> + /* Section 11.3 Fan Devices */
> +
> + { method_test_FIF, "Test _FIF (Fan Information)." },
> + { method_test_FPS, "Test _FPS (Fan Performance States)." },
> + { method_test_FSL, "Test _FSL (Fan Set Level)." },
> + { method_test_FST, "Test _FST (Fan Status)." },
> +
> + /* Section 11.4 Thermal Objects */
> +
> + { method_test_ACx, "Test _ACx (Active Cooling)." },
> + { method_test_ART, "Test _ART (Active Cooling Relationship Table)." },
> + /* { method_test_ALx, "Test _ALx (Active List)". }, */
> + { method_test_CRT, "Test _CRT (Critical Trip Point)." },
> + { method_test_CR3, "Test _CR3 (Warm/Standby Temperature)." },
> + { method_test_DTI, "Test _DTI (Device Temperature Indication)." },
> + { method_test_HOT, "Test _HOT (Hot Temperature)." },
> + { method_test_MTL, "Test _MTL (Minimum Throttle Limit)." },
> + { method_test_NTT, "Test _NTT (Notification Temp Threshold)." },
> + { method_test_PSL, "Test _PSL (Passive List)." },
> + { method_test_PSV, "Test _PSV (Passive Temp)." },
> + { method_test_RTV, "Test _RTV (Relative Temp Values)." },
> + { method_test_SCP, "Test _SCP (Set Cooling Policy)." },
> + { method_test_TC1, "Test _TC1 (Thermal Constant 1)." },
> + { method_test_TC2, "Test _TC2 (Thermal Constant 2)." },
> + { method_test_TFP, "Test _TFP (Thermal fast Sampling Period)." },
> + { method_test_TMP, "Test _TMP (Thermal Zone Current Temp)." },
> + { method_test_TPT, "Test _TPT (Trip Point Temperature)." },
> + { method_test_TRT, "Test _TRT (Thermal Relationship Table)." },
> + { method_test_TSN, "Test _TSN (Thermal Sensor Device)." },
> + { method_test_TSP, "Test _TSP (Thermal Sampling Period)." },
> + { method_test_TST, "Test _TST (Temperature Sensor Threshold)." },
> + { method_test_TZD, "Test _TZD (Thermal Zone Devices)." },
> + { method_test_TZM, "Test _TZM (Thermal Zone member)." },
> + { method_test_TZP, "Test _TZP (Thermal Zone Polling)." },
> +
> + /* Section 12 Embedded Controller Interface */
> + { method_test_GPE, "Test _GPE (General Purpose Events)." },
> + { method_test_EC_, "Test _EC_ (EC Offset Query)." },
> +
> + /* Section 16 Waking and Sleeping */
> +
> + { method_test_PTS, "Test _PTS (Prepare to Sleep)." },
> + { method_test_TTS, "Test _TTS (Transition to State)." },
> + { method_test_WAK, "Test _WAK (System Wake)." },
> +
> + /* Appendix B, ACPI Extensions for Display Adapters */
> +
> + { method_test_ADR, "Test _ADR (Return Unique ID for Device)." },
> + { method_test_BCL, "Test _BCL (Query List of Brightness Control Levels Supported)." },
> + { method_test_BCM, "Test _BCM (Set Brightness Level)." },
> + { method_test_BQC, "Test _BQC (Brightness Query Current Level)." },
> + { method_test_DCS, "Test _DCS (Return the Status of Output Device)." },
> + { method_test_DDC, "Test _DDC (Return the EDID for this Device)." },
> + { method_test_DSS, "Test _DSS (Device Set State)." },
> + { method_test_DGS, "Test _DGS (Query Graphics State)." },
> + { method_test_DOD, "Test _DOD (Enumerate All Devices Attached to Display Adapter)." },
> + { method_test_DOS, "Test _DOS (Enable/Disable Output Switching)." },
> + { method_test_GPD, "Test _GPD (Get POST Device)." },
> + { method_test_ROM, "Test _ROM (Get ROM Data)." },
> + { method_test_SPD, "Test _SPD (Set POST Device)." },
> + { method_test_VPO, "Test _VPO (Video POST Options)." },
> +
> + /* From PCI Specification */
> + { method_test_CBA, "Test _CBA (Configuration Base Address)." },
> +
> + /* From IPMI Specification 2.0 */
> + { method_test_IFT, "Test _IFT (IPMI Interface Type)." },
> + { method_test_SRV, "Test _SRV (IPMI Interface Revision)." },
> +
> + /* From ARM SBBR */
> + { sbbr_method_test_ADR, "SBBR Test _ADR (Return Unique ID for Device)." },
> + { sbbr_method_test_AEI, "SBBR Test _AEI (Event Information)." },
> + { sbbr_method_test_CCA, "SBBR Test _CCA (Cache Coherency Attribute)." },
> + { sbbr_method_test_EVT, "SBBR Test _EVT (Event Method)." },
> + { sbbr_method_test_HID, "SBBR Test _HID (Hardware ID)." },
> + { sbbr_method_test_OSI, "SBBR Test _OSI (Operating System Interfaces)." },
> + { sbbr_method_test_SST, "SBBR Test _SST (System Status)." },
> + { sbbr_method_test_STA, "SBBR Test _STA (Status)." },
> + { sbbr_method_test_UID, "SBBR Test _UID (Unique ID)." },
> +
> + /* End! */
> +
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops sbbr_method_ops = {
> + .description = "ACPI DSDT Method Semantic tests.",
> + .init = sbbr_method_init,
> + .deinit = sbbr_method_deinit,
> + .minor_tests = sbbr_method_tests
> +};
> +
> +FWTS_REGISTER("sbbr_method", &sbbr_method_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_TEST_SBBR)
> +
> +#endif
>
More information about the fwts-devel
mailing list