162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: uteval - Object evaluation
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acnamesp.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_UTILITIES
1562306a36Sopenharmony_ciACPI_MODULE_NAME("uteval")
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*******************************************************************************
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * FUNCTION:    acpi_ut_evaluate_object
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * PARAMETERS:  prefix_node         - Starting node
2262306a36Sopenharmony_ci *              path                - Path to object from starting node
2362306a36Sopenharmony_ci *              expected_return_types - Bitmap of allowed return types
2462306a36Sopenharmony_ci *              return_desc         - Where a return value is stored
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * RETURN:      Status
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * DESCRIPTION: Evaluates a namespace object and verifies the type of the
2962306a36Sopenharmony_ci *              return object. Common code that simplifies accessing objects
3062306a36Sopenharmony_ci *              that have required return objects of fixed types.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci *              NOTE: Internal function, no parameter validation
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci ******************************************************************************/
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciacpi_status
3762306a36Sopenharmony_ciacpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
3862306a36Sopenharmony_ci			const char *path,
3962306a36Sopenharmony_ci			u32 expected_return_btypes,
4062306a36Sopenharmony_ci			union acpi_operand_object **return_desc)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct acpi_evaluate_info *info;
4362306a36Sopenharmony_ci	acpi_status status;
4462306a36Sopenharmony_ci	u32 return_btype;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_evaluate_object);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/* Allocate the evaluation information block */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
5162306a36Sopenharmony_ci	if (!info) {
5262306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	info->prefix_node = prefix_node;
5662306a36Sopenharmony_ci	info->relative_pathname = path;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Evaluate the object/method */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	status = acpi_ns_evaluate(info);
6162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
6262306a36Sopenharmony_ci		if (status == AE_NOT_FOUND) {
6362306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
6462306a36Sopenharmony_ci					  "[%4.4s.%s] was not found\n",
6562306a36Sopenharmony_ci					  acpi_ut_get_node_name(prefix_node),
6662306a36Sopenharmony_ci					  path));
6762306a36Sopenharmony_ci		} else {
6862306a36Sopenharmony_ci			ACPI_ERROR_METHOD("Method execution failed",
6962306a36Sopenharmony_ci					  prefix_node, path, status);
7062306a36Sopenharmony_ci		}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		goto cleanup;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Did we get a return object? */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (!info->return_object) {
7862306a36Sopenharmony_ci		if (expected_return_btypes) {
7962306a36Sopenharmony_ci			ACPI_ERROR_METHOD("No object was returned from",
8062306a36Sopenharmony_ci					  prefix_node, path, AE_NOT_EXIST);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci			status = AE_NOT_EXIST;
8362306a36Sopenharmony_ci		}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		goto cleanup;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* Map the return object type to the bitmapped type */
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	switch ((info->return_object)->common.type) {
9162306a36Sopenharmony_ci	case ACPI_TYPE_INTEGER:
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		return_btype = ACPI_BTYPE_INTEGER;
9462306a36Sopenharmony_ci		break;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	case ACPI_TYPE_BUFFER:
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		return_btype = ACPI_BTYPE_BUFFER;
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	case ACPI_TYPE_STRING:
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci		return_btype = ACPI_BTYPE_STRING;
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	case ACPI_TYPE_PACKAGE:
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		return_btype = ACPI_BTYPE_PACKAGE;
10962306a36Sopenharmony_ci		break;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	default:
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		return_btype = 0;
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) {
11862306a36Sopenharmony_ci		/*
11962306a36Sopenharmony_ci		 * We received a return object, but one was not expected. This can
12062306a36Sopenharmony_ci		 * happen frequently if the "implicit return" feature is enabled.
12162306a36Sopenharmony_ci		 * Just delete the return object and return AE_OK.
12262306a36Sopenharmony_ci		 */
12362306a36Sopenharmony_ci		acpi_ut_remove_reference(info->return_object);
12462306a36Sopenharmony_ci		goto cleanup;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/* Is the return object one of the expected types? */
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (!(expected_return_btypes & return_btype)) {
13062306a36Sopenharmony_ci		ACPI_ERROR_METHOD("Return object type is incorrect",
13162306a36Sopenharmony_ci				  prefix_node, path, AE_TYPE);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO,
13462306a36Sopenharmony_ci			    "Type returned from %s was incorrect: %s, expected Btypes: 0x%X",
13562306a36Sopenharmony_ci			    path,
13662306a36Sopenharmony_ci			    acpi_ut_get_object_type_name(info->return_object),
13762306a36Sopenharmony_ci			    expected_return_btypes));
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		/* On error exit, we must delete the return object */
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		acpi_ut_remove_reference(info->return_object);
14262306a36Sopenharmony_ci		status = AE_TYPE;
14362306a36Sopenharmony_ci		goto cleanup;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* Object type is OK, return it */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	*return_desc = info->return_object;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cicleanup:
15162306a36Sopenharmony_ci	ACPI_FREE(info);
15262306a36Sopenharmony_ci	return_ACPI_STATUS(status);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci/*******************************************************************************
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * FUNCTION:    acpi_ut_evaluate_numeric_object
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * PARAMETERS:  object_name         - Object name to be evaluated
16062306a36Sopenharmony_ci *              device_node         - Node for the device
16162306a36Sopenharmony_ci *              value               - Where the value is returned
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci * RETURN:      Status
16462306a36Sopenharmony_ci *
16562306a36Sopenharmony_ci * DESCRIPTION: Evaluates a numeric namespace object for a selected device
16662306a36Sopenharmony_ci *              and stores result in *Value.
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci *              NOTE: Internal function, no parameter validation
16962306a36Sopenharmony_ci *
17062306a36Sopenharmony_ci ******************************************************************************/
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciacpi_status
17362306a36Sopenharmony_ciacpi_ut_evaluate_numeric_object(const char *object_name,
17462306a36Sopenharmony_ci				struct acpi_namespace_node *device_node,
17562306a36Sopenharmony_ci				u64 *value)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
17862306a36Sopenharmony_ci	acpi_status status;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_evaluate_numeric_object);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	status = acpi_ut_evaluate_object(device_node, object_name,
18362306a36Sopenharmony_ci					 ACPI_BTYPE_INTEGER, &obj_desc);
18462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
18562306a36Sopenharmony_ci		return_ACPI_STATUS(status);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* Get the returned Integer */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	*value = obj_desc->integer.value;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* On exit, we must delete the return object */
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	acpi_ut_remove_reference(obj_desc);
19562306a36Sopenharmony_ci	return_ACPI_STATUS(status);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/*******************************************************************************
19962306a36Sopenharmony_ci *
20062306a36Sopenharmony_ci * FUNCTION:    acpi_ut_execute_STA
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * PARAMETERS:  device_node         - Node for the device
20362306a36Sopenharmony_ci *              flags               - Where the status flags are returned
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * RETURN:      Status
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * DESCRIPTION: Executes _STA for selected device and stores results in
20862306a36Sopenharmony_ci *              *Flags. If _STA does not exist, then the device is assumed
20962306a36Sopenharmony_ci *              to be present/functional/enabled (as per the ACPI spec).
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci *              NOTE: Internal function, no parameter validation
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci ******************************************************************************/
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciacpi_status
21662306a36Sopenharmony_ciacpi_ut_execute_STA(struct acpi_namespace_node *device_node, u32 * flags)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
21962306a36Sopenharmony_ci	acpi_status status;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_execute_STA);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__STA,
22462306a36Sopenharmony_ci					 ACPI_BTYPE_INTEGER, &obj_desc);
22562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
22662306a36Sopenharmony_ci		if (AE_NOT_FOUND == status) {
22762306a36Sopenharmony_ci			/*
22862306a36Sopenharmony_ci			 * if _STA does not exist, then (as per the ACPI specification),
22962306a36Sopenharmony_ci			 * the returned flags will indicate that the device is present,
23062306a36Sopenharmony_ci			 * functional, and enabled.
23162306a36Sopenharmony_ci			 */
23262306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
23362306a36Sopenharmony_ci					  "_STA on %4.4s was not found, assuming device is present\n",
23462306a36Sopenharmony_ci					  acpi_ut_get_node_name(device_node)));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci			*flags = ACPI_UINT32_MAX;
23762306a36Sopenharmony_ci			status = AE_OK;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		return_ACPI_STATUS(status);
24162306a36Sopenharmony_ci	}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* Extract the status flags */
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	*flags = (u32) obj_desc->integer.value;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* On exit, we must delete the return object */
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	acpi_ut_remove_reference(obj_desc);
25062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/*******************************************************************************
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * FUNCTION:    acpi_ut_execute_power_methods
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * PARAMETERS:  device_node         - Node for the device
25862306a36Sopenharmony_ci *              method_names        - Array of power method names
25962306a36Sopenharmony_ci *              method_count        - Number of methods to execute
26062306a36Sopenharmony_ci *              out_values          - Where the power method values are returned
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * RETURN:      Status, out_values
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * DESCRIPTION: Executes the specified power methods for the device and returns
26562306a36Sopenharmony_ci *              the result(s).
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci *              NOTE: Internal function, no parameter validation
26862306a36Sopenharmony_ci *
26962306a36Sopenharmony_ci******************************************************************************/
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ciacpi_status
27262306a36Sopenharmony_ciacpi_ut_execute_power_methods(struct acpi_namespace_node *device_node,
27362306a36Sopenharmony_ci			      const char **method_names,
27462306a36Sopenharmony_ci			      u8 method_count, u8 *out_values)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
27762306a36Sopenharmony_ci	acpi_status status;
27862306a36Sopenharmony_ci	acpi_status final_status = AE_NOT_FOUND;
27962306a36Sopenharmony_ci	u32 i;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ut_execute_power_methods);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	for (i = 0; i < method_count; i++) {
28462306a36Sopenharmony_ci		/*
28562306a36Sopenharmony_ci		 * Execute the power method (_sx_d or _sx_w). The only allowable
28662306a36Sopenharmony_ci		 * return type is an Integer.
28762306a36Sopenharmony_ci		 */
28862306a36Sopenharmony_ci		status = acpi_ut_evaluate_object(device_node,
28962306a36Sopenharmony_ci						 ACPI_CAST_PTR(char,
29062306a36Sopenharmony_ci							       method_names[i]),
29162306a36Sopenharmony_ci						 ACPI_BTYPE_INTEGER, &obj_desc);
29262306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
29362306a36Sopenharmony_ci			out_values[i] = (u8)obj_desc->integer.value;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci			/* Delete the return object */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci			acpi_ut_remove_reference(obj_desc);
29862306a36Sopenharmony_ci			final_status = AE_OK;	/* At least one value is valid */
29962306a36Sopenharmony_ci			continue;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		out_values[i] = ACPI_UINT8_MAX;
30362306a36Sopenharmony_ci		if (status == AE_NOT_FOUND) {
30462306a36Sopenharmony_ci			continue;	/* Ignore if not found */
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
30862306a36Sopenharmony_ci				  "Failed %s on Device %4.4s, %s\n",
30962306a36Sopenharmony_ci				  ACPI_CAST_PTR(char, method_names[i]),
31062306a36Sopenharmony_ci				  acpi_ut_get_node_name(device_node),
31162306a36Sopenharmony_ci				  acpi_format_exception(status)));
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return_ACPI_STATUS(final_status);
31562306a36Sopenharmony_ci}
316