162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: dsmthdat - control method arguments and local variables 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci ******************************************************************************/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <acpi/acpi.h> 962306a36Sopenharmony_ci#include "accommon.h" 1062306a36Sopenharmony_ci#include "acdispat.h" 1162306a36Sopenharmony_ci#include "acnamesp.h" 1262306a36Sopenharmony_ci#include "acinterp.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_DISPATCHER 1562306a36Sopenharmony_ciACPI_MODULE_NAME("dsmthdat") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Local prototypes */ 1862306a36Sopenharmony_cistatic void 1962306a36Sopenharmony_ciacpi_ds_method_data_delete_value(u8 type, 2062306a36Sopenharmony_ci u32 index, struct acpi_walk_state *walk_state); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic acpi_status 2362306a36Sopenharmony_ciacpi_ds_method_data_set_value(u8 type, 2462306a36Sopenharmony_ci u32 index, 2562306a36Sopenharmony_ci union acpi_operand_object *object, 2662306a36Sopenharmony_ci struct acpi_walk_state *walk_state); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS 2962306a36Sopenharmony_ciacpi_object_type 3062306a36Sopenharmony_ciacpi_ds_method_data_get_type(u16 opcode, 3162306a36Sopenharmony_ci u32 index, struct acpi_walk_state *walk_state); 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/******************************************************************************* 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_init 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state object 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * RETURN: Status 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * DESCRIPTION: Initialize the data structures that hold the method's arguments 4362306a36Sopenharmony_ci * and locals. The data struct is an array of namespace nodes for 4462306a36Sopenharmony_ci * each - this allows ref_of and de_ref_of to work properly for these 4562306a36Sopenharmony_ci * special data types. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * NOTES: walk_state fields are initialized to zero by the 4862306a36Sopenharmony_ci * ACPI_ALLOCATE_ZEROED(). 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * A pseudo-Namespace Node is assigned to each argument and local 5162306a36Sopenharmony_ci * so that ref_of() can return a pointer to the Node. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci ******************************************************************************/ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid acpi_ds_method_data_init(struct acpi_walk_state *walk_state) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci u32 i; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_init); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Init the method arguments */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { 6462306a36Sopenharmony_ci ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name, 6562306a36Sopenharmony_ci NAMEOF_ARG_NTE); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci walk_state->arguments[i].name.integer |= (i << 24); 6862306a36Sopenharmony_ci walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED; 6962306a36Sopenharmony_ci walk_state->arguments[i].type = ACPI_TYPE_ANY; 7062306a36Sopenharmony_ci walk_state->arguments[i].flags = ANOBJ_METHOD_ARG; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci /* Init the method locals */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { 7662306a36Sopenharmony_ci ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name, 7762306a36Sopenharmony_ci NAMEOF_LOCAL_NTE); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci walk_state->local_variables[i].name.integer |= (i << 24); 8062306a36Sopenharmony_ci walk_state->local_variables[i].descriptor_type = 8162306a36Sopenharmony_ci ACPI_DESC_TYPE_NAMED; 8262306a36Sopenharmony_ci walk_state->local_variables[i].type = ACPI_TYPE_ANY; 8362306a36Sopenharmony_ci walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return_VOID; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/******************************************************************************* 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_delete_all 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk state object 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * RETURN: None 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * DESCRIPTION: Delete method locals and arguments. Arguments are only 9862306a36Sopenharmony_ci * deleted if this method was called from another method. 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci ******************************************************************************/ 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_civoid acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 index; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_delete_all); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Detach the locals */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) { 11162306a36Sopenharmony_ci if (walk_state->local_variables[index].object) { 11262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n", 11362306a36Sopenharmony_ci index, 11462306a36Sopenharmony_ci walk_state->local_variables[index]. 11562306a36Sopenharmony_ci object)); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci /* Detach object (if present) and remove a reference */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci acpi_ns_detach_object(&walk_state-> 12062306a36Sopenharmony_ci local_variables[index]); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Detach the arguments */ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) { 12762306a36Sopenharmony_ci if (walk_state->arguments[index].object) { 12862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n", 12962306a36Sopenharmony_ci index, 13062306a36Sopenharmony_ci walk_state->arguments[index].object)); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Detach object (if present) and remove a reference */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci acpi_ns_detach_object(&walk_state->arguments[index]); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return_VOID; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/******************************************************************************* 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_init_args 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * PARAMETERS: *params - Pointer to a parameter list for the method 14662306a36Sopenharmony_ci * max_param_count - The arg count for this method 14762306a36Sopenharmony_ci * walk_state - Current walk state object 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * RETURN: Status 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * DESCRIPTION: Initialize arguments for a method. The parameter list is a list 15262306a36Sopenharmony_ci * of ACPI operand objects, either null terminated or whose length 15362306a36Sopenharmony_ci * is defined by max_param_count. 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci ******************************************************************************/ 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ciacpi_status 15862306a36Sopenharmony_ciacpi_ds_method_data_init_args(union acpi_operand_object **params, 15962306a36Sopenharmony_ci u32 max_param_count, 16062306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci acpi_status status; 16362306a36Sopenharmony_ci u32 index = 0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!params) { 16862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 16962306a36Sopenharmony_ci "No parameter list passed to method\n")); 17062306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* Copy passed parameters into the new method stack frame */ 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci while ((index < ACPI_METHOD_NUM_ARGS) && 17662306a36Sopenharmony_ci (index < max_param_count) && params[index]) { 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * A valid parameter. 17962306a36Sopenharmony_ci * Store the argument in the method/walk descriptor. 18062306a36Sopenharmony_ci * Do not copy the arg in order to implement call by reference 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci status = 18362306a36Sopenharmony_ci acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index, 18462306a36Sopenharmony_ci params[index], walk_state); 18562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 18662306a36Sopenharmony_ci return_ACPI_STATUS(status); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci index++; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index)); 19362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/******************************************************************************* 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_get_node 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or 20162306a36Sopenharmony_ci * ACPI_REFCLASS_ARG 20262306a36Sopenharmony_ci * index - Which Local or Arg whose type to get 20362306a36Sopenharmony_ci * walk_state - Current walk state object 20462306a36Sopenharmony_ci * node - Where the node is returned. 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * RETURN: Status and node 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * DESCRIPTION: Get the Node associated with a local or arg. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci ******************************************************************************/ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciacpi_status 21362306a36Sopenharmony_ciacpi_ds_method_data_get_node(u8 type, 21462306a36Sopenharmony_ci u32 index, 21562306a36Sopenharmony_ci struct acpi_walk_state *walk_state, 21662306a36Sopenharmony_ci struct acpi_namespace_node **node) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_get_node); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Method Locals and Arguments are supported 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci switch (type) { 22462306a36Sopenharmony_ci case ACPI_REFCLASS_LOCAL: 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (index > ACPI_METHOD_MAX_LOCAL) { 22762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 22862306a36Sopenharmony_ci "Local index %u is invalid (max %u)", 22962306a36Sopenharmony_ci index, ACPI_METHOD_MAX_LOCAL)); 23062306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INVALID_INDEX); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Return a pointer to the pseudo-node */ 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci *node = &walk_state->local_variables[index]; 23662306a36Sopenharmony_ci break; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci case ACPI_REFCLASS_ARG: 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (index > ACPI_METHOD_MAX_ARG) { 24162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 24262306a36Sopenharmony_ci "Arg index %u is invalid (max %u)", 24362306a36Sopenharmony_ci index, ACPI_METHOD_MAX_ARG)); 24462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INVALID_INDEX); 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Return a pointer to the pseudo-node */ 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci *node = &walk_state->arguments[index]; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Type %u is invalid", type)); 25562306a36Sopenharmony_ci return_ACPI_STATUS(AE_TYPE); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/******************************************************************************* 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_set_value 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or 26662306a36Sopenharmony_ci * ACPI_REFCLASS_ARG 26762306a36Sopenharmony_ci * index - Which Local or Arg to get 26862306a36Sopenharmony_ci * object - Object to be inserted into the stack entry 26962306a36Sopenharmony_ci * walk_state - Current walk state object 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * RETURN: Status 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. 27462306a36Sopenharmony_ci * Note: There is no "implicit conversion" for locals. 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci ******************************************************************************/ 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic acpi_status 27962306a36Sopenharmony_ciacpi_ds_method_data_set_value(u8 type, 28062306a36Sopenharmony_ci u32 index, 28162306a36Sopenharmony_ci union acpi_operand_object *object, 28262306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci acpi_status status; 28562306a36Sopenharmony_ci struct acpi_namespace_node *node; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_set_value); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 29062306a36Sopenharmony_ci "NewObj %p Type %2.2X, Refs=%u [%s]\n", object, 29162306a36Sopenharmony_ci type, object->common.reference_count, 29262306a36Sopenharmony_ci acpi_ut_get_type_name(object->common.type))); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Get the namespace node for the arg/local */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci status = acpi_ds_method_data_get_node(type, index, walk_state, &node); 29762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 29862306a36Sopenharmony_ci return_ACPI_STATUS(status); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Increment ref count so object can't be deleted while installed. 30362306a36Sopenharmony_ci * NOTE: We do not copy the object in order to preserve the call by 30462306a36Sopenharmony_ci * reference semantics of ACPI Control Method invocation. 30562306a36Sopenharmony_ci * (See ACPI Specification 2.0C) 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci acpi_ut_add_reference(object); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Install the object */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci node->object = object; 31262306a36Sopenharmony_ci return_ACPI_STATUS(status); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/******************************************************************************* 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_get_value 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or 32062306a36Sopenharmony_ci * ACPI_REFCLASS_ARG 32162306a36Sopenharmony_ci * index - Which localVar or argument to get 32262306a36Sopenharmony_ci * walk_state - Current walk state object 32362306a36Sopenharmony_ci * dest_desc - Where Arg or Local value is returned 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * RETURN: Status 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * DESCRIPTION: Retrieve value of selected Arg or Local for this method 32862306a36Sopenharmony_ci * Used only in acpi_ex_resolve_to_value(). 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci ******************************************************************************/ 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciacpi_status 33362306a36Sopenharmony_ciacpi_ds_method_data_get_value(u8 type, 33462306a36Sopenharmony_ci u32 index, 33562306a36Sopenharmony_ci struct acpi_walk_state *walk_state, 33662306a36Sopenharmony_ci union acpi_operand_object **dest_desc) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci acpi_status status; 33962306a36Sopenharmony_ci struct acpi_namespace_node *node; 34062306a36Sopenharmony_ci union acpi_operand_object *object; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_get_value); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Validate the object descriptor */ 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!dest_desc) { 34762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Null object descriptor pointer")); 34862306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Get the namespace node for the arg/local */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci status = acpi_ds_method_data_get_node(type, index, walk_state, &node); 35462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 35562306a36Sopenharmony_ci return_ACPI_STATUS(status); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Get the object from the node */ 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci object = node->object; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Examine the returned object, it must be valid. */ 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!object) { 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * Index points to uninitialized object. 36762306a36Sopenharmony_ci * This means that either 1) The expected argument was 36862306a36Sopenharmony_ci * not passed to the method, or 2) A local variable 36962306a36Sopenharmony_ci * was referenced by the method (via the ASL) 37062306a36Sopenharmony_ci * before it was initialized. Either case is an error. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (acpi_gbl_enable_interpreter_slack) { 37662306a36Sopenharmony_ci object = acpi_ut_create_integer_object((u64) 0); 37762306a36Sopenharmony_ci if (!object) { 37862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci node->object = object; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Otherwise, return the error */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci switch (type) { 38862306a36Sopenharmony_ci case ACPI_REFCLASS_ARG: 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 39162306a36Sopenharmony_ci "Uninitialized Arg[%u] at node %p", 39262306a36Sopenharmony_ci index, node)); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci case ACPI_REFCLASS_LOCAL: 39762306a36Sopenharmony_ci /* 39862306a36Sopenharmony_ci * No error message for this case, will be trapped again later to 39962306a36Sopenharmony_ci * detect and ignore cases of Store(local_x,local_x) 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci default: 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 40662306a36Sopenharmony_ci "Not a Arg/Local opcode: 0x%X", 40762306a36Sopenharmony_ci type)); 40862306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * The Index points to an initialized and valid object. 41462306a36Sopenharmony_ci * Return an additional reference to the object 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci *dest_desc = object; 41762306a36Sopenharmony_ci acpi_ut_add_reference(object); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci/******************************************************************************* 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_delete_value 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or 42762306a36Sopenharmony_ci * ACPI_REFCLASS_ARG 42862306a36Sopenharmony_ci * index - Which localVar or argument to delete 42962306a36Sopenharmony_ci * walk_state - Current walk state object 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * RETURN: None 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * DESCRIPTION: Delete the entry at Opcode:Index. Inserts 43462306a36Sopenharmony_ci * a null into the stack slot after the object is deleted. 43562306a36Sopenharmony_ci * 43662306a36Sopenharmony_ci ******************************************************************************/ 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic void 43962306a36Sopenharmony_ciacpi_ds_method_data_delete_value(u8 type, 44062306a36Sopenharmony_ci u32 index, struct acpi_walk_state *walk_state) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci acpi_status status; 44362306a36Sopenharmony_ci struct acpi_namespace_node *node; 44462306a36Sopenharmony_ci union acpi_operand_object *object; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_delete_value); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Get the namespace node for the arg/local */ 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci status = acpi_ds_method_data_get_node(type, index, walk_state, &node); 45162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 45262306a36Sopenharmony_ci return_VOID; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* Get the associated object */ 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci object = acpi_ns_get_attached_object(node); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* 46062306a36Sopenharmony_ci * Undefine the Arg or Local by setting its descriptor 46162306a36Sopenharmony_ci * pointer to NULL. Locals/Args can contain both 46262306a36Sopenharmony_ci * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci node->object = NULL; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if ((object) && 46762306a36Sopenharmony_ci (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) { 46862306a36Sopenharmony_ci /* 46962306a36Sopenharmony_ci * There is a valid object. 47062306a36Sopenharmony_ci * Decrement the reference count by one to balance the 47162306a36Sopenharmony_ci * increment when the object was stored. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci acpi_ut_remove_reference(object); 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return_VOID; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/******************************************************************************* 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci * FUNCTION: acpi_ds_store_object_to_local 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or 48462306a36Sopenharmony_ci * ACPI_REFCLASS_ARG 48562306a36Sopenharmony_ci * index - Which Local or Arg to set 48662306a36Sopenharmony_ci * obj_desc - Value to be stored 48762306a36Sopenharmony_ci * walk_state - Current walk state 48862306a36Sopenharmony_ci * 48962306a36Sopenharmony_ci * RETURN: Status 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed 49262306a36Sopenharmony_ci * as the new value for the Arg or Local and the reference count 49362306a36Sopenharmony_ci * for obj_desc is incremented. 49462306a36Sopenharmony_ci * 49562306a36Sopenharmony_ci ******************************************************************************/ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ciacpi_status 49862306a36Sopenharmony_ciacpi_ds_store_object_to_local(u8 type, 49962306a36Sopenharmony_ci u32 index, 50062306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 50162306a36Sopenharmony_ci struct acpi_walk_state *walk_state) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci acpi_status status; 50462306a36Sopenharmony_ci struct acpi_namespace_node *node; 50562306a36Sopenharmony_ci union acpi_operand_object *current_obj_desc; 50662306a36Sopenharmony_ci union acpi_operand_object *new_obj_desc; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_store_object_to_local); 50962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n", 51062306a36Sopenharmony_ci type, index, obj_desc)); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* Parameter validation */ 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (!obj_desc) { 51562306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* Get the namespace node for the arg/local */ 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci status = acpi_ds_method_data_get_node(type, index, walk_state, &node); 52162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 52262306a36Sopenharmony_ci return_ACPI_STATUS(status); 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci current_obj_desc = acpi_ns_get_attached_object(node); 52662306a36Sopenharmony_ci if (current_obj_desc == obj_desc) { 52762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n", 52862306a36Sopenharmony_ci obj_desc)); 52962306a36Sopenharmony_ci return_ACPI_STATUS(status); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* 53362306a36Sopenharmony_ci * If the reference count on the object is more than one, we must 53462306a36Sopenharmony_ci * take a copy of the object before we store. A reference count 53562306a36Sopenharmony_ci * of exactly 1 means that the object was just created during the 53662306a36Sopenharmony_ci * evaluation of an expression, and we can safely use it since it 53762306a36Sopenharmony_ci * is not used anywhere else. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci new_obj_desc = obj_desc; 54062306a36Sopenharmony_ci if (obj_desc->common.reference_count > 1) { 54162306a36Sopenharmony_ci status = 54262306a36Sopenharmony_ci acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc, 54362306a36Sopenharmony_ci walk_state); 54462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 54562306a36Sopenharmony_ci return_ACPI_STATUS(status); 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* 55062306a36Sopenharmony_ci * If there is an object already in this slot, we either 55162306a36Sopenharmony_ci * have to delete it, or if this is an argument and there 55262306a36Sopenharmony_ci * is an object reference stored there, we have to do 55362306a36Sopenharmony_ci * an indirect store! 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci if (current_obj_desc) { 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * Check for an indirect store if an argument 55862306a36Sopenharmony_ci * contains an object reference (stored as an Node). 55962306a36Sopenharmony_ci * We don't allow this automatic dereferencing for 56062306a36Sopenharmony_ci * locals, since a store to a local should overwrite 56162306a36Sopenharmony_ci * anything there, including an object reference. 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * If both Arg0 and Local0 contain ref_of (Local4): 56462306a36Sopenharmony_ci * 56562306a36Sopenharmony_ci * Store (1, Arg0) - Causes indirect store to local4 56662306a36Sopenharmony_ci * Store (1, Local0) - Stores 1 in local0, overwriting 56762306a36Sopenharmony_ci * the reference to local4 56862306a36Sopenharmony_ci * Store (1, de_refof (Local0)) - Causes indirect store to local4 56962306a36Sopenharmony_ci * 57062306a36Sopenharmony_ci * Weird, but true. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci if (type == ACPI_REFCLASS_ARG) { 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * If we have a valid reference object that came from ref_of(), 57562306a36Sopenharmony_ci * do the indirect store 57662306a36Sopenharmony_ci */ 57762306a36Sopenharmony_ci if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) == 57862306a36Sopenharmony_ci ACPI_DESC_TYPE_OPERAND) && 57962306a36Sopenharmony_ci (current_obj_desc->common.type == 58062306a36Sopenharmony_ci ACPI_TYPE_LOCAL_REFERENCE) && 58162306a36Sopenharmony_ci (current_obj_desc->reference.class == 58262306a36Sopenharmony_ci ACPI_REFCLASS_REFOF)) { 58362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 58462306a36Sopenharmony_ci "Arg (%p) is an ObjRef(Node), storing in node %p\n", 58562306a36Sopenharmony_ci new_obj_desc, 58662306a36Sopenharmony_ci current_obj_desc)); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * Store this object to the Node (perform the indirect store) 59062306a36Sopenharmony_ci * NOTE: No implicit conversion is performed, as per the ACPI 59162306a36Sopenharmony_ci * specification rules on storing to Locals/Args. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_ci status = 59462306a36Sopenharmony_ci acpi_ex_store_object_to_node(new_obj_desc, 59562306a36Sopenharmony_ci current_obj_desc-> 59662306a36Sopenharmony_ci reference. 59762306a36Sopenharmony_ci object, 59862306a36Sopenharmony_ci walk_state, 59962306a36Sopenharmony_ci ACPI_NO_IMPLICIT_CONVERSION); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Remove local reference if we copied the object above */ 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (new_obj_desc != obj_desc) { 60462306a36Sopenharmony_ci acpi_ut_remove_reference(new_obj_desc); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return_ACPI_STATUS(status); 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* Delete the existing object before storing the new one */ 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci acpi_ds_method_data_delete_value(type, index, walk_state); 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci /* 61762306a36Sopenharmony_ci * Install the Obj descriptor (*new_obj_desc) into 61862306a36Sopenharmony_ci * the descriptor for the Arg or Local. 61962306a36Sopenharmony_ci * (increments the object reference count by one) 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci status = 62262306a36Sopenharmony_ci acpi_ds_method_data_set_value(type, index, new_obj_desc, 62362306a36Sopenharmony_ci walk_state); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Remove local reference if we copied the object above */ 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (new_obj_desc != obj_desc) { 62862306a36Sopenharmony_ci acpi_ut_remove_reference(new_obj_desc); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return_ACPI_STATUS(status); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS 63562306a36Sopenharmony_ci/******************************************************************************* 63662306a36Sopenharmony_ci * 63762306a36Sopenharmony_ci * FUNCTION: acpi_ds_method_data_get_type 63862306a36Sopenharmony_ci * 63962306a36Sopenharmony_ci * PARAMETERS: opcode - Either AML_FIRST LOCAL_OP or 64062306a36Sopenharmony_ci * AML_FIRST_ARG_OP 64162306a36Sopenharmony_ci * index - Which Local or Arg whose type to get 64262306a36Sopenharmony_ci * walk_state - Current walk state object 64362306a36Sopenharmony_ci * 64462306a36Sopenharmony_ci * RETURN: Data type of current value of the selected Arg or Local 64562306a36Sopenharmony_ci * 64662306a36Sopenharmony_ci * DESCRIPTION: Get the type of the object stored in the Local or Arg 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci ******************************************************************************/ 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ciacpi_object_type 65162306a36Sopenharmony_ciacpi_ds_method_data_get_type(u16 opcode, 65262306a36Sopenharmony_ci u32 index, struct acpi_walk_state *walk_state) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci acpi_status status; 65562306a36Sopenharmony_ci struct acpi_namespace_node *node; 65662306a36Sopenharmony_ci union acpi_operand_object *object; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_method_data_get_type); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* Get the namespace node for the arg/local */ 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node); 66362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 66462306a36Sopenharmony_ci return_VALUE((ACPI_TYPE_NOT_FOUND)); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Get the object */ 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci object = acpi_ns_get_attached_object(node); 67062306a36Sopenharmony_ci if (!object) { 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* Uninitialized local/arg, return TYPE_ANY */ 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return_VALUE(ACPI_TYPE_ANY); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Get the object type */ 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return_VALUE(object->type); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci#endif 682