acpi_status acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node, char *path, u32 expected_return_btypes, union acpi_operand_object **return_desc) { struct acpi_evaluate_info *info; acpi_status status; u32 return_btype; ACPI_FUNCTION_TRACE(ut_evaluate_object); /* Allocate the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } info->prefix_node = prefix_node; info->pathname = path; /* Evaluate the object/method */ status = acpi_ns_evaluate(info); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n", acpi_ut_get_node_name(prefix_node), path)); } else { ACPI_ERROR_METHOD("Method execution failed", prefix_node, path, status); } goto cleanup; } /* Did we get a return object? */ if (!info->return_object) { if (expected_return_btypes) { ACPI_ERROR_METHOD("No object was returned from", prefix_node, path, AE_NOT_EXIST); status = AE_NOT_EXIST; } goto cleanup; } /* Map the return object type to the bitmapped type */ switch ((info->return_object)->common.type) { case ACPI_TYPE_INTEGER: return_btype = ACPI_BTYPE_INTEGER; break; case ACPI_TYPE_BUFFER: return_btype = ACPI_BTYPE_BUFFER; break; case ACPI_TYPE_STRING: return_btype = ACPI_BTYPE_STRING; break; case ACPI_TYPE_PACKAGE: return_btype = ACPI_BTYPE_PACKAGE; break; default: return_btype = 0; break; } if ((acpi_gbl_enable_interpreter_slack) && (!expected_return_btypes)) { /* * We received a return object, but one was not expected. This can * happen frequently if the "implicit return" feature is enabled. * Just delete the return object and return AE_OK. */ acpi_ut_remove_reference(info->return_object); goto cleanup; } /* Is the return object one of the expected types? */ if (!(expected_return_btypes & return_btype)) { ACPI_ERROR_METHOD("Return object type is incorrect", prefix_node, path, AE_TYPE); ACPI_ERROR((AE_INFO, "Type returned from %s was incorrect: %s, expected Btypes: 0x%X", path, acpi_ut_get_object_type_name(info->return_object), expected_return_btypes)); /* On error exit, we must delete the return object */ acpi_ut_remove_reference(info->return_object); status = AE_TYPE; goto cleanup; } /* Object type is OK, return it */ *return_desc = info->return_object; cleanup: ACPI_FREE(info); return_ACPI_STATUS(status); }
acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; u64 index; union acpi_operand_object *this_element; ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { case AML_MATCH_OP: if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || (operand[3]->integer.value > MAX_MATCH_OPERATOR)) { ACPI_ERROR((AE_INFO, "Match operator out of range")); status = AE_AML_OPERAND_VALUE; goto cleanup; } index = operand[5]->integer.value; if (index >= operand[0]->package.count) { ACPI_ERROR((AE_INFO, "Index (0x%8.8X%8.8X) beyond package end (0x%X)", ACPI_FORMAT_UINT64(index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } return_desc = acpi_ut_create_integer_object(ACPI_UINT64_MAX); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } for (; index < operand[0]->package.count; index++) { this_element = operand[0]->package.elements[index]; if (!this_element) { continue; } if (!acpi_ex_do_match((u32) operand[1]->integer.value, this_element, operand[2])) { continue; } if (!acpi_ex_do_match((u32) operand[3]->integer.value, this_element, operand[4])) { continue; } return_desc->integer.value = index; break; } break; case AML_LOAD_TABLE_OP: status = acpi_ex_load_table_op(walk_state, &return_desc); break; default: ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } cleanup: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); } else { walk_state->result_obj = return_desc; } return_ACPI_STATUS(status); }
acpi_status acpi_ds_call_control_method(struct acpi_thread_state *thread, struct acpi_walk_state *this_walk_state, union acpi_parse_object *op) { acpi_status status; struct acpi_namespace_node *method_node; struct acpi_walk_state *next_walk_state = NULL; union acpi_operand_object *obj_desc; struct acpi_evaluate_info *info; u32 i; ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", this_walk_state->prev_op, this_walk_state)); /* * Get the namespace entry for the control method we are about to call */ method_node = this_walk_state->method_call_node; if (!method_node) { return_ACPI_STATUS(AE_NULL_ENTRY); } obj_desc = acpi_ns_get_attached_object(method_node); if (!obj_desc) { return_ACPI_STATUS(AE_NULL_OBJECT); } /* Init for new method, possibly wait on method mutex */ status = acpi_ds_begin_method_execution(method_node, obj_desc, this_walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Begin method parse/execution. Create a new walk state */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, thread); if (!next_walk_state) { status = AE_NO_MEMORY; goto cleanup; } /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always * start at index 0. Also, null terminate the list of arguments */ this_walk_state->operands[this_walk_state->num_operands] = NULL; /* * Allocate and initialize the evaluation information block * TBD: this is somewhat inefficient, should change interface to * ds_init_aml_walk. For now, keeps this struct off the CPU stack */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } info->parameters = &this_walk_state->operands[0]; info->parameter_type = ACPI_PARAM_ARGS; status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, info, ACPI_IMODE_EXECUTE); ACPI_FREE(info); if (ACPI_FAILURE(status)) { goto cleanup; } /* * Delete the operands on the previous walkstate operand stack * (they were copied to new objects) */ for (i = 0; i < obj_desc->method.param_count; i++) { acpi_ut_remove_reference(this_walk_state->operands[i]); this_walk_state->operands[i] = NULL; } /* Clear the operand stack */ this_walk_state->num_operands = 0; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", method_node->name.ascii, next_walk_state)); /* Invoke an internal method if necessary */ if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { status = obj_desc->method.implementation(next_walk_state); } return_ACPI_STATUS(status); cleanup: /* On error, we must terminate the method properly */ acpi_ds_terminate_control_method(obj_desc, next_walk_state); if (next_walk_state) { acpi_ds_delete_walk_state(next_walk_state); } return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_ns_root_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Allocate and initialize the default root named objects * * MUTEX: Locks namespace for entire execution * ******************************************************************************/ acpi_status acpi_ns_root_initialize(void) { acpi_status status; const struct acpi_predefined_names *init_val = NULL; struct acpi_namespace_node *new_node; union acpi_operand_object *obj_desc; acpi_string val = NULL; ACPI_FUNCTION_TRACE(ns_root_initialize); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * The global root ptr is initially NULL, so a non-NULL value indicates * that acpi_ns_root_initialize() has already been called; just return. */ if (acpi_gbl_root_node) { status = AE_OK; goto unlock_and_exit; } /* * Tell the rest of the subsystem that the root is initialized * (This is OK because the namespace is locked) */ acpi_gbl_root_node = &acpi_gbl_root_node_struct; /* Enter the pre-defined names in the name table */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { /* _OSI is optional for now, will be permanent later */ if (!ACPI_STRCMP(init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { continue; } status = acpi_ns_lookup(NULL, init_val->name, init_val->type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); if (ACPI_FAILURE(status) || (!new_node)) { /* Must be on same line for code converter */ ACPI_EXCEPTION((AE_INFO, status, "Could not create predefined name %s", init_val->name)); } /* * Name entered successfully. * If entry in pre_defined_names[] specifies an * initial value, create the initial value. */ if (init_val->val) { status = acpi_os_predefined_override(init_val, &val); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not override predefined %s", init_val->name)); } if (!val) { val = init_val->val; } /* * Entry requests an initial value, allocate a * descriptor for it. */ obj_desc = acpi_ut_create_internal_object(init_val->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* * Convert value string from table entry to * internal representation. Only types actually * used for initial values are implemented here. */ switch (init_val->type) { case ACPI_TYPE_METHOD: obj_desc->method.param_count = (u8) ACPI_TO_INTEGER(val); obj_desc->common.flags |= AOPOBJ_DATA_VALID; #if defined (ACPI_ASL_COMPILER) /* Save the parameter count for the i_aSL compiler */ new_node->value = obj_desc->method.param_count; #else /* Mark this as a very SPECIAL method */ obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; obj_desc->method.implementation = acpi_ut_osi_implementation; #endif break; case ACPI_TYPE_INTEGER: obj_desc->integer.value = ACPI_TO_INTEGER(val); break; case ACPI_TYPE_STRING: /* * Build an object around the static string */ obj_desc->string.length = (u32) ACPI_STRLEN(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER(val) - 1); /* Create a mutex */ status = acpi_os_create_mutex(&obj_desc->mutex. os_mutex); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(obj_desc); goto unlock_and_exit; } /* Special case for ACPI Global Lock */ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { acpi_gbl_global_lock_mutex = obj_desc; /* Create additional counting semaphore for global lock */ status = acpi_os_create_semaphore(1, 0, &acpi_gbl_global_lock_semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); goto unlock_and_exit; } } break; default: ACPI_ERROR((AE_INFO, "Unsupported initial type value %X", init_val->type)); acpi_ut_remove_reference(obj_desc); obj_desc = NULL; continue; } /* Store pointer to value descriptor in the Node */ status = acpi_ns_attach_object(new_node, obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc)); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Save a handle to "_GPE", it is always present */ if (ACPI_SUCCESS(status)) { status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, &acpi_gbl_fadt_gpe_device); } return_ACPI_STATUS(status); }
acpi_status acpi_ds_store_object_to_local(u16 opcode, u32 index, union acpi_operand_object *obj_desc, struct acpi_walk_state *walk_state) { acpi_status status; struct acpi_namespace_node *node; union acpi_operand_object *current_obj_desc; union acpi_operand_object *new_obj_desc; ACPI_FUNCTION_TRACE(ds_store_object_to_local); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", opcode, index, obj_desc)); /* Parameter validation */ if (!obj_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Get the namespace node for the arg/local */ status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } current_obj_desc = acpi_ns_get_attached_object(node); if (current_obj_desc == obj_desc) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n", obj_desc)); return_ACPI_STATUS(status); } /* * If the reference count on the object is more than one, we must * take a copy of the object before we store. A reference count * of exactly 1 means that the object was just created during the * evaluation of an expression, and we can safely use it since it * is not used anywhere else. */ new_obj_desc = obj_desc; if (obj_desc->common.reference_count > 1) { status = acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc, walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* * If there is an object already in this slot, we either * have to delete it, or if this is an argument and there * is an object reference stored there, we have to do * an indirect store! */ if (current_obj_desc) { /* * Check for an indirect store if an argument * contains an object reference (stored as an Node). * We don't allow this automatic dereferencing for * locals, since a store to a local should overwrite * anything there, including an object reference. * * If both Arg0 and Local0 contain ref_of (Local4): * * Store (1, Arg0) - Causes indirect store to local4 * Store (1, Local0) - Stores 1 in local0, overwriting * the reference to local4 * Store (1, de_refof (Local0)) - Causes indirect store to local4 * * Weird, but true. */ if (opcode == AML_ARG_OP) { /* * If we have a valid reference object that came from ref_of(), * do the indirect store */ if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) == ACPI_DESC_TYPE_OPERAND) && (current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Arg (%p) is an ObjRef(Node), storing in node %p\n", new_obj_desc, current_obj_desc)); /* * Store this object to the Node (perform the indirect store) * NOTE: No implicit conversion is performed, as per the ACPI * specification rules on storing to Locals/Args. */ status = acpi_ex_store_object_to_node(new_obj_desc, current_obj_desc-> reference. object, walk_state, ACPI_NO_IMPLICIT_CONVERSION); /* Remove local reference if we copied the object above */ if (new_obj_desc != obj_desc) { acpi_ut_remove_reference(new_obj_desc); } return_ACPI_STATUS(status); } } /* * Delete the existing object * before storing the new one */ acpi_ds_method_data_delete_value(opcode, index, walk_state); } /* * Install the Obj descriptor (*new_obj_desc) into * the descriptor for the Arg or Local. * (increments the object reference count by one) */ status = acpi_ds_method_data_set_value(opcode, index, new_obj_desc, walk_state); /* Remove local reference if we copied the object above */ if (new_obj_desc != obj_desc) { acpi_ut_remove_reference(new_obj_desc); } return_ACPI_STATUS(status); }
acpi_status acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) { struct acpi_evaluate_info *info; union acpi_operand_object *args[3]; union acpi_operand_object *region_obj2; acpi_status status; ACPI_FUNCTION_TRACE(ev_execute_reg_method); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } if (region_obj2->extra.method_REG == NULL) { return_ACPI_STATUS(AE_OK); } /* Allocate and initialize the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } info->prefix_node = region_obj2->extra.method_REG; info->relative_pathname = NULL; info->parameters = args; info->flags = ACPI_IGNORE_RETURN_VALUE; /* * The _REG method has two arguments: * * arg0 - Integer: * Operation region space ID Same value as region_obj->Region.space_id * * arg1 - Integer: * connection status 1 for connecting the handler, 0 for disconnecting * the handler (Passed as a parameter) */ args[0] = acpi_ut_create_integer_object((u64)region_obj->region.space_id); if (!args[0]) { status = AE_NO_MEMORY; goto cleanup1; } args[1] = acpi_ut_create_integer_object((u64)function); if (!args[1]) { status = AE_NO_MEMORY; goto cleanup2; } args[2] = NULL; /* Terminate list */ /* Execute the method, no return value */ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, info->prefix_node, NULL)); status = acpi_ns_evaluate(info); acpi_ut_remove_reference(args[1]); cleanup2: acpi_ut_remove_reference(args[0]); cleanup1: ACPI_FREE(info); return_ACPI_STATUS(status); }
acpi_status acpi_ds_call_control_method(struct acpi_thread_state *thread, struct acpi_walk_state *this_walk_state, union acpi_parse_object *op) { acpi_status status; struct acpi_namespace_node *method_node; struct acpi_walk_state *next_walk_state = NULL; union acpi_operand_object *obj_desc; struct acpi_parameter_info info; u32 i; ACPI_FUNCTION_TRACE_PTR("ds_call_control_method", this_walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", this_walk_state->prev_op, this_walk_state)); /* * Get the namespace entry for the control method we are about to call */ method_node = this_walk_state->method_call_node; if (!method_node) { return_ACPI_STATUS(AE_NULL_ENTRY); } obj_desc = acpi_ns_get_attached_object(method_node); if (!obj_desc) { return_ACPI_STATUS(AE_NULL_OBJECT); } /* Init for new method, wait on concurrency semaphore */ status = acpi_ds_begin_method_execution(method_node, obj_desc, this_walk_state->method_node); if (ACPI_FAILURE(status)) { goto cleanup; } if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { /* 1) Parse: Create a new walk state for the preempting walk */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, op, obj_desc, NULL); if (!next_walk_state) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Create and init a Root Node */ op = acpi_ps_create_scope_op(); if (!op) { status = AE_NO_MEMORY; goto cleanup; } status = acpi_ds_init_aml_walk(next_walk_state, op, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, NULL, 1); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(next_walk_state); goto cleanup; } /* Begin AML parse */ status = acpi_ps_parse_aml(next_walk_state); acpi_ps_delete_parse_tree(op); } /* 2) Execute: Create a new state for the preempting walk */ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc, thread); if (!next_walk_state) { status = AE_NO_MEMORY; goto cleanup; } /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always * start at index 0. Also, null terminate the list of arguments */ this_walk_state->operands[this_walk_state->num_operands] = NULL; info.parameters = &this_walk_state->operands[0]; info.parameter_type = ACPI_PARAM_ARGS; status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node, obj_desc->method.aml_start, obj_desc->method.aml_length, &info, 3); if (ACPI_FAILURE(status)) { goto cleanup; } /* * Delete the operands on the previous walkstate operand stack * (they were copied to new objects) */ for (i = 0; i < obj_desc->method.param_count; i++) { acpi_ut_remove_reference(this_walk_state->operands[i]); this_walk_state->operands[i] = NULL; } /* Clear the operand stack */ this_walk_state->num_operands = 0; ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Starting nested execution, newstate=%p\n", next_walk_state)); if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { status = obj_desc->method.implementation(next_walk_state); } return_ACPI_STATUS(status); cleanup: /* Decrement the thread count on the method parse tree */ if (next_walk_state && (next_walk_state->method_desc)) { next_walk_state->method_desc->method.thread_count--; } /* On error, we must delete the new walk state */ acpi_ds_terminate_control_method(next_walk_state); acpi_ds_delete_walk_state(next_walk_state); return_ACPI_STATUS(status); }
acpi_status acpi_ut_copy_esimple_to_isimple ( union acpi_object *external_object, union acpi_operand_object **ret_internal_object) { union acpi_operand_object *internal_object; ACPI_FUNCTION_TRACE ("ut_copy_esimple_to_isimple"); /* * Simple types supported are: String, Buffer, Integer */ switch (external_object->type) { case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: case ACPI_TYPE_INTEGER: internal_object = acpi_ut_create_internal_object ((u8) external_object->type); if (!internal_object) { return_ACPI_STATUS (AE_NO_MEMORY); } break; default: /* All other types are not supported */ return_ACPI_STATUS (AE_SUPPORT); } /* Must COPY string and buffer contents */ switch (external_object->type) { case ACPI_TYPE_STRING: internal_object->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) external_object->string.length + 1); if (!internal_object->string.pointer) { goto error_exit; } ACPI_MEMCPY (internal_object->string.pointer, external_object->string.pointer, external_object->string.length); internal_object->string.length = external_object->string.length; break; case ACPI_TYPE_BUFFER: internal_object->buffer.pointer = ACPI_MEM_CALLOCATE (external_object->buffer.length); if (!internal_object->buffer.pointer) { goto error_exit; } ACPI_MEMCPY (internal_object->buffer.pointer, external_object->buffer.pointer, external_object->buffer.length); internal_object->buffer.length = external_object->buffer.length; break; case ACPI_TYPE_INTEGER: internal_object->integer.value = external_object->integer.value; break; default: /* Other types can't get here */ break; } *ret_internal_object = internal_object; return_ACPI_STATUS (AE_OK); error_exit: acpi_ut_remove_reference (internal_object); return_ACPI_STATUS (AE_NO_MEMORY); }
acpi_status acpi_ut_copy_ielement_to_ielement ( u8 object_type, union acpi_operand_object *source_object, union acpi_generic_state *state, void *context) { acpi_status status = AE_OK; u32 this_index; union acpi_operand_object **this_target_ptr; union acpi_operand_object *target_object; ACPI_FUNCTION_ENTRY (); this_index = state->pkg.index; this_target_ptr = (union acpi_operand_object **) &state->pkg.dest_object->package.elements[this_index]; switch (object_type) { case ACPI_COPY_TYPE_SIMPLE: /* A null source object indicates a (legal) null package element */ if (source_object) { /* * This is a simple object, just copy it */ target_object = acpi_ut_create_internal_object ( ACPI_GET_OBJECT_TYPE (source_object)); if (!target_object) { return (AE_NO_MEMORY); } status = acpi_ut_copy_simple_object (source_object, target_object); if (ACPI_FAILURE (status)) { goto error_exit; } *this_target_ptr = target_object; } else { /* Pass through a null element */ *this_target_ptr = NULL; } break; case ACPI_COPY_TYPE_PACKAGE: /* * This object is a package - go down another nesting level * Create and build the package object */ target_object = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); if (!target_object) { return (AE_NO_MEMORY); } target_object->package.count = source_object->package.count; target_object->common.flags = source_object->common.flags; /* * Create the object array */ target_object->package.elements = ACPI_MEM_CALLOCATE (((acpi_size) source_object->package.count + 1) * sizeof (void *)); if (!target_object->package.elements) { status = AE_NO_MEMORY; goto error_exit; } /* * Pass the new package object back to the package walk routine */ state->pkg.this_target_obj = target_object; /* * Store the object pointer in the parent package object */ *this_target_ptr = target_object; break; default: return (AE_BAD_PARAMETER); } return (status); error_exit: acpi_ut_remove_reference (target_object); return (status); }
acpi_status acpi_ex_do_concatenate ( union acpi_operand_object *operand0, union acpi_operand_object *operand1, union acpi_operand_object **actual_return_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *local_operand1 = operand1; union acpi_operand_object *return_desc; char *new_buf; acpi_status status; acpi_size new_length; ACPI_FUNCTION_TRACE ("ex_do_concatenate"); /* * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); break; case ACPI_TYPE_STRING: status = acpi_ex_convert_to_string (operand1, &local_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer (operand1, &local_operand1); break; default: ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n", ACPI_GET_OBJECT_TYPE (operand0))); status = AE_AML_INTERNAL; } if (ACPI_FAILURE (status)) { goto cleanup; } /* * Both operands are now known to be the same object type * (Both are Integer, String, or Buffer), and we can now perform the * concatenation. */ /* * There are three cases to handle: * * 1) Two Integers concatenated to produce a new Buffer * 2) Two Strings concatenated to produce a new String * 3) Two Buffers concatenated to produce a new Buffer */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ return_desc = acpi_ut_create_buffer_object ( ACPI_MUL_2 (acpi_gbl_integer_byte_width)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = (char *) return_desc->buffer.pointer; /* Copy the first integer, LSB first */ ACPI_MEMCPY (new_buf, &operand0->integer.value, acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ ACPI_MEMCPY (new_buf + acpi_gbl_integer_byte_width, &local_operand1->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ new_length = (acpi_size) operand0->string.length + (acpi_size) local_operand1->string.length; if (new_length > ACPI_MAX_STRING_CONVERSION) { status = AE_AML_STRING_LIMIT; goto cleanup; } return_desc = acpi_ut_create_string_object (new_length); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = return_desc->string.pointer; /* Concatenate the strings */ ACPI_STRCPY (new_buf, operand0->string.pointer); ACPI_STRCPY (new_buf + operand0->string.length, local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ return_desc = acpi_ut_create_buffer_object ( (acpi_size) operand0->buffer.length + (acpi_size) local_operand1->buffer.length); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = (char *) return_desc->buffer.pointer; /* Concatenate the buffers */ ACPI_MEMCPY (new_buf, operand0->buffer.pointer, operand0->buffer.length); ACPI_MEMCPY (new_buf + operand0->buffer.length, local_operand1->buffer.pointer, local_operand1->buffer.length); break; default: /* Invalid object type, should not happen here */ ACPI_REPORT_ERROR (("Concatenate - Invalid object type: %X\n", ACPI_GET_OBJECT_TYPE (operand0))); status =AE_AML_INTERNAL; goto cleanup; } *actual_return_desc = return_desc; cleanup: if (local_operand1 != operand1) { acpi_ut_remove_reference (local_operand1); } return_ACPI_STATUS (AE_OK); }
acpi_status acpi_ex_do_logical_op ( u16 opcode, union acpi_operand_object *operand0, union acpi_operand_object *operand1, u8 *logical_result) { union acpi_operand_object *local_operand1 = operand1; acpi_integer integer0; acpi_integer integer1; u32 length0; u32 length1; acpi_status status = AE_OK; u8 local_result = FALSE; int compare; ACPI_FUNCTION_TRACE ("ex_do_logical_op"); /* * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI 3.0+ specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); break; case ACPI_TYPE_STRING: status = acpi_ex_convert_to_string (operand1, &local_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer (operand1, &local_operand1); break; default: status = AE_AML_INTERNAL; break; } if (ACPI_FAILURE (status)) { goto cleanup; } /* * Two cases: 1) Both Integers, 2) Both Strings or Buffers */ if (ACPI_GET_OBJECT_TYPE (operand0) == ACPI_TYPE_INTEGER) { /* * 1) Both operands are of type integer * Note: local_operand1 may have changed above */ integer0 = operand0->integer.value; integer1 = local_operand1->integer.value; switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ if (integer0 == integer1) { local_result = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (integer0 > integer1) { local_result = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (integer0 < integer1) { local_result = TRUE; } break; default: status = AE_AML_INTERNAL; break; } } else { /* * 2) Both operands are Strings or both are Buffers * Note: Code below takes advantage of common Buffer/String * object fields. local_operand1 may have changed above. Use * memcmp to handle nulls in buffers. */ length0 = operand0->buffer.length; length1 = local_operand1->buffer.length; /* Lexicographic compare: compare the data bytes */ compare = ACPI_MEMCMP ((const char * ) operand0->buffer.pointer, (const char * ) local_operand1->buffer.pointer, (length0 > length1) ? length1 : length0); switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ /* Length and all bytes must be equal */ if ((length0 == length1) && (compare == 0)) { /* Length and all bytes match ==> TRUE */ local_result = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (compare > 0) { local_result = TRUE; goto cleanup; /* TRUE */ } if (compare < 0) { goto cleanup; /* FALSE */ } /* Bytes match (to shortest length), compare lengths */ if (length0 > length1) { local_result = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (compare > 0) { goto cleanup; /* FALSE */ } if (compare < 0) { local_result = TRUE; goto cleanup; /* TRUE */ } /* Bytes match (to shortest length), compare lengths */ if (length0 < length1) { local_result = TRUE; } break; default: status = AE_AML_INTERNAL; break; } } cleanup: /* New object was created if implicit conversion performed - delete */ if (local_operand1 != operand1) { acpi_ut_remove_reference (local_operand1); } /* Return the logical result and status */ *logical_result = local_result; return_ACPI_STATUS (status); }
acpi_status acpi_ev_install_space_handler(struct acpi_namespace_node * node, acpi_adr_space_type space_id, acpi_adr_space_handler handler, acpi_adr_space_setup setup, void *context) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; acpi_status status; acpi_object_type type; u8 flags = 0; ACPI_FUNCTION_TRACE(ev_install_space_handler); /* * This registration is valid for only the types below * and the root. This is where the default handlers * get placed. */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && (node->type != ACPI_TYPE_THERMAL) && (node != acpi_gbl_root_node)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (handler == ACPI_DEFAULT_HANDLER) { flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; switch (space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: handler = acpi_ex_system_memory_space_handler; setup = acpi_ev_system_memory_region_setup; break; case ACPI_ADR_SPACE_SYSTEM_IO: handler = acpi_ex_system_io_space_handler; setup = acpi_ev_io_space_region_setup; break; case ACPI_ADR_SPACE_PCI_CONFIG: handler = acpi_ex_pci_config_space_handler; setup = acpi_ev_pci_config_region_setup; break; case ACPI_ADR_SPACE_CMOS: handler = acpi_ex_cmos_space_handler; setup = acpi_ev_cmos_region_setup; break; case ACPI_ADR_SPACE_PCI_BAR_TARGET: handler = acpi_ex_pci_bar_space_handler; setup = acpi_ev_pci_bar_region_setup; break; case ACPI_ADR_SPACE_DATA_TABLE: handler = acpi_ex_data_table_space_handler; setup = NULL; break; default: status = AE_BAD_PARAMETER; goto unlock_and_exit; } } /* If the caller hasn't specified a setup routine, use the default */ if (!setup) { setup = acpi_ev_default_region_setup; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* * The attached device object already exists. * Make sure the handler is not already installed. */ handler_obj = obj_desc->device.handler; /* Walk the handler list for this device */ while (handler_obj) { /* Same space_id indicates a handler already installed */ if (handler_obj->address_space.space_id == space_id) { if (handler_obj->address_space.handler == handler) { /* * It is (relatively) OK to attempt to install the SAME * handler twice. This can easily happen * with PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; } else { /* A handler is already installed */ status = AE_ALREADY_EXISTS; } goto unlock_and_exit; } /* Walk the linked list of handlers */ handler_obj = handler_obj->address_space.next; } } else { ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Creating object on Device %p while installing handler\n", node)); /* obj_desc does not exist, create one */ if (node->type == ACPI_TYPE_ANY) { type = ACPI_TYPE_DEVICE; } else { type = node->type; } obj_desc = acpi_ut_create_internal_object(type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Init new descriptor */ obj_desc->common.type = (u8) type; /* Attach the new object to the Node */ status = acpi_ns_attach_object(node, obj_desc, type); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", acpi_ut_get_region_name(space_id), space_id, acpi_ut_get_node_name(node), node, obj_desc)); /* * Install the handler * * At this point there is no existing handler. * Just allocate the object for the handler and link it * into the list. */ handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER); if (!handler_obj) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Init handler obj */ handler_obj->address_space.space_id = (u8) space_id; handler_obj->address_space.handler_flags = flags; handler_obj->address_space.region_list = NULL; handler_obj->address_space.node = node; handler_obj->address_space.handler = handler; handler_obj->address_space.context = context; handler_obj->address_space.setup = setup; /* Install at head of Device.address_space list */ handler_obj->address_space.next = obj_desc->device.handler; /* * The Device object is the first reference on the handler_obj. * Each region that uses the handler adds a reference. */ obj_desc->device.handler = handler_obj; /* * Walk the namespace finding all of the regions this * handler will manage. * * Start at the device and search the branch toward * the leaf nodes until either the leaf is encountered or * a device is detected that has an address handler of the * same type. * * In either case, back up and search down the remainder * of the branch */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler, handler_obj, NULL); unlock_and_exit: return_ACPI_STATUS(status); }
acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; char *buffer = NULL; acpi_status status = AE_OK; u64 index; acpi_size length; ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ return_desc = acpi_ut_create_internal_object((operand[0])-> common.type); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } /* Get the Integer values from the objects */ index = operand[1]->integer.value; length = (acpi_size) operand[2]->integer.value; /* * If the index is beyond the length of the String/Buffer, or if the * requested length is zero, return a zero-length String/Buffer */ if (index >= operand[0]->string.length) { length = 0; } /* Truncate request if larger than the actual String/Buffer */ else if ((index + length) > operand[0]->string.length) { length = (acpi_size) operand[0]->string.length - (acpi_size) index; } /* Strings always have a sub-pointer, not so for buffers */ switch ((operand[0])->common.type) { case ACPI_TYPE_STRING: /* Always allocate a new buffer for the String */ buffer = ACPI_ALLOCATE_ZEROED((acpi_size) length + 1); if (!buffer) { status = AE_NO_MEMORY; goto cleanup; } break; case ACPI_TYPE_BUFFER: /* If the requested length is zero, don't allocate a buffer */ if (length > 0) { /* Allocate a new buffer for the Buffer */ buffer = ACPI_ALLOCATE_ZEROED(length); if (!buffer) { status = AE_NO_MEMORY; goto cleanup; } } break; default: /* Should not happen */ status = AE_AML_OPERAND_TYPE; goto cleanup; } if (buffer) { /* We have a buffer, copy the portion requested */ ACPI_MEMCPY(buffer, operand[0]->string.pointer + index, length); } /* Set the length of the new String/Buffer */ return_desc->string.pointer = buffer; return_desc->string.length = (u32) length; /* Mark buffer initialized */ return_desc->buffer.flags |= AOPOBJ_DATA_VALID; break; default: ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } /* Store the result in the target */ status = acpi_ex_store(return_desc, operand[3], walk_state); cleanup: /* Delete return object on error */ if (ACPI_FAILURE(status) || walk_state->result_obj) { acpi_ut_remove_reference(return_desc); walk_state->result_obj = NULL; } /* Set the return object and exit */ else { walk_state->result_obj = return_desc; } return_ACPI_STATUS(status); }
static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) { void *obj_pointer = NULL; union acpi_operand_object *handler_desc; union acpi_operand_object *second_desc; union acpi_operand_object *next_desc; ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); if (!object) { return_VOID; } /* * Must delete or free any pointers within the object that are not * actual ACPI objects (for example, a raw buffer pointer). */ switch (ACPI_GET_OBJECT_TYPE(object)) { case ACPI_TYPE_STRING: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n", object, object->string.pointer)); /* Free the actual string buffer */ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { /* But only if it is NOT a pointer into an ACPI table */ obj_pointer = object->string.pointer; } break; case ACPI_TYPE_BUFFER: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n", object, object->buffer.pointer)); /* Free the actual buffer */ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) { /* But only if it is NOT a pointer into an ACPI table */ obj_pointer = object->buffer.pointer; } break; case ACPI_TYPE_PACKAGE: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n", object->package.count)); /* * Elements of the package are not handled here, they are deleted * separately */ /* Free the (variable length) element pointer array */ obj_pointer = object->package.elements; break; case ACPI_TYPE_DEVICE: if (object->device.gpe_block) { (void)acpi_ev_delete_gpe_block(object->device. gpe_block); } /* Walk the handler list for this device */ handler_desc = object->device.handler; while (handler_desc) { next_desc = handler_desc->address_space.next; acpi_ut_remove_reference(handler_desc); handler_desc = next_desc; } break; case ACPI_TYPE_MUTEX: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Mutex %p, OS Mutex %p\n", object, object->mutex.os_mutex)); if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) { /* Global Lock has extra semaphore */ (void) acpi_os_delete_semaphore (acpi_gbl_global_lock_semaphore); acpi_gbl_global_lock_semaphore = NULL; acpi_os_delete_mutex(object->mutex.os_mutex); acpi_gbl_global_lock_mutex = NULL; } else { acpi_ex_unlink_mutex(object); acpi_os_delete_mutex(object->mutex.os_mutex); } break; case ACPI_TYPE_EVENT: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Event %p, OS Semaphore %p\n", object, object->event.os_semaphore)); (void)acpi_os_delete_semaphore(object->event.os_semaphore); object->event.os_semaphore = NULL; break; case ACPI_TYPE_METHOD: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object)); /* Delete the method mutex if it exists */ if (object->method.mutex) { acpi_os_delete_mutex(object->method.mutex->mutex. os_mutex); acpi_ut_delete_object_desc(object->method.mutex); object->method.mutex = NULL; } break; case ACPI_TYPE_REGION: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); second_desc = acpi_ns_get_secondary_object(object); if (second_desc) { /* * Free the region_context if and only if the handler is one of the * default handlers -- and therefore, we created the context object * locally, it was not created by an external caller. */ handler_desc = object->region.handler; if (handler_desc) { if (handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { /* Deactivate region and free region context */ if (handler_desc->address_space.setup) { (void)handler_desc-> address_space.setup(object, ACPI_REGION_DEACTIVATE, handler_desc-> address_space. context, &second_desc-> extra. region_context); } } acpi_ut_remove_reference(handler_desc); } /* Now we can free the Extra object */ acpi_ut_delete_object_desc(second_desc); } break; case ACPI_TYPE_BUFFER_FIELD: ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object)); second_desc = acpi_ns_get_secondary_object(object); if (second_desc) { acpi_ut_delete_object_desc(second_desc); } break; default: break; } /* Free any allocated memory (pointer within the object) found above */ if (obj_pointer) { ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n", obj_pointer)); ACPI_FREE(obj_pointer); } /* Now the object can be safely deleted */ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n", object, acpi_ut_get_object_type_name(object))); acpi_ut_delete_object_desc(object); return_VOID; }
/******************************************************************************* * * FUNCTION: acpi_remove_notify_handler * * PARAMETERS: Device - The device for which notifies will be handled * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for notifies on an ACPI device * ******************************************************************************/ acpi_status acpi_remove_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler) { union acpi_operand_object *notify_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { status = AE_BAD_PARAMETER; goto exit; } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Convert and validate the device handle */ node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Root Object */ if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Removing notify handler for namespace root object\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } /* All Other Objects */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Remove the handler */ obj_desc->common_notify.system_notify = NULL; acpi_ut_remove_reference(notify_obj); } if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; acpi_ut_remove_reference(notify_obj); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler")); return_ACPI_STATUS(status); }
static acpi_status acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, union acpi_operand_object *index_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; union acpi_operand_object *obj_desc; union acpi_operand_object *new_desc; u8 value = 0; u32 i; ACPI_FUNCTION_TRACE(ex_store_object_to_index); /* * Destination must be a reference pointer, and * must point to either a buffer or a package */ switch (index_desc->reference.target_type) { case ACPI_TYPE_PACKAGE: /* * Storing to a package element. Copy the object and replace * any existing object with the new object. No implicit * conversion is performed. * * The object at *(index_desc->Reference.Where) is the * element within the package that is to be modified. * The parent package object is at index_desc->Reference.Object */ obj_desc = *(index_desc->reference.where); status = acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (obj_desc) { /* Decrement reference count by the ref count of the parent package */ for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common. reference_count; i++) { acpi_ut_remove_reference(obj_desc); } } *(index_desc->reference.where) = new_desc; /* Increment ref count by the ref count of the parent package-1 */ for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common. reference_count; i++) { acpi_ut_add_reference(new_desc); } break; case ACPI_TYPE_BUFFER_FIELD: /* * Store into a Buffer or String (not actually a real buffer_field) * at a location defined by an Index. * * The first 8-bit element of the source object is written to the * 8-bit Buffer location defined by the Index destination object, * according to the ACPI 2.0 specification. */ /* * Make sure the target is a Buffer or String. An error should * not happen here, since the reference_object was constructed * by the INDEX_OP code. */ obj_desc = index_desc->reference.object; if ((ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_BUFFER) && (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_STRING)) { return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* * The assignment of the individual elements will be slightly * different for each source type. */ switch (ACPI_GET_OBJECT_TYPE(source_desc)) { case ACPI_TYPE_INTEGER: /* Use the least-significant byte of the integer */ value = (u8) (source_desc->integer.value); break; case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: /* Note: Takes advantage of common string/buffer fields */ value = source_desc->buffer.pointer[0]; break; default: /* All other types are invalid */ ACPI_ERROR((AE_INFO, "Source must be Integer/Buffer/String type, not %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* Store the source value into the target buffer byte */ obj_desc->buffer.pointer[index_desc->reference.offset] = value; break; default: ACPI_ERROR((AE_INFO, "Target is not a Package or BufferField")); status = AE_AML_OPERAND_TYPE; break; } return_ACPI_STATUS(status); }
void acpi_ev_detach_region(union acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; union acpi_operand_object *start_desc; union acpi_operand_object **last_obj_ptr; acpi_adr_space_setup region_setup; void **region_context; union acpi_operand_object *region_obj2; acpi_status status; ACPI_FUNCTION_TRACE(ev_detach_region); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_VOID; } region_context = ®ion_obj2->extra.region_context; /* Get the address handler from the region object */ handler_obj = region_obj->region.handler; if (!handler_obj) { /* This region has no handler, all done */ return_VOID; } /* Find this region in the handler's list */ obj_desc = handler_obj->address_space.region_list; start_desc = obj_desc; last_obj_ptr = &handler_obj->address_space.region_list; while (obj_desc) { /* Is this the correct Region? */ if (obj_desc == region_obj) { ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Removing Region %p from address handler %p\n", region_obj, handler_obj)); /* This is it, remove it from the handler's list */ *last_obj_ptr = obj_desc->region.next; obj_desc->region.next = NULL; /* Must clear field */ if (acpi_ns_is_locked) { status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_VOID; } } /* Now stop region accesses by executing the _REG method */ status = acpi_ev_execute_reg_method(region_obj, ACPI_REG_DISCONNECT); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "from region _REG, [%s]", acpi_ut_get_region_name (region_obj->region.space_id))); } if (acpi_ns_is_locked) { status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_VOID; } } /* * If the region has been activated, call the setup handler with * the deactivate notification */ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { region_setup = handler_obj->address_space.setup; status = region_setup(region_obj, ACPI_REGION_DEACTIVATE, handler_obj->address_space. context, region_context); /* * region_context should have been released by the deactivate * operation. We don't need access to it anymore here. */ if (region_context) { *region_context = NULL; } /* Init routine may fail, Just ignore errors */ if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "from region handler - deactivate, [%s]", acpi_ut_get_region_name (region_obj->region. space_id))); } region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); } /* * Remove handler reference in the region * * NOTE: this doesn't mean that the region goes away, the region * is just inaccessible as indicated to the _REG method * * If the region is on the handler's list, this must be the * region's handler */ region_obj->region.handler = NULL; acpi_ut_remove_reference(handler_obj); return_VOID; } /* Walk the linked list of handlers */ last_obj_ptr = &obj_desc->region.next; obj_desc = obj_desc->region.next; /* Prevent infinite loop if list is corrupted */ if (obj_desc == start_desc) { ACPI_ERROR((AE_INFO, "Circular handler list in region object %p", region_obj)); return_VOID; } } /* If we get here, the region was not in the handler's region list */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Cannot remove region %p from address handler %p\n", region_obj, handler_obj)); return_VOID; }
static acpi_status acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, u32 level, void *info, void **return_value) { struct acpi_gpe_walk_info *gpe_info = (void *)info; struct acpi_namespace_node *gpe_device; struct acpi_gpe_block_info *gpe_block; struct acpi_namespace_node *target_gpe_device; struct acpi_gpe_event_info *gpe_event_info; union acpi_operand_object *pkg_desc; union acpi_operand_object *obj_desc; u32 gpe_number; acpi_status status; ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe); /* Check for a _PRW method under this device */ status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW, ACPI_BTYPE_PACKAGE, &pkg_desc); if (ACPI_FAILURE(status)) { /* Ignore all errors from _PRW, we don't want to abort the subsystem */ return_ACPI_STATUS(AE_OK); } /* The returned _PRW package must have at least two elements */ if (pkg_desc->package.count < 2) { goto cleanup; } /* Extract pointers from the input context */ gpe_device = gpe_info->gpe_device; gpe_block = gpe_info->gpe_block; /* * The _PRW object must return a package, we are only interested * in the first element */ obj_desc = pkg_desc->package.elements[0]; if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { /* Use FADT-defined GPE device (from definition of _PRW) */ target_gpe_device = acpi_gbl_fadt_gpe_device; /* Integer is the GPE number in the FADT described GPE blocks */ gpe_number = (u32) obj_desc->integer.value; } else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { /* Package contains a GPE reference and GPE number within a GPE block */ if ((obj_desc->package.count < 2) || (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) || (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) { goto cleanup; } /* Get GPE block reference and decode */ target_gpe_device = obj_desc->package.elements[0]->reference.node; gpe_number = (u32) obj_desc->package.elements[1]->integer.value; } else { /* Unknown type, just ignore it */ goto cleanup; } /* * Is this GPE within this block? * * TRUE iff these conditions are true: * 1) The GPE devices match. * 2) The GPE index(number) is within the range of the Gpe Block * associated with the GPE device. */ if ((gpe_device == target_gpe_device) && (gpe_number >= gpe_block->block_base_number) && (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ gpe_event_info->flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); status = acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); if (ACPI_FAILURE(status)) { goto cleanup; } status = acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE); } cleanup: acpi_ut_remove_reference(pkg_desc); return_ACPI_STATUS(AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_evaluate_object * * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ acpi_status acpi_evaluate_object(acpi_handle handle, acpi_string pathname, struct acpi_object_list *external_params, struct acpi_buffer *return_buffer) { acpi_status status; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; ACPI_FUNCTION_TRACE(acpi_evaluate_object); /* Allocate and initialize the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Convert and validate the device handle */ info->prefix_node = acpi_ns_validate_handle(handle); if (!info->prefix_node) { status = AE_BAD_PARAMETER; goto cleanup; } /* * Get the actual namespace node for the target object. * Handles these cases: * * 1) Null node, valid pathname from root (absolute path) * 2) Node and valid pathname (path relative to Node) * 3) Node, Null pathname */ if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) { /* The path is fully qualified, just evaluate by name */ info->prefix_node = NULL; } else if (!handle) { /* * A handle is optional iff a fully qualified pathname is specified. * Since we've already handled fully qualified names above, this is * an error. */ if (!pathname) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Both Handle and Pathname are NULL")); } else { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null Handle with relative pathname [%s]", pathname)); } status = AE_BAD_PARAMETER; goto cleanup; } info->relative_pathname = pathname; /* * Convert all external objects passed as arguments to the * internal version(s). */ if (external_params && external_params->count) { info->param_count = (u16)external_params->count; /* Warn on impossible argument count */ if (info->param_count > ACPI_METHOD_NUM_ARGS) { ACPI_WARN_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS, "Excess arguments (%u) - using only %u", info->param_count, ACPI_METHOD_NUM_ARGS)); info->param_count = ACPI_METHOD_NUM_ARGS; } /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)info-> param_count + 1) * sizeof(void *)); if (!info->parameters) { status = AE_NO_MEMORY; goto cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < info->param_count; i++) { status = acpi_ut_copy_eobject_to_iobject(&external_params-> pointer[i], &info-> parameters[i]); if (ACPI_FAILURE(status)) { goto cleanup; } } info->parameters[info->param_count] = NULL; } #ifdef _FUTURE_FEATURE /* * Begin incoming argument count analysis. Check for too few args * and too many args. */ switch (acpi_ns_get_type(info->node)) { case ACPI_TYPE_METHOD: /* Check incoming argument count against the method definition */ if (info->obj_desc->method.param_count > info->param_count) { ACPI_ERROR((AE_INFO, "Insufficient arguments (%u) - %u are required", info->param_count, info->obj_desc->method.param_count)); status = AE_MISSING_ARGUMENTS; goto cleanup; } else if (info->obj_desc->method.param_count < info->param_count) { ACPI_WARNING((AE_INFO, "Excess arguments (%u) - only %u are required", info->param_count, info->obj_desc->method.param_count)); /* Just pass the required number of arguments */ info->param_count = info->obj_desc->method.param_count; } /* * Any incoming external objects to be passed as arguments to the * method must be converted to internal objects */ if (info->param_count) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) info-> param_count + 1) * sizeof(void *)); if (!info->parameters) { status = AE_NO_MEMORY; goto cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < info->param_count; i++) { status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], &info->parameters[i]); if (ACPI_FAILURE(status)) { goto cleanup; } } info->parameters[info->param_count] = NULL; } break; default: /* Warn if arguments passed to an object that is not a method */ if (info->param_count) { ACPI_WARNING((AE_INFO, "%u arguments were passed to a non-method ACPI object", info->param_count)); } break; } #endif /* Now we can evaluate the object */ status = acpi_ns_evaluate(info); /* * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ if (!return_buffer) { goto cleanup_return_object; } if (!info->return_object) { return_buffer->length = 0; goto cleanup; } if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to * return (such as a mutex, etc.) We return an error because * these types are essentially unsupported by this interface. * We don't check up front because this makes it easier to add * support for various types at a later date if necessary. */ status = AE_TYPE; info->return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } if (ACPI_FAILURE(status)) { goto cleanup_return_object; } /* Dereference Index and ref_of references */ acpi_ns_resolve_references(info); /* Get the size of the returned object */ status = acpi_ut_get_object_size(info->return_object, &buffer_space_needed); if (ACPI_SUCCESS(status)) { /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer(return_buffer, buffer_space_needed); if (ACPI_FAILURE(status)) { /* * Caller's buffer is too small or a new one can't * be allocated */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Needed buffer size %X, %s\n", (u32)buffer_space_needed, acpi_format_exception(status))); } else { /* We have enough space for the object, build it */ status = acpi_ut_copy_iobject_to_eobject(info->return_object, return_buffer); } } cleanup_return_object: if (info->return_object) { /* * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ acpi_ex_enter_interpreter(); /* Remove one reference on the return object (should delete it) */ acpi_ut_remove_reference(info->return_object); acpi_ex_exit_interpreter(); } cleanup: /* Free the input parameter list (if we created one) */ if (info->parameters) { /* Free the allocated parameter block */ acpi_ut_delete_internal_object_list(info->parameters); } ACPI_FREE(info); return_ACPI_STATUS(status); }
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; union acpi_operand_object *second_desc = NULL; acpi_status status; u32 access_byte_width; u32 type; ACPI_FUNCTION_TRACE(ex_prep_field_value); /* */ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } type = acpi_ns_get_type(info->region_node); if (type != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)", type, acpi_ut_get_type_name(type))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } } /* */ obj_desc = acpi_ut_create_internal_object(info->field_type); if (!obj_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* */ obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags, info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } /* */ switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); /* */ obj_desc->field.access_length = info->access_length; if (info->connection_node) { second_desc = info->connection_node->object; if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_arguments(second_desc); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } } obj_desc->field.resource_buffer = second_desc->buffer.pointer; obj_desc->field.resource_length = (u16)second_desc->buffer.length; } else if (info->resource_buffer) { obj_desc->field.resource_buffer = info->resource_buffer; obj_desc->field.resource_length = info->resource_length; } /* */ if ((obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_EC) && (obj_desc->common_field.bit_length > 8)) { access_byte_width = ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field. bit_length); /* */ if (access_byte_width < 256) { obj_desc->common_field.access_byte_width = (u8)access_byte_width; } } /* */ acpi_ut_add_reference(obj_desc->field.region_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; obj_desc->bank_field.region_obj = acpi_ns_get_attached_object(info->region_node); obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object(info->register_node); /* */ acpi_ut_add_reference(obj_desc->bank_field.region_obj); acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); /* */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.data; second_desc->extra.aml_length = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* */ obj_desc->index_field.index_obj = acpi_ns_get_attached_object(info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object(info->data_register_node); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_ERROR((AE_INFO, "Null Index Object during field prep")); acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_AML_INTERNAL); } /* */ acpi_ut_add_reference(obj_desc->index_field.data_obj); acpi_ut_add_reference(obj_desc->index_field.index_obj); /* */ obj_desc->index_field.value = (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), obj_desc->index_field. access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, obj_desc->field.access_byte_width, obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; default: /* */ break; } /* */ status = acpi_ns_attach_object(info->field_node, obj_desc, acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); /* */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_gpe_block * * PARAMETERS: gpe_device - Handle to the parent GPE Block Device * gpe_block_address - Address and space_iD * register_count - Number of GPE register pairs in the block * interrupt_number - H/W interrupt for the block * * RETURN: Status * * DESCRIPTION: Create and Install a block of GPE registers * ******************************************************************************/ acpi_status acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, u32 register_count, u32 interrupt_number) { acpi_status status; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; struct acpi_gpe_block_info *gpe_block; ACPI_FUNCTION_TRACE(acpi_install_gpe_block); if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_validate_handle(gpe_device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* * For user-installed GPE Block Devices, the gpe_block_base_number * is always zero */ status = acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, interrupt_number, &gpe_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Install block in the device_object attached to the node */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* * No object, create a new one (Device nodes do not always have * an attached object) */ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } /* Now install the GPE block in the device_object */ obj_desc->device.gpe_block = gpe_block; /* Enable the runtime GPEs in the new block */ status = acpi_ev_initialize_gpe_block(node, gpe_block); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; union acpi_operand_object *second_desc = NULL; u32 type; acpi_status status; ACPI_FUNCTION_TRACE(ex_prep_field_value); /* Parameter validation */ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } type = acpi_ns_get_type(info->region_node); if (type != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)", type, acpi_ut_get_type_name(type))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } } /* Allocate a new field object */ obj_desc = acpi_ut_create_internal_object(info->field_type); if (!obj_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Initialize areas of the object that are common to all fields */ obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags, info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } /* Initialize areas of the object that are specific to the field type */ switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); /* An additional reference for the container */ acpi_ut_add_reference(obj_desc->field.region_obj); /* allow full data read from EC address space */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_EC) { if (obj_desc->common_field.bit_length > 8) { unsigned width = ACPI_ROUND_BITS_UP_TO_BYTES( obj_desc->common_field.bit_length); // access_bit_width is u8, don't overflow it if (width > 8) width = 8; obj_desc->common_field.access_byte_width = width; obj_desc->common_field.access_bit_width = 8 * width; } } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; obj_desc->bank_field.region_obj = acpi_ns_get_attached_object(info->region_node); obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object(info->register_node); /* An additional reference for the attached objects */ acpi_ut_add_reference(obj_desc->bank_field.region_obj); acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); /* * Remember location in AML stream of the field unit * opcode and operands -- since the bank_value * operands must be evaluated. */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.data; second_desc->extra.aml_length = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Get the Index and Data registers */ obj_desc->index_field.index_obj = acpi_ns_get_attached_object(info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object(info->data_register_node); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_ERROR((AE_INFO, "Null Index Object during field prep")); acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_AML_INTERNAL); } /* An additional reference for the attached objects */ acpi_ut_add_reference(obj_desc->index_field.data_obj); acpi_ut_add_reference(obj_desc->index_field.index_obj); /* * April 2006: Changed to match MS behavior * * The value written to the Index register is the byte offset of the * target field in units of the granularity of the index_field * * Previously, the value was calculated as an index in terms of the * width of the Data register, as below: * * obj_desc->index_field.Value = (u32) * (Info->field_bit_position / ACPI_MUL_8 ( * obj_desc->Field.access_byte_width)); * * February 2006: Tried value as a byte offset: * obj_desc->index_field.Value = (u32) * ACPI_DIV_8 (Info->field_bit_position); */ obj_desc->index_field.value = (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), obj_desc->index_field. access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, obj_desc->field.access_byte_width, obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; default: /* No other types should get here */ break; } /* * Store the constructed descriptor (obj_desc) into the parent Node, * preserving the current type of that named_obj. */ status = acpi_ns_attach_object(info->field_node, obj_desc, acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_evaluate_object * * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ acpi_status acpi_evaluate_object(acpi_handle handle, acpi_string pathname, struct acpi_object_list *external_params, struct acpi_buffer *return_buffer) { acpi_status status; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; ACPI_FUNCTION_TRACE(acpi_evaluate_object); /* Allocate and initialize the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } info->pathname = pathname; /* Convert and validate the device handle */ info->prefix_node = acpi_ns_validate_handle(handle); if (!info->prefix_node) { status = AE_BAD_PARAMETER; goto cleanup; } /* * If there are parameters to be passed to a control method, the external * objects must all be converted to internal objects */ if (external_params && external_params->count) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) external_params-> count + 1) * sizeof(void *)); if (!info->parameters) { status = AE_NO_MEMORY; goto cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject(&external_params-> pointer[i], &info-> parameters[i]); if (ACPI_FAILURE(status)) { goto cleanup; } } info->parameters[external_params->count] = NULL; } /* * Three major cases: * 1) Fully qualified pathname * 2) No handle, not fully qualified pathname (error) * 3) Valid handle */ if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) { /* The path is fully qualified, just evaluate by name */ info->prefix_node = NULL; status = acpi_ns_evaluate(info); } else if (!handle) { /* * A handle is optional iff a fully qualified pathname is specified. * Since we've already handled fully qualified names above, this is * an error */ if (!pathname) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Both Handle and Pathname are NULL")); } else { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null Handle with relative pathname [%s]", pathname)); } status = AE_BAD_PARAMETER; } else { /* We have a namespace a node and a possible relative path */ status = acpi_ns_evaluate(info); } /* * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ if (return_buffer) { if (!info->return_object) { return_buffer->length = 0; } else { if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to * return (such as a mutex, etc.) We return an error because * these types are essentially unsupported by this interface. * We don't check up front because this makes it easier to add * support for various types at a later date if necessary. */ status = AE_TYPE; info->return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } if (ACPI_SUCCESS(status)) { /* Dereference Index and ref_of references */ acpi_ns_resolve_references(info); /* Get the size of the returned object */ status = acpi_ut_get_object_size(info->return_object, &buffer_space_needed); if (ACPI_SUCCESS(status)) { /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); if (ACPI_FAILURE(status)) { /* * Caller's buffer is too small or a new one can't * be allocated */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Needed buffer size %X, %s\n", (u32) buffer_space_needed, acpi_format_exception (status))); } else { /* We have enough space for the object, build it */ status = acpi_ut_copy_iobject_to_eobject (info->return_object, return_buffer); } } } } } if (info->return_object) { /* * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ acpi_ex_enter_interpreter(); /* Remove one reference on the return object (should delete it) */ acpi_ut_remove_reference(info->return_object); acpi_ex_exit_interpreter(); } cleanup: /* Free the input parameter list (if we created one) */ if (info->parameters) { /* Free the allocated parameter block */ acpi_ut_delete_internal_object_list(info->parameters); } ACPI_FREE(info); return_ACPI_STATUS(status); }
acpi_status acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, union acpi_operand_object *obj_desc, union acpi_operand_object **ret_buffer_desc) { acpi_status status; union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; u32 function; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); if (!obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (!ret_buffer_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { length = ACPI_GSBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else { length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_READ; } buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(u64, buffer_desc-> buffer.pointer), function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; } else { buffer_desc = acpi_ut_create_integer_object((u64) 0); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; buffer = &buffer_desc->integer.value; } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_read_data_from_field(struct acpi_walk_state * walk_state, union acpi_operand_object *obj_desc, union acpi_operand_object **ret_buffer_desc) { acpi_status status; union acpi_operand_object *buffer_desc; acpi_size length; void *buffer; u32 function; u16 accessor_type; ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); /* Parameter validation */ if (!obj_desc) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } if (!ret_buffer_desc) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { /* * If the buffer_field arguments have not been previously evaluated, * evaluate them now and save the results. */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_field_arguments(obj_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } } else if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold * the data and then directly access the region handler. * * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); } else if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) { accessor_type = obj_desc->field.attribute; length = acpi_ex_get_serial_access_length(accessor_type, obj_desc-> field. access_length); /* * Add additional 2 bytes for the generic_serial_bus data buffer: * * Status; (Byte 0 of the data buffer) * Length; (Byte 1 of the data buffer) * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) */ length += 2; function = ACPI_READ | (accessor_type << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; function = ACPI_READ; } buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Call the region handler for the read */ status = acpi_ex_access_region(obj_desc, 0, ACPI_CAST_PTR(u64, buffer_desc-> buffer.pointer), function); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); goto exit; } /* * Allocate a buffer for the contents of the field. * * If the field is larger than the current integer width, create * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. * * Note: Field.length is in bits. */ length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); if (length > acpi_gbl_integer_byte_width) { /* Field is too large for an Integer, create a Buffer instead */ buffer_desc = acpi_ut_create_buffer_object(length); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } buffer = buffer_desc->buffer.pointer; } else { /* Field will fit within an Integer (normal case) */ buffer_desc = acpi_ut_create_integer_object((u64) 0); if (!buffer_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } length = acpi_gbl_integer_byte_width; buffer = &buffer_desc->integer.value; } if ((obj_desc->common.type == ACPI_TYPE_LOCAL_REGION_FIELD) && (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) { /* * For GPIO (general_purpose_io), the Address will be the bit offset * from the previous Connection() operator, making it effectively a * pin number index. The bit_length is the length of the field, which * is thus the number of pins. */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "GPIO FieldRead [FROM]: Pin %u Bits %u\n", obj_desc->field.pin_number_index, obj_desc->field.bit_length)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Perform the write */ status = acpi_ex_access_region(obj_desc, 0, (u64 *)buffer, ACPI_READ); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", obj_desc, obj_desc->common.type, buffer, (u32) length)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", obj_desc->common_field.bit_length, obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); /* Lock entire transaction if requested */ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags); /* Read from the field */ status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length); acpi_ex_release_global_lock(obj_desc->common_field.field_flags); exit: if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(buffer_desc); } else { *ret_buffer_desc = buffer_desc; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_do_concatenate(union acpi_operand_object *operand0, union acpi_operand_object *operand1, union acpi_operand_object **actual_return_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *local_operand0 = operand0; union acpi_operand_object *local_operand1 = operand1; union acpi_operand_object *temp_operand1 = NULL; union acpi_operand_object *return_desc; char *buffer; acpi_object_type operand0_type; acpi_object_type operand1_type; acpi_status status; ACPI_FUNCTION_TRACE(ex_do_concatenate); /* Operand 0 preprocessing */ switch (operand0->common.type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: operand0_type = operand0->common.type; break; default: /* For all other types, get the "object type" string */ status = acpi_ex_convert_to_object_type_string(operand0, &local_operand0); if (ACPI_FAILURE(status)) { goto cleanup; } operand0_type = ACPI_TYPE_STRING; break; } /* Operand 1 preprocessing */ switch (operand1->common.type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: operand1_type = operand1->common.type; break; default: /* For all other types, get the "object type" string */ status = acpi_ex_convert_to_object_type_string(operand1, &local_operand1); if (ACPI_FAILURE(status)) { goto cleanup; } operand1_type = ACPI_TYPE_STRING; break; } /* * Convert the second operand if necessary. The first operand (0) * determines the type of the second operand (1) (See the Data Types * section of the ACPI specification). Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (operand0_type) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer(local_operand1, &temp_operand1, 16); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer(local_operand1, &temp_operand1); break; case ACPI_TYPE_STRING: switch (operand1_type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Other types have already been converted to string */ status = acpi_ex_convert_to_string(local_operand1, &temp_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; default: status = AE_OK; break; } break; default: ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", operand0->common.type)); status = AE_AML_INTERNAL; } if (ACPI_FAILURE(status)) { goto cleanup; } /* Take care with any newly created operand objects */ if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) { acpi_ut_remove_reference(local_operand1); } local_operand1 = temp_operand1; /* * Both operands are now known to be the same object type * (Both are Integer, String, or Buffer), and we can now perform * the concatenation. * * There are three cases to handle, as per the ACPI spec: * * 1) Two Integers concatenated to produce a new Buffer * 2) Two Strings concatenated to produce a new String * 3) Two Buffers concatenated to produce a new Buffer */ switch (operand0_type) { case ACPI_TYPE_INTEGER: /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ return_desc = acpi_ut_create_buffer_object((acpi_size) ACPI_MUL_2 (acpi_gbl_integer_byte_width)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = (char *)return_desc->buffer.pointer; /* Copy the first integer, LSB first */ memcpy(buffer, &operand0->integer.value, acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ memcpy(buffer + acpi_gbl_integer_byte_width, &local_operand1->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ return_desc = acpi_ut_create_string_object(((acpi_size) local_operand0-> string.length + local_operand1-> string.length)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = return_desc->string.pointer; /* Concatenate the strings */ strcpy(buffer, local_operand0->string.pointer); strcat(buffer, local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ return_desc = acpi_ut_create_buffer_object(((acpi_size) operand0->buffer. length + local_operand1-> buffer.length)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = (char *)return_desc->buffer.pointer; /* Concatenate the buffers */ memcpy(buffer, operand0->buffer.pointer, operand0->buffer.length); memcpy(buffer + operand0->buffer.length, local_operand1->buffer.pointer, local_operand1->buffer.length); break; default: /* Invalid object type, should not happen here */ ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", operand0->common.type)); status = AE_AML_INTERNAL; goto cleanup; } *actual_return_desc = return_desc; cleanup: if (local_operand0 != operand0) { acpi_ut_remove_reference(local_operand0); } if (local_operand1 != operand1) { acpi_ut_remove_reference(local_operand1); } return_ACPI_STATUS(status); }
acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) { union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; acpi_status status = AE_OK; acpi_integer index; union acpi_operand_object *this_element; ACPI_FUNCTION_TRACE_STR(ex_opcode_6A_0T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); switch (walk_state->opcode) { case AML_MATCH_OP: /* * Match (search_pkg[0], match_op1[1], match_obj1[2], * match_op2[3], match_obj2[4], start_index[5]) */ /* Validate both Match Term Operators (MTR, MEQ, etc.) */ if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || (operand[3]->integer.value > MAX_MATCH_OPERATOR)) { ACPI_ERROR((AE_INFO, "Match operator out of range")); status = AE_AML_OPERAND_VALUE; goto cleanup; } /* Get the package start_index, validate against the package length */ index = operand[5]->integer.value; if (index >= operand[0]->package.count) { ACPI_ERROR((AE_INFO, "Index (%X%8.8X) beyond package end (%X)", ACPI_FORMAT_UINT64(index), operand[0]->package.count)); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } /* Create an integer for the return value */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } /* Default return value if no match found */ return_desc->integer.value = ACPI_INTEGER_MAX; /* * Examine each element until a match is found. Both match conditions * must be satisfied for a match to occur. Within the loop, * "continue" signifies that the current element does not match * and the next should be examined. * * Upon finding a match, the loop will terminate via "break" at * the bottom. If it terminates "normally", match_value will be * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no * match was found. */ for (; index < operand[0]->package.count; index++) { /* Get the current package element */ this_element = operand[0]->package.elements[index]; /* Treat any uninitialized (NULL) elements as non-matching */ if (!this_element) { continue; } /* * Both match conditions must be satisfied. Execution of a continue * (proceed to next iteration of enclosing for loop) signifies a * non-match. */ if (!acpi_ex_do_match((u32) operand[1]->integer.value, this_element, operand[2])) { continue; } if (!acpi_ex_do_match((u32) operand[3]->integer.value, this_element, operand[4])) { continue; } /* Match found: Index is the return value */ return_desc->integer.value = index; break; } break; case AML_LOAD_TABLE_OP: status = acpi_ex_load_table_op(walk_state, &return_desc); break; default: ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } walk_state->result_obj = return_desc; cleanup: /* Delete return object on error */ if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); } return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_notify_handler * * PARAMETERS: Device - The device for which notifies will be handled * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status * * DESCRIPTION: Install a handler for notifies on an ACPI device * ******************************************************************************/ acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler, void *context) { union acpi_operand_object *obj_desc; union acpi_operand_object *notify_obj; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_install_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Convert and validate the device handle */ node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* * Root Object: * Registering a notify handler on the root object indicates that the * caller wishes to receive notifications for all objects. Note that * only one <external> global handler can be regsitered (per notify type). */ if (device == ACPI_ROOT_OBJECT) { /* Make sure the handler is not already installed */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && acpi_gbl_device_notify.handler)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = node; acpi_gbl_system_notify.handler = handler; acpi_gbl_system_notify.context = context; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = node; acpi_gbl_device_notify.handler = handler; acpi_gbl_device_notify.context = context; } /* Global notify handler installed */ } /* * All Other Objects: * Caller will only receive notifications specific to the target object. * Note that only certain object types can receive notifications. */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Object exists - make sure there's no handler */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && obj_desc->common_notify.system_notify) || ((handler_type & ACPI_DEVICE_NOTIFY) && obj_desc->common_notify.device_notify)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } } else { /* Create a new object */ obj_desc = acpi_ut_create_internal_object(node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Attach new object to the Node */ status = acpi_ns_attach_object(device, obj_desc, node->type); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } /* Install the handler */ notify_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY); if (!notify_obj) { status = AE_NO_MEMORY; goto unlock_and_exit; } notify_obj->notify.node = node; notify_obj->notify.handler = handler; notify_obj->notify.context = context; if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; } if (handler_type & ACPI_DEVICE_NOTIFY) { obj_desc->common_notify.device_notify = notify_obj; } if (handler_type == ACPI_ALL_NOTIFY) { /* Extra ref if installed in both */ acpi_ut_add_reference(notify_obj); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
acpi_status acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, union acpi_operand_object *return_desc) { acpi_status status; int same_as_implicit_return; ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", acpi_ut_get_node_name(walk_state->method_node), walk_state->method_call_op, return_desc)); ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", walk_state->return_used, walk_state->results, walk_state)); /* Did the called method return a value? */ if (return_desc) { /* Is the implicit return object the same as the return desc? */ same_as_implicit_return = (walk_state->implicit_return_obj == return_desc); /* Are we actually going to use the return value? */ if (walk_state->return_used) { /* Save the return value from the previous method */ status = acpi_ds_result_push(return_desc, walk_state); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); return_ACPI_STATUS(status); } /* * Save as THIS method's return value in case it is returned * immediately to yet another method */ walk_state->return_desc = return_desc; } /* * The following code is the optional support for the so-called * "implicit return". Some AML code assumes that the last value of the * method is "implicitly" returned to the caller, in the absence of an * explicit return value. * * Just save the last result of the method as the return value. * * NOTE: this is optional because the ASL language does not actually * support this behavior. */ else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE) || same_as_implicit_return) { /* * Delete the return value if it will not be used by the * calling method or remove one reference if the explicit return * is the same as the implicit return value. */ acpi_ut_remove_reference(return_desc); } } return_ACPI_STATUS(AE_OK); }
void acpi_ns_detach_object(struct acpi_namespace_node *node) { union acpi_operand_object *obj_desc; ACPI_FUNCTION_TRACE(ns_detach_object); obj_desc = node->object; if (!obj_desc || (obj_desc->common.type == ACPI_TYPE_LOCAL_DATA)) { return_VOID; } if (node->flags & ANOBJ_ALLOCATED_BUFFER) { /* Free the dynamic aml buffer */ if (obj_desc->common.type == ACPI_TYPE_METHOD) { ACPI_FREE(obj_desc->method.aml_start); } } if (obj_desc->common.type == ACPI_TYPE_REGION) { acpi_ut_remove_address_range(obj_desc->region.space_id, node); } /* Clear the Node entry in all cases */ node->object = NULL; if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_OPERAND) { /* Unlink object from front of possible object list */ node->object = obj_desc->common.next_object; /* Handle possible 2-descriptor object */ if (node->object && (node->object->common.type != ACPI_TYPE_LOCAL_DATA)) { node->object = node->object->common.next_object; } /* * Detach the object from any data objects (which are still held by * the namespace node) */ if (obj_desc->common.next_object && ((obj_desc->common.next_object)->common.type == ACPI_TYPE_LOCAL_DATA)) { obj_desc->common.next_object = NULL; } } /* Reset the node type to untyped */ node->type = ACPI_TYPE_ANY; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", node, acpi_ut_get_node_name(node), obj_desc)); /* Remove one reference on the object (and all subobjects) */ acpi_ut_remove_reference(obj_desc); return_VOID; }