static acpi_status acpi_ex_setup_region(union acpi_operand_object *obj_desc, u32 field_datum_byte_offset) { acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset); rgn_desc = obj_desc->common_field.region_obj; /* We must have a valid region */ if (ACPI_GET_OBJECT_TYPE(rgn_desc) != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type %X (%s)", ACPI_GET_OBJECT_TYPE(rgn_desc), acpi_ut_get_object_type_name(rgn_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. */ if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_region_arguments(rgn_desc); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } /* Exit if Address/Length have been disallowed by the host OS */ if (rgn_desc->common.flags & AOPOBJ_INVALID) { return_ACPI_STATUS(AE_AML_ILLEGAL_ADDRESS); } /* * Exit now for SMBus address space, it has a non-linear address space * and the request cannot be directly validated */ if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { /* SMBus has a non-linear address space */ return_ACPI_STATUS(AE_OK); } #ifdef ACPI_UNDER_DEVELOPMENT /* * If the Field access is any_acc, we can now compute the optimal * access (because we know know the length of the parent region) */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } #endif /* * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { if (acpi_gbl_enable_interpreter_slack) { /* * Slack mode only: We will go ahead and allow access to this * field if it is within the region length rounded up to the next * access width boundary. */ if (ACPI_ROUND_UP(rgn_desc->region.length, obj_desc->common_field. access_byte_width) >= (obj_desc->common_field.base_byte_offset + (acpi_native_uint) obj_desc->common_field. access_byte_width + field_datum_byte_offset)) { return_ACPI_STATUS(AE_OK); } } if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider * than the region itself. For example, a region of length one * byte, and a field with Dword access specified. */ ACPI_ERROR((AE_INFO, "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)", acpi_ut_get_node_name(obj_desc-> common_field.node), obj_desc->common_field.access_byte_width, acpi_ut_get_node_name(rgn_desc->region. node), rgn_desc->region.length)); } /* * Offset rounded up to next multiple of field width * exceeds region length, indicate an error */ ACPI_ERROR((AE_INFO, "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)", acpi_ut_get_node_name(obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name(rgn_desc->region.node), rgn_desc->region.length)); return_ACPI_STATUS(AE_AML_REGION_LIMIT); } return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ev_queue_notify_request(struct acpi_namespace_node * node, u32 notify_value) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj = NULL; union acpi_generic_state *notify_info; acpi_status status = AE_OK; ACPI_FUNCTION_NAME(ev_queue_notify_request); /* * For value 3 (Ejection Request), some device method may need to be run. * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need * to be run. * For value 0x80 (Status Change) on the power button or sleep button, * initiate soft-off or sleep operation? */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n", acpi_ut_get_node_name(node), node, notify_value, acpi_ut_get_notify_name(notify_value))); /* Get the notify object attached to the NS Node */ obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* We have the notify object, Get the right handler */ switch (node->type) { /* Notify allowed only on these types */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: case ACPI_TYPE_PROCESSOR: if (notify_value <= ACPI_MAX_SYS_NOTIFY) { handler_obj = obj_desc->common_notify.system_notify; } else { handler_obj = obj_desc->common_notify.device_notify; } break; default: /* All other types are not supported */ return (AE_TYPE); } } /* * If there is any handler to run, schedule the dispatcher. * Check for: * 1) Global system notify handler * 2) Global device notify handler * 3) Per-device notify handler */ if ((acpi_gbl_system_notify.handler && (notify_value <= ACPI_MAX_SYS_NOTIFY)) || (acpi_gbl_device_notify.handler && (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) { notify_info = acpi_ut_create_generic_state(); if (!notify_info) { return (AE_NO_MEMORY); } if (!handler_obj) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Executing system notify handler for Notify (%4.4s, %X) " "node %p\n", acpi_ut_get_node_name(node), notify_value, node)); } notify_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY; notify_info->notify.node = node; notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, notify_info); if (ACPI_FAILURE(status)) { acpi_ut_delete_generic_state(notify_info); } } else { /* There is no notify handler (per-device or system) for this device */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No notify handler for Notify (%4.4s, %X) node %p\n", acpi_ut_get_node_name(node), notify_value, node)); } return (status); }
void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ struct acpi_namespace_node *node, /* New Child */ acpi_object_type type) { acpi_owner_id owner_id = 0; struct acpi_namespace_node *child_node; ACPI_FUNCTION_TRACE(ns_install_node); if (walk_state) { /* * Get the owner ID from the Walk state. The owner ID is used to * track table deletion and deletion of objects created by methods. */ owner_id = walk_state->owner_id; if ((walk_state->method_desc) && (parent_node != walk_state->method_node)) { /* * A method is creating a new node that is not a child of the * method (it is non-local). Mark the executing method as having * modified the namespace. This is used for cleanup when the * method exits. */ walk_state->method_desc->method.info_flags |= ACPI_METHOD_MODIFIED_NAMESPACE; } } /* Link the new entry into the parent and existing children */ node->peer = NULL; node->parent = parent_node; child_node = parent_node->child; if (!child_node) { parent_node->child = node; } else { /* Add node to the end of the peer list */ while (child_node->peer) { child_node = child_node->peer; } child_node->peer = node; } /* Init the new entry */ node->owner_id = owner_id; node->type = (u8) type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", acpi_ut_get_node_name(node), acpi_ut_get_type_name(node->type), node, owner_id, acpi_ut_get_node_name(parent_node), acpi_ut_get_type_name(parent_node->type), parent_node)); return_VOID; }
static acpi_status acpi_ds_init_buffer_field(u16 aml_opcode, union acpi_operand_object *obj_desc, union acpi_operand_object *buffer_desc, union acpi_operand_object *offset_desc, union acpi_operand_object *length_desc, union acpi_operand_object *result_desc) { u32 offset; u32 bit_offset; u32 bit_count; u8 field_flags; acpi_status status; ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc); /* Host object must be a Buffer */ if (buffer_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, "Target of Create Field is not a Buffer object - %s", acpi_ut_get_object_type_name(buffer_desc))); status = AE_AML_OPERAND_TYPE; goto cleanup; } /* * The last parameter to all of these opcodes (result_desc) started * out as a name_string, and should therefore now be a NS node * after resolution in acpi_ex_resolve_operands(). */ if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "(%s) destination not a NS Node [%s]", acpi_ps_get_opcode_name(aml_opcode), acpi_ut_get_descriptor_name(result_desc))); status = AE_AML_OPERAND_TYPE; goto cleanup; } offset = (u32) offset_desc->integer.value; /* * Setup the Bit offsets and counts, according to the opcode */ switch (aml_opcode) { case AML_CREATE_FIELD_OP: /* Offset is in bits, count is in bits */ field_flags = AML_FIELD_ACCESS_BYTE; bit_offset = offset; bit_count = (u32) length_desc->integer.value; /* Must have a valid (>0) bit count */ if (bit_count == 0) { ACPI_ERROR((AE_INFO, "Attempt to CreateField of length zero")); status = AE_AML_OPERAND_VALUE; goto cleanup; } break; case AML_CREATE_BIT_FIELD_OP: /* Offset is in bits, Field is one bit */ bit_offset = offset; bit_count = 1; field_flags = AML_FIELD_ACCESS_BYTE; break; case AML_CREATE_BYTE_FIELD_OP: /* Offset is in bytes, field is one byte */ bit_offset = 8 * offset; bit_count = 8; field_flags = AML_FIELD_ACCESS_BYTE; break; case AML_CREATE_WORD_FIELD_OP: /* Offset is in bytes, field is one word */ bit_offset = 8 * offset; bit_count = 16; field_flags = AML_FIELD_ACCESS_WORD; break; case AML_CREATE_DWORD_FIELD_OP: /* Offset is in bytes, field is one dword */ bit_offset = 8 * offset; bit_count = 32; field_flags = AML_FIELD_ACCESS_DWORD; break; case AML_CREATE_QWORD_FIELD_OP: /* Offset is in bytes, field is one qword */ bit_offset = 8 * offset; bit_count = 64; field_flags = AML_FIELD_ACCESS_QWORD; break; default: ACPI_ERROR((AE_INFO, "Unknown field creation opcode 0x%02X", aml_opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } /* Entire field must fit within the current length of the buffer */ if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) { ACPI_ERROR((AE_INFO, "Field [%4.4s] at %u exceeds Buffer [%4.4s] size %u (bits)", acpi_ut_get_node_name(result_desc), bit_offset + bit_count, acpi_ut_get_node_name(buffer_desc->buffer.node), 8 * (u32) buffer_desc->buffer.length)); status = AE_AML_BUFFER_LIMIT; goto cleanup; } /* * Initialize areas of the field object that are common to all fields * For field_flags, use LOCK_RULE = 0 (NO_LOCK), * UPDATE_RULE = 0 (UPDATE_PRESERVE) */ status = acpi_ex_prep_common_field_object(obj_desc, field_flags, 0, bit_offset, bit_count); if (ACPI_FAILURE(status)) { goto cleanup; } obj_desc->buffer_field.buffer_obj = buffer_desc; /* Reference count for buffer_desc inherits obj_desc count */ buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + obj_desc->common.reference_count); cleanup: /* Always delete the operands */ acpi_ut_remove_reference(offset_desc); acpi_ut_remove_reference(buffer_desc); if (aml_opcode == AML_CREATE_FIELD_OP) { acpi_ut_remove_reference(length_desc); } /* On failure, delete the result descriptor */ if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(result_desc); /* Result descriptor */ } else { /* Now the address and length are valid for this buffer_field */ obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; } return_ACPI_STATUS(status); }
acpi_status acpi_ev_queue_notify_request ( struct acpi_namespace_node *node, u32 notify_value) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj = NULL; union acpi_generic_state *notify_info; acpi_status status = AE_OK; ACPI_FUNCTION_NAME ("ev_queue_notify_request"); /* * For value 3 (Ejection Request), some device method may need to be run. * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need * to be run. * For value 0x80 (Status Change) on the power button or sleep button, * initiate soft-off or sleep operation? */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dispatching Notify(%X) on node %p\n", notify_value, node)); if (notify_value <= 7) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: %s\n", acpi_notify_value_names[notify_value])); } else { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n", notify_value)); } /* Get the notify object attached to the NS Node */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* We have the notify object, Get the right handler */ switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_POWER: if (notify_value <= ACPI_MAX_SYS_NOTIFY) { handler_obj = obj_desc->common_notify.system_notify; } else { handler_obj = obj_desc->common_notify.device_notify; } break; default: /* All other types are not supported */ return (AE_TYPE); } } /* If there is any handler to run, schedule the dispatcher */ if ((acpi_gbl_system_notify.handler && (notify_value <= ACPI_MAX_SYS_NOTIFY)) || (acpi_gbl_device_notify.handler && (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) { notify_info = acpi_ut_create_generic_state (); if (!notify_info) { return (AE_NO_MEMORY); } notify_info->common.data_type = ACPI_DESC_TYPE_STATE_NOTIFY; notify_info->notify.node = node; notify_info->notify.value = (u16) notify_value; notify_info->notify.handler_obj = handler_obj; status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_notify_dispatch, notify_info); if (ACPI_FAILURE (status)) { acpi_ut_delete_generic_state (notify_info); } } if (!handler_obj) { /* * There is no per-device notify handler for this device. * This may or may not be a problem. */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "No notify handler for Notify(%4.4s, %X) node %p\n", acpi_ut_get_node_name (node), notify_value, node)); } return (status); }
acpi_status acpi_ex_setup_region ( union acpi_operand_object *obj_desc, u32 field_datum_byte_offset) { acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; ACPI_FUNCTION_TRACE_U32 ("ex_setup_region", field_datum_byte_offset); rgn_desc = obj_desc->common_field.region_obj; /* We must have a valid region */ if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", ACPI_GET_OBJECT_TYPE (rgn_desc), acpi_ut_get_object_type_name (rgn_desc))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. */ if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_region_arguments (rgn_desc); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { /* SMBus has a non-linear address space */ return_ACPI_STATUS (AE_OK); } #ifdef ACPI_UNDER_DEVELOPMENT /* * If the Field access is any_acc, we can now compute the optimal * access (because we know know the length of the parent region) */ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } } #endif /* * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider * than the region itself. For example, a region of length one * byte, and a field with Dword access specified. */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); } /* * Offset rounded up to next multiple of field width * exceeds region length, indicate an error */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", acpi_ut_get_node_name (obj_desc->common_field.node), obj_desc->common_field.base_byte_offset, field_datum_byte_offset, obj_desc->common_field.access_byte_width, acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); if (!acpi_strict) { /* * Allow access to the field if it is within the region size * rounded up to a multiple of the access byte width. This * overcomes "off-by-one" programming errors in the AML often * found in Toshiba laptops. These errors were allowed by * the Microsoft ASL compiler. */ u32 rounded_length = ACPI_ROUND_UP(rgn_desc->region.length, obj_desc->common_field.access_byte_width); if (rounded_length < (obj_desc->common_field.base_byte_offset + field_datum_byte_offset + obj_desc->common_field.access_byte_width)) { return_ACPI_STATUS (AE_AML_REGION_LIMIT); } else { static int warn_once = 1; if (warn_once) { // Could also associate a flag with each field, and // warn once for each field. ACPI_REPORT_WARNING(( "The ACPI AML in your computer contains errors, " "please nag the manufacturer to correct it.\n")); ACPI_REPORT_WARNING(( "Allowing relaxed access to fields; " "turn on CONFIG_ACPI_DEBUG for details.\n")); warn_once = 0; } return_ACPI_STATUS (AE_OK); } } else { return_ACPI_STATUS (AE_AML_REGION_LIMIT); } } return_ACPI_STATUS (AE_OK); }
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); 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 %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); 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); }
acpi_status acpi_ds_init_one_object ( acpi_handle obj_handle, u32 level, void *context, void **return_value) { acpi_object_type type; acpi_status status; struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; ACPI_FUNCTION_NAME ("ds_init_one_object"); /* * We are only interested in objects owned by the table that * was just loaded */ if (((struct acpi_namespace_node *) obj_handle)->owner_id != info->table_desc->table_id) { return (AE_OK); } info->object_count++; /* And even then, we are only interested in a few object types */ type = acpi_ns_get_type (obj_handle); switch (type) { case ACPI_TYPE_REGION: status = acpi_ds_initialize_region (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); } info->op_region_count++; break; case ACPI_TYPE_METHOD: info->method_count++; /* Print a dot for each method unless we are going to print the entire pathname */ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); } /* * Set the execution data width (32 or 64) based upon the * revision number of the parent ACPI table. * TBD: This is really for possible future support of integer width * on a per-table basis. Currently, we just use a global for the width. */ if (info->table_desc->pointer->revision == 1) { ((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; } /* * Always parse methods to detect errors, we will delete * the parse tree below */ status = acpi_ds_parse_method (obj_handle); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", obj_handle, acpi_ut_get_node_name (obj_handle), acpi_format_exception (status))); /* This parse failed, but we will continue parsing more methods */ break; } /* * Delete the parse tree. We simply re-parse the method * for every execution since there isn't much overhead */ acpi_ns_delete_namespace_subtree (obj_handle); acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); break; case ACPI_TYPE_DEVICE: info->device_count++; break; default: break; } /* * We ignore errors from above, and always return OK, since * we don't want to abort the walk on a single error. */ return (AE_OK); }
acpi_status acpi_ns_lookup(union acpi_generic_state *scope_info, char *pathname, acpi_object_type type, acpi_interpreter_mode interpreter_mode, u32 flags, struct acpi_walk_state *walk_state, struct acpi_namespace_node **return_node) { acpi_status status; char *path = pathname; struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *current_node = NULL; struct acpi_namespace_node *this_node = NULL; u32 num_segments; u32 num_carats; acpi_name simple_name; acpi_object_type type_to_check_for; acpi_object_type this_search_type; u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); ACPI_FUNCTION_TRACE("ns_lookup"); if (!return_node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } acpi_gbl_ns_lookup_count++; *return_node = ACPI_ENTRY_NOT_FOUND; if (!acpi_gbl_root_node) { return_ACPI_STATUS(AE_NO_NAMESPACE); } /* * Get the prefix scope. * A null scope means use the root scope */ if ((!scope_info) || (!scope_info->scope.node)) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null scope prefix, using root node (%p)\n", acpi_gbl_root_node)); prefix_node = acpi_gbl_root_node; } else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", prefix_node, acpi_ut_get_descriptor_name(prefix_node))); return_ACPI_STATUS(AE_AML_INTERNAL); } /* * This node might not be a actual "scope" node (such as a * Device/Method, etc.) It could be a Package or other object node. * Backup up the tree to find the containing scope node. */ while (!acpi_ns_opens_scope(prefix_node->type) && prefix_node->type != ACPI_TYPE_ANY) { prefix_node = acpi_ns_get_parent_node(prefix_node); } } /* Save type TBD: may be no longer necessary */ type_to_check_for = type; /* * Begin examination of the actual pathname */ if (!pathname) { /* A Null name_path is allowed and refers to the root */ num_segments = 0; this_node = acpi_gbl_root_node; path = ""; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null Pathname (Zero segments), Flags=%X\n", flags)); } else { /* * Name pointer is valid (and must be in internal name format) * * Check for scope prefixes: * * As represented in the AML stream, a namepath consists of an * optional scope prefix followed by a name segment part. * * If present, the scope prefix is either a Root Prefix (in * which case the name is fully qualified), or one or more * Parent Prefixes (in which case the name's scope is relative * to the current scope). */ if (*path == (u8) AML_ROOT_PREFIX) { /* Pathname is fully qualified, start from the root */ this_node = acpi_gbl_root_node; search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Point to name segment part */ path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Path is absolute from root [%p]\n", this_node)); } else { /* Pathname is relative to current scope, start there */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching relative to prefix scope [%4.4s] (%p)\n", acpi_ut_get_node_name(prefix_node), prefix_node)); /* * Handle multiple Parent Prefixes (carat) by just getting * the parent node for each prefix instance. */ this_node = prefix_node; num_carats = 0; while (*path == (u8) AML_PARENT_PREFIX) { /* Name is fully qualified, no search rules apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* * Point past this prefix to the name segment * part or the next Parent Prefix */ path++; /* Backup to the parent node */ num_carats++; this_node = acpi_ns_get_parent_node(this_node); if (!this_node) { /* Current scope has no parent scope */ ACPI_ERROR((AE_INFO, "ACPI path has too many parent prefixes (^) - reached beyond root node")); return_ACPI_STATUS(AE_NOT_FOUND); } } if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Search scope is [%4.4s], path has %d carat(s)\n", acpi_ut_get_node_name (this_node), num_carats)); } } /* * Determine the number of ACPI name segments in this pathname. * * The segment part consists of either: * - A Null name segment (0) * - A dual_name_prefix followed by two 4-byte name segments * - A multi_name_prefix followed by a byte indicating the * number of segments and the segments themselves. * - A single 4-byte name segment * * Examine the name prefix opcode, if any, to determine the number of * segments. */ switch (*path) { case 0: /* * Null name after a root or parent prefixes. We already * have the correct target node and there are no name segments. */ num_segments = 0; type = this_node->type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags)); break; case AML_DUAL_NAME_PREFIX: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Two segments, point to first name segment */ num_segments = 2; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Dual Pathname (2 segments, Flags=%X)\n", flags)); break; case AML_MULTI_NAME_PREFIX_OP: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Extract segment count, point to first name segment */ path++; num_segments = (u32) (u8) * path; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Multi Pathname (%d Segments, Flags=%X)\n", num_segments, flags)); break; default: /* * Not a Null name, no Dual or Multi prefix, hence there is * only one name segment and Pathname is already pointing to it. */ num_segments = 1; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Simple Pathname (1 segment, Flags=%X)\n", flags)); break; } ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); } /* * Search namespace for each segment of the name. Loop through and * verify (or add to the namespace) each name segment. * * The object type is significant only at the last name * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; current_node = this_node; while (num_segments && current_node) { num_segments--; if (!num_segments) { /* * This is the last segment, enable typechecking */ this_search_type = type; /* * Only allow automatic parent search (search rules) if the caller * requested it AND we have a single, non-fully-qualified name_seg */ if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && (flags & ACPI_NS_SEARCH_PARENT)) { local_flags |= ACPI_NS_SEARCH_PARENT; } /* Set error flag according to caller */ if (flags & ACPI_NS_ERROR_IF_FOUND) { local_flags |= ACPI_NS_ERROR_IF_FOUND; } } /* Extract one ACPI name from the front of the pathname */ ACPI_MOVE_32_TO_32(&simple_name, path); /* Try to find the single (4 character) ACPI name */ status = acpi_ns_search_and_enter(simple_name, walk_state, current_node, interpreter_mode, this_search_type, local_flags, &this_node); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { /* Name not found in ACPI namespace */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] not found in scope [%4.4s] %p\n", (char *)&simple_name, (char *)¤t_node->name, current_node)); } *return_node = this_node; return_ACPI_STATUS(status); } /* * Sanity typecheck of the target object: * * If 1) This is the last segment (num_segments == 0) * 2) And we are looking for a specific type * (Not checking for TYPE_ANY) * 3) Which is not an alias * 4) Which is not a local type (TYPE_SCOPE) * 5) And the type of target object is known (not TYPE_ANY) * 6) And target object does not match what we are looking for * * Then we have a type mismatch. Just warn and ignore it. */ if ((num_segments == 0) && (type_to_check_for != ACPI_TYPE_ANY) && (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { /* Complain about a type mismatch */ ACPI_WARNING((AE_INFO, "ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)", ACPI_CAST_PTR(char, &simple_name), acpi_ut_get_type_name(this_node->type), acpi_ut_get_type_name (type_to_check_for))); } /* * If this is the last name segment and we are not looking for a * specific type, but the type of found object is known, use that type * to see if it opens a scope. */ if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) { type = this_node->type; } /* Point to next name segment and make this node current */ path += ACPI_NAME_SIZE; current_node = this_node; }
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); }