acpi_status acpi_ev_attach_region(union acpi_operand_object *handler_obj, union acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { ACPI_FUNCTION_TRACE(ev_attach_region); ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Adding Region [%4.4s] %p to address handler %p [%s]\n", acpi_ut_get_node_name(region_obj->region.node), region_obj, handler_obj, acpi_ut_get_region_name(region_obj->region. space_id))); /* Link this region to the front of the handler's list */ region_obj->region.next = handler_obj->address_space.region_list; handler_obj->address_space.region_list = region_obj; /* Install the region's handler */ if (region_obj->region.handler) { return_ACPI_STATUS(AE_ALREADY_EXISTS); } region_obj->region.handler = handler_obj; acpi_ut_add_reference(handler_obj); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) { u64 address; acpi_status status; ACPI_FUNCTION_NAME(hw_write); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_write_memory((acpi_physical_address) address, (u64)value, reg->bit_width); } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_write_port((acpi_io_address) address, value, reg->bit_width); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", value, reg->bit_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) { u64 address; acpi_status status; ACPI_FUNCTION_NAME(hw_read); status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } *value = 0; if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_read_memory((acpi_physical_address) address, value, reg->bit_width); } else { status = acpi_hw_read_port((acpi_io_address) address, value, reg->bit_width); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *value, reg->bit_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
u32 acpi_ut_check_address_range(acpi_adr_space_type space_id, acpi_physical_address address, u32 length, u8 warn) { struct acpi_address_range *range_info; acpi_physical_address end_address; char *pathname; u32 overlap_count = 0; ACPI_FUNCTION_TRACE(ut_check_address_range); if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { return_UINT32(0); } range_info = acpi_gbl_address_range_list[space_id]; end_address = address + length - 1; /* Check entire list for all possible conflicts */ while (range_info) { /* * Check if the requested address/length overlaps this * address range. There are four cases to consider: * * 1) Input address/length is contained completely in the * address range * 2) Input address/length overlaps range at the range start * 3) Input address/length overlaps range at the range end * 4) Input address/length completely encompasses the range */ if ((address <= range_info->end_address) && (end_address >= range_info->start_address)) { /* Found an address range overlap */ overlap_count++; if (warn) { /* Optional warning message */ pathname = acpi_ns_get_external_pathname(range_info-> region_node); ACPI_WARNING((AE_INFO, "%s range 0x%p-0x%p conflicts with OpRegion 0x%p-0x%p (%s)", acpi_ut_get_region_name (space_id), ACPI_CAST_PTR(void, address), ACPI_CAST_PTR(void, end_address), ACPI_CAST_PTR(void, range_info->start_address), ACPI_CAST_PTR(void, range_info->end_address), pathname)); ACPI_FREE(pathname); } } range_info = range_info->next; }
acpi_status acpi_ev_attach_region ( union acpi_operand_object *handler_obj, union acpi_operand_object *region_obj, u8 acpi_ns_is_locked) { acpi_status status; acpi_status status2; ACPI_FUNCTION_TRACE ("ev_attach_region"); ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Adding Region %p to address handler %p [%s]\n", region_obj, handler_obj, acpi_ut_get_region_name (region_obj->region.space_id))); /* Link this region to the front of the handler's list */ region_obj->region.next = handler_obj->address_space.region_list; handler_obj->address_space.region_list = region_obj; /* Install the region's handler */ if (region_obj->region.address_space) { return_ACPI_STATUS (AE_ALREADY_EXISTS); } region_obj->region.address_space = handler_obj; acpi_ut_add_reference (handler_obj); /* * Tell all users that this region is usable by running the _REG * method */ if (acpi_ns_is_locked) { status2 = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status2)) { return_ACPI_STATUS (status2); } } status = acpi_ev_execute_reg_method (region_obj, 1); if (acpi_ns_is_locked) { status2 = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status2)) { return_ACPI_STATUS (status2); } } return_ACPI_STATUS (status); }
acpi_status acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, acpi_adr_space_type space_id) { acpi_status status; struct acpi_reg_walk_info info; ACPI_FUNCTION_TRACE(ev_execute_reg_methods); info.space_id = space_id; info.reg_run_count = 0; ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, " Running _REG methods for SpaceId %s\n", acpi_ut_get_region_name(info.space_id))); /* * Run all _REG methods for all Operation Regions for this space ID. This * is a separate walk in order to handle any interdependencies between * regions and _REG methods. (i.e. handlers must be installed for all * regions of this Space ID before we can run any _REG methods) */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL, &info, NULL); /* Special case for EC: handle "orphan" _REG methods with no region */ if (space_id == ACPI_ADR_SPACE_EC) { acpi_ev_orphan_ec_reg_method(node); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, " Executed %u _REG methods for SpaceId %s\n", info.reg_run_count, acpi_ut_get_region_name(info.space_id))); return_ACPI_STATUS(status); }
static acpi_status acpi_db_display_non_root_handlers(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_namespace_node *node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; char *pathname; obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return (AE_OK); } pathname = acpi_ns_get_normalized_pathname(node, TRUE); if (!pathname) { return (AE_OK); } /* Display all handlers associated with this device */ handler_obj = obj_desc->common_notify.handler; while (handler_obj) { acpi_os_printf(ACPI_PREDEFINED_PREFIX, acpi_ut_get_region_name((u8)handler_obj-> address_space.space_id), handler_obj->address_space.space_id); acpi_os_printf(ACPI_HANDLER_PRESENT_STRING2, (handler_obj->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default" : "User", handler_obj->address_space.handler); acpi_os_printf(" Device Name: %s (%p)\n", pathname, node); handler_obj = handler_obj->address_space.next; } ACPI_FREE(pathname); return (AE_OK); }
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) { u64 address; u64 value64; acpi_status status; ACPI_FUNCTION_NAME(hw_read); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* Initialize entire 32-bit return value to zero */ *value = 0; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_read_memory((acpi_physical_address) address, &value64, reg->bit_width); *value = (u32)value64; } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_read_port((acpi_io_address) address, value, reg->bit_width); } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *value, reg->bit_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj, u8 acpi_ns_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; struct acpi_namespace_node *method_node; acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; union acpi_operand_object *region_obj2; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { return_ACPI_STATUS(AE_OK); } region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } node = acpi_ns_get_parent_node(region_obj->region.node); space_id = region_obj->region.space_id; /* Setup defaults */ region_obj->region.handler = NULL; region_obj2->extra.method_REG = NULL; region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; /* Find any "_REG" method associated with this region definition */ status = acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, &method_node); if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region * definition. This will be executed when the handler is attached * or removed */ region_obj2->extra.method_REG = method_node; } /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->parent_entry being set to NULL */ while (node) { /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: handler_obj = obj_desc->device.handler; break; case ACPI_TYPE_PROCESSOR: handler_obj = obj_desc->processor.handler; break; case ACPI_TYPE_THERMAL: handler_obj = obj_desc->thermal_zone.handler; break; default: /* Ignore other objects */ break; } while (handler_obj) { /* Is this handler of the correct type? */ if (handler_obj->address_space.space_id == space_id) { /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler %p for region %p in obj %p\n", handler_obj, region_obj, obj_desc)); status = acpi_ev_attach_region(handler_obj, region_obj, acpi_ns_locked); /* * Tell all users that this region is usable by running the _REG * method */ if (acpi_ns_locked) { status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } status = acpi_ev_execute_reg_method (region_obj, 1); if (acpi_ns_locked) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } return_ACPI_STATUS(AE_OK); } /* Try next handler in the list */ handler_obj = handler_obj->address_space.next; } } /* * This node does not have the handler we need; * Pop up one level */ node = acpi_ns_get_parent_node(node); } /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); }
acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *field_obj, u32 function, u32 region_offset, u32 bit_width, u64 *value) { acpi_status status; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; union acpi_operand_object *handler_desc; union acpi_operand_object *region_obj2; void *region_context = NULL; struct acpi_connection_info *context; acpi_physical_address address; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } /* Ensure that there is a handler associated with this region */ handler_desc = region_obj->region.handler; if (!handler_desc) { ACPI_ERROR((AE_INFO, "No handler for Region [%4.4s] (%p) [%s]", acpi_ut_get_node_name(region_obj->region.node), region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); return_ACPI_STATUS(AE_NOT_EXIST); } context = handler_desc->address_space.context; /* * It may be the case that the region has never been initialized. * Some types of regions require special init code */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { /* This region has not been initialized yet, do it */ region_setup = handler_desc->address_space.setup; if (!region_setup) { /* No initialization routine, exit with error */ ACPI_ERROR((AE_INFO, "No init routine for region(%p) [%s]", region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); return_ACPI_STATUS(AE_NOT_EXIST); } /* * We must exit the interpreter because the region setup will * potentially execute control methods (for example, the _REG method * for this region) */ acpi_ex_exit_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, context, ®ion_context); /* Re-enter the interpreter */ acpi_ex_enter_interpreter(); /* Check for failure of the Region Setup */ if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During region initialization: [%s]", acpi_ut_get_region_name(region_obj-> region. space_id))); return_ACPI_STATUS(status); } /* Region initialization may have been completed by region_setup */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; /* * Save the returned context for use in all accesses to * the handler for this particular region */ if (!(region_obj2->extra.region_context)) { region_obj2->extra.region_context = region_context; } } } /* We have everything we need, we can invoke the address space handler */ handler = handler_desc->address_space.handler; address = (region_obj->region.address + region_offset); /* * Special handling for generic_serial_bus and general_purpose_io: * There are three extra parameters that must be passed to the * handler via the context: * 1) Connection buffer, a resource template from Connection() op * 2) Length of the above buffer * 3) Actual access length from the access_as() op * * In addition, for general_purpose_io, the Address and bit_width fields * are defined as follows: * 1) Address is the pin number index of the field (bit offset from * the previous Connection) * 2) bit_width is the actual bit length of the field (number of pins) */ if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) && context && field_obj) { /* Get the Connection (resource_template) buffer */ context->connection = field_obj->field.resource_buffer; context->length = field_obj->field.resource_length; context->access_length = field_obj->field.access_length; } if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) && context && field_obj) { /* Get the Connection (resource_template) buffer */ context->connection = field_obj->field.resource_buffer; context->length = field_obj->field.resource_length; context->access_length = field_obj->field.access_length; address = field_obj->field.pin_number_index; bit_width = field_obj->field.bit_length; } ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, ACPI_FORMAT_NATIVE_UINT(address), acpi_ut_get_region_name(region_obj->region. space_id))); if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't * know what it will do, so we can't hold the lock on the intepreter. */ acpi_ex_exit_interpreter(); } /* Call the handler */ status = handler(function, address, bit_width, value, context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", acpi_ut_get_region_name(region_obj->region. space_id))); } if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter */ acpi_ex_enter_interpreter(); } return_ACPI_STATUS(status); }
acpi_status acpi_ex_access_region(union acpi_operand_object *obj_desc, u32 field_datum_byte_offset, u64 *value, u32 function) { acpi_status status; union acpi_operand_object *rgn_desc; u32 region_offset; ACPI_FUNCTION_TRACE(ex_access_region); /* * Ensure that the region operands are fully evaluated and verify * the validity of the request */ status = acpi_ex_setup_region(obj_desc, field_datum_byte_offset); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * The physical address of this field datum is: * * 1) The base of the region, plus * 2) The base offset of the field, plus * 3) The current offset into the field */ rgn_desc = obj_desc->common_field.region_obj; region_offset = obj_desc->common_field.base_byte_offset + field_datum_byte_offset; if ((function & ACPI_IO_MASK) == ACPI_READ) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[READ]")); } else { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "[WRITE]")); } ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD, " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id, obj_desc->common_field.access_byte_width, obj_desc->common_field.base_byte_offset, field_datum_byte_offset, ACPI_CAST_PTR(void, (rgn_desc-> region. address + region_offset)))); /* Invoke the appropriate address_space/op_region handler */ status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc, function, region_offset, ACPI_MUL_8(obj_desc-> common_field. access_byte_width), value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { ACPI_ERROR((AE_INFO, "Region %s (ID=%u) not implemented", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { ACPI_ERROR((AE_INFO, "Region %s (ID=%u) has no handler", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id)); } } return_ACPI_STATUS(status); }
acpi_status acpi_ns_dump_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { struct acpi_walk_info *info = (struct acpi_walk_info *)context; struct acpi_namespace_node *this_node; union acpi_operand_object *obj_desc = NULL; acpi_object_type obj_type; acpi_object_type type; u32 bytes_to_dump; u32 dbg_level; u32 i; ACPI_FUNCTION_NAME(ns_dump_one_object); /* Is output enabled? */ if (!(acpi_dbg_level & info->debug_level)) { return (AE_OK); } if (!obj_handle) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null object handle\n")); return (AE_OK); } this_node = acpi_ns_map_handle_to_node(obj_handle); type = this_node->type; /* Check if the owner matches */ if ((info->owner_id != ACPI_OWNER_ID_MAX) && (info->owner_id != this_node->owner_id)) { return (AE_OK); } if (!(info->display_type & ACPI_DISPLAY_SHORT)) { /* Indent the object according to the level */ acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " "); /* Check the node type and name */ if (type > ACPI_TYPE_LOCAL_MAX) { ACPI_WARNING((AE_INFO, "Invalid ACPI Object Type %08X", type)); } if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { this_node->name.integer = acpi_ut_repair_name(this_node->name.ascii); ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); } acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); } /* * Now we can print out the pertinent information */ acpi_os_printf(" %-12s %p %2.2X ", acpi_ut_get_type_name(type), this_node, this_node->owner_id); dbg_level = acpi_dbg_level; acpi_dbg_level = 0; obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; /* Temp nodes are those nodes created by a control method */ if (this_node->flags & ANOBJ_TEMPORARY) { acpi_os_printf("(T) "); } switch (info->display_type & ACPI_DISPLAY_MASK) { case ACPI_DISPLAY_SUMMARY: if (!obj_desc) { /* No attached object, we are done */ acpi_os_printf("\n"); return (AE_OK); } switch (type) { case ACPI_TYPE_PROCESSOR: acpi_os_printf("ID %X Len %.4X Addr %p\n", obj_desc->processor.proc_id, obj_desc->processor.length, ACPI_CAST_PTR(void, obj_desc->processor. address)); break; case ACPI_TYPE_DEVICE: acpi_os_printf("Notify Object: %p\n", obj_desc); break; case ACPI_TYPE_METHOD: acpi_os_printf("Args %X Len %.4X Aml %p\n", (u32) obj_desc->method.param_count, obj_desc->method.aml_length, obj_desc->method.aml_start); break; case ACPI_TYPE_INTEGER: acpi_os_printf("= %8.8X%8.8X\n", ACPI_FORMAT_UINT64(obj_desc->integer. value)); break; case ACPI_TYPE_PACKAGE: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Elements %.2X\n", obj_desc->package.count); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_BUFFER: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Len %.2X", obj_desc->buffer.length); /* Dump some of the buffer */ if (obj_desc->buffer.length > 0) { acpi_os_printf(" ="); for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { acpi_os_printf(" %.2hX", obj_desc->buffer. pointer[i]); } } acpi_os_printf("\n"); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_STRING: acpi_os_printf("Len %.2X ", obj_desc->string.length); acpi_ut_print_string(obj_desc->string.pointer, 32); acpi_os_printf("\n"); break; case ACPI_TYPE_REGION: acpi_os_printf("[%s]", acpi_ut_get_region_name(obj_desc->region. space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", ACPI_FORMAT_NATIVE_UINT (obj_desc->region.address), obj_desc->region.length); } else { acpi_os_printf (" [Address/Length not yet evaluated]\n"); } break; case ACPI_TYPE_LOCAL_REFERENCE: acpi_os_printf("[%s]\n", acpi_ps_get_opcode_name(obj_desc-> reference. opcode)); break; case ACPI_TYPE_BUFFER_FIELD: if (obj_desc->buffer_field.buffer_obj && obj_desc->buffer_field.buffer_obj->buffer.node) { acpi_os_printf("Buf [%4.4s]", acpi_ut_get_node_name(obj_desc-> buffer_field. buffer_obj-> buffer. node)); } break; case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf("Rgn [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: acpi_os_printf("Rgn [%4.4s] Bnk [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node), acpi_ut_get_node_name(obj_desc-> bank_field. bank_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf("Idx [%4.4s] Dat [%4.4s]", acpi_ut_get_node_name(obj_desc-> index_field. index_obj-> common_field.node), acpi_ut_get_node_name(obj_desc-> index_field. data_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_ALIAS: case ACPI_TYPE_LOCAL_METHOD_ALIAS: acpi_os_printf("Target %4.4s (%p)\n", acpi_ut_get_node_name(obj_desc), obj_desc); break; default: acpi_os_printf("Object %p\n", obj_desc); break; } /* Common field handling */ switch (type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf(" Off %.3X Len %.2X Acc %.2hd\n", (obj_desc->common_field. base_byte_offset * 8) + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field.bit_length, obj_desc->common_field. access_byte_width); break; default: break; } break; case ACPI_DISPLAY_OBJECTS: acpi_os_printf("O:%p", obj_desc); if (!obj_desc) { /* No attached object, we are done */ acpi_os_printf("\n"); return (AE_OK); } acpi_os_printf("(R%d)", obj_desc->common.reference_count); switch (type) { case ACPI_TYPE_METHOD: /* Name is a Method and its AML offset/length are set */ acpi_os_printf(" M:%p-%X\n", obj_desc->method.aml_start, obj_desc->method.aml_length); break; case ACPI_TYPE_INTEGER: acpi_os_printf(" I:%8.8X8.8%X\n", ACPI_FORMAT_UINT64(obj_desc->integer. value)); break; case ACPI_TYPE_STRING: acpi_os_printf(" S:%p-%X\n", obj_desc->string.pointer, obj_desc->string.length); break; case ACPI_TYPE_BUFFER: acpi_os_printf(" B:%p-%X\n", obj_desc->buffer.pointer, obj_desc->buffer.length); break; default: acpi_os_printf("\n"); break; } break; default: acpi_os_printf("\n"); break; } /* If debug turned off, done */ if (!(acpi_dbg_level & ACPI_LV_VALUES)) { return (AE_OK); } /* If there is an attached object, display it */ dbg_level = acpi_dbg_level; acpi_dbg_level = 0; obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; /* Dump attached objects */ while (obj_desc) { obj_type = ACPI_TYPE_INVALID; acpi_os_printf("Attached Object %p: ", obj_desc); /* Decode the type of attached object and dump the contents */ switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { case ACPI_DESC_TYPE_NAMED: acpi_os_printf("(Ptr to Node)\n"); bytes_to_dump = sizeof(struct acpi_namespace_node); ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); break; case ACPI_DESC_TYPE_OPERAND: obj_type = ACPI_GET_OBJECT_TYPE(obj_desc); if (obj_type > ACPI_TYPE_LOCAL_MAX) { acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n", obj_type); bytes_to_dump = 32; } else { acpi_os_printf ("(Ptr to ACPI Object type %X [%s])\n", obj_type, acpi_ut_get_type_name(obj_type)); bytes_to_dump = sizeof(union acpi_operand_object); } ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); break; default: break; } /* If value is NOT an internal object, we are done */ if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { goto cleanup; } /* * Valid object, get the pointer to next level, if any */ switch (obj_type) { case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: /* * NOTE: takes advantage of common fields between string/buffer */ bytes_to_dump = obj_desc->string.length; obj_desc = (void *)obj_desc->string.pointer; acpi_os_printf("(Buffer/String pointer %p length %X)\n", obj_desc, bytes_to_dump); ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); goto cleanup; case ACPI_TYPE_BUFFER_FIELD: obj_desc = (union acpi_operand_object *)obj_desc->buffer_field. buffer_obj; break; case ACPI_TYPE_PACKAGE: obj_desc = (void *)obj_desc->package.elements; break; case ACPI_TYPE_METHOD: obj_desc = (void *)obj_desc->method.aml_start; break; case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc = (void *)obj_desc->field.region_obj; break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc = (void *)obj_desc->bank_field.region_obj; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: obj_desc = (void *)obj_desc->index_field.index_obj; break; default: goto cleanup; } obj_type = ACPI_TYPE_INVALID; /* Terminate loop after next pass */ } cleanup: acpi_os_printf("\n"); return (AE_OK); }
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u32 value32; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_read); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* * Initialize entire 32-bit return value to zero, convert access_width * into number of bits based */ *value = 0; access_width = acpi_hw_get_access_bit_width(reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { if (bit_offset >= access_width) { value32 = 0; bit_offset -= access_width; } else { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_read_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), &value64, access_width); value32 = (u32)value64; } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_read_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), &value32, access_width); } /* * Use offset style bit masks because: * bit_offset < access_width/bit_width < access_width, and * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ if (bit_offset) { value32 &= ACPI_MASK_BITS_BELOW(bit_offset); bit_offset = 0; } if (bit_width < access_width) { value32 &= ACPI_MASK_BITS_ABOVE(bit_width); } } /* * Use offset style bit writes because "Index * AccessWidth" is * ensured to be less than 32-bits by acpi_hw_validate_register(). */ ACPI_SET_BITS(value, index * access_width, ACPI_MASK_BITS_ABOVE_32(access_width), value32); bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) { u32 length; u32 index; ACPI_FUNCTION_NAME(ex_dump_operand) if (! ((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } if (!obj_desc) { /* This could be a null element of a package */ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); return; } if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) == ACPI_DESC_TYPE_NAMED) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p Namespace Node: ", obj_desc)); ACPI_DUMP_ENTRY(obj_desc, ACPI_LV_EXEC); return; } if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p is not a node or operand object: [%s]\n", obj_desc, acpi_ut_get_descriptor_name(obj_desc))); ACPI_DUMP_BUFFER(obj_desc, sizeof(union acpi_operand_object)); return; } /* obj_desc is a valid object */ if (depth > 0) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%*s[%u] %p ", depth, " ", depth, obj_desc)); } else { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%p ", obj_desc)); } /* Decode object type */ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) { case ACPI_TYPE_LOCAL_REFERENCE: switch (obj_desc->reference.opcode) { case AML_DEBUG_OP: acpi_os_printf("Reference: Debug\n"); break; case AML_NAME_OP: ACPI_DUMP_PATHNAME(obj_desc->reference.object, "Reference: Name: ", ACPI_LV_INFO, _COMPONENT); ACPI_DUMP_ENTRY(obj_desc->reference.object, ACPI_LV_INFO); break; case AML_INDEX_OP: acpi_os_printf("Reference: Index %p\n", obj_desc->reference.object); break; case AML_REF_OF_OP: acpi_os_printf("Reference: (RefOf) %p\n", obj_desc->reference.object); break; case AML_ARG_OP: acpi_os_printf("Reference: Arg%d", obj_desc->reference.offset); if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { /* Value is an Integer */ acpi_os_printf(" value is [%8.8X%8.8x]", ACPI_FORMAT_UINT64(obj_desc-> integer. value)); } acpi_os_printf("\n"); break; case AML_LOCAL_OP: acpi_os_printf("Reference: Local%d", obj_desc->reference.offset); if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { /* Value is an Integer */ acpi_os_printf(" value is [%8.8X%8.8x]", ACPI_FORMAT_UINT64(obj_desc-> integer. value)); } acpi_os_printf("\n"); break; case AML_INT_NAMEPATH_OP: acpi_os_printf("Reference.Node->Name %X\n", obj_desc->reference.node->name.integer); break; default: /* Unknown opcode */ acpi_os_printf("Unknown Reference opcode=%X\n", obj_desc->reference.opcode); break; } break; case ACPI_TYPE_BUFFER: acpi_os_printf("Buffer len %X @ %p\n", obj_desc->buffer.length, obj_desc->buffer.pointer); length = obj_desc->buffer.length; if (length > 64) { length = 64; } /* Debug only -- dump the buffer contents */ if (obj_desc->buffer.pointer) { acpi_os_printf("Buffer Contents: "); for (index = 0; index < length; index++) { acpi_os_printf(" %02x", obj_desc->buffer.pointer[index]); } acpi_os_printf("\n"); } break; case ACPI_TYPE_INTEGER: acpi_os_printf("Integer %8.8X%8.8X\n", ACPI_FORMAT_UINT64(obj_desc->integer.value)); break; case ACPI_TYPE_PACKAGE: acpi_os_printf("Package [Len %X] ElementArray %p\n", obj_desc->package.count, obj_desc->package.elements); /* * If elements exist, package element pointer is valid, * and debug_level exceeds 1, dump package's elements. */ if (obj_desc->package.count && obj_desc->package.elements && acpi_dbg_level > 1) { for (index = 0; index < obj_desc->package.count; index++) { acpi_ex_dump_operand(obj_desc->package. elements[index], depth + 1); } } break; case ACPI_TYPE_REGION: acpi_os_printf("Region %s (%X)", acpi_ut_get_region_name(obj_desc->region. space_id), obj_desc->region.space_id); /* * If the address and length have not been evaluated, * don't print them. */ if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) { acpi_os_printf("\n"); } else { acpi_os_printf(" base %8.8X%8.8X Length %X\n", ACPI_FORMAT_UINT64(obj_desc->region. address), obj_desc->region.length); } break; case ACPI_TYPE_STRING: acpi_os_printf("String length %X @ %p ", obj_desc->string.length, obj_desc->string.pointer); acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX); acpi_os_printf("\n"); break; case ACPI_TYPE_LOCAL_BANK_FIELD: acpi_os_printf("BankField\n"); break; case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf ("RegionField: Bits=%X AccWidth=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", obj_desc->field.bit_length, obj_desc->field.access_byte_width, obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset); acpi_ex_dump_operand(obj_desc->field.region_obj, depth + 1); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf("IndexField\n"); break; case ACPI_TYPE_BUFFER_FIELD: acpi_os_printf("BufferField: %X bits at byte %X bit %X of\n", obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, obj_desc->buffer_field.start_field_bit_offset); if (!obj_desc->buffer_field.buffer_obj) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "*NULL*\n")); } else if (ACPI_GET_OBJECT_TYPE(obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) { acpi_os_printf("*not a Buffer*\n"); } else { acpi_ex_dump_operand(obj_desc->buffer_field.buffer_obj, depth + 1); } break; case ACPI_TYPE_EVENT: acpi_os_printf("Event\n"); break; case ACPI_TYPE_METHOD: acpi_os_printf("Method(%X) @ %p:%X\n", obj_desc->method.param_count, obj_desc->method.aml_start, obj_desc->method.aml_length); break; case ACPI_TYPE_MUTEX: acpi_os_printf("Mutex\n"); break; case ACPI_TYPE_DEVICE: acpi_os_printf("Device\n"); break; case ACPI_TYPE_POWER: acpi_os_printf("Power\n"); break; case ACPI_TYPE_PROCESSOR: acpi_os_printf("Processor\n"); break; case ACPI_TYPE_THERMAL: acpi_os_printf("Thermal\n"); break; default: /* Unknown Type */ acpi_os_printf("Unknown Type %X\n", ACPI_GET_OBJECT_TYPE(obj_desc)); break; } return; }
static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value) { union acpi_operand_object *handler_obj; union acpi_operand_object *next_handler_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_NAME(ev_install_handler); handler_obj = (union acpi_operand_object *)context; /* Parameter validation */ if (!handler_obj) { return (AE_OK); } /* Convert and validate the device handle */ node = acpi_ns_map_handle_to_node(obj_handle); if (!node) { return (AE_BAD_PARAMETER); } /* * We only care about regions.and objects * that are allowed to have address space handlers */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { return (AE_OK); } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* No object, just exit */ return (AE_OK); } /* Devices are handled different than regions */ if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_DEVICE) { /* Check if this Device already has a handler for this address space */ next_handler_obj = obj_desc->device.handler; while (next_handler_obj) { /* Found a handler, is it for the same address space? */ if (next_handler_obj->address_space.space_id == handler_obj->address_space.space_id) { ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler for region [%s] in device %p(%p) handler %p\n", acpi_ut_get_region_name (handler_obj->address_space. space_id), obj_desc, next_handler_obj, handler_obj)); /* * Since the object we found it on was a device, then it * means that someone has already installed a handler for * the branch of the namespace from this device on. Just * bail out telling the walk routine to not traverse this * branch. This preserves the scoping rule for handlers. */ return (AE_CTRL_DEPTH); } /* Walk the linked list of handlers attached to this device */ next_handler_obj = next_handler_obj->address_space.next; } /* * As long as the device didn't have a handler for this * space we don't care about it. We just ignore it and * proceed. */ return (AE_OK); } /* Object is a Region */ if (obj_desc->region.space_id != handler_obj->address_space.space_id) { /* * This region is for a different address space * -- just ignore it */ return (AE_OK); } /* * Now we have a region and it is for the handler's address * space type. * * First disconnect region for any previous handler (if any) */ acpi_ev_detach_region(obj_desc, FALSE); /* Connect the region to the new handler */ status = acpi_ev_attach_region(handler_obj, obj_desc, FALSE); return (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); }
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 **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.address_space; 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; 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, 0); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region _REG, [%s]\n", acpi_format_exception (status), 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; } } /* Call the setup handler with the deactivate notification */ region_setup = handler_obj->address_space.setup; status = region_setup (region_obj, ACPI_REGION_DEACTIVATE, handler_obj->address_space.context, region_context); /* Init routine may fail, Just ignore errors */ if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region init, [%s]\n", acpi_format_exception (status), 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 better be the region's handler */ region_obj->region.address_space = 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; } /* 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; }
acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, u32 function, acpi_physical_address address, u32 bit_width, acpi_integer * value) { acpi_status status; acpi_status status2; acpi_adr_space_handler handler; acpi_adr_space_setup region_setup; union acpi_operand_object *handler_desc; union acpi_operand_object *region_obj2; void *region_context = NULL; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } /* Ensure that there is a handler associated with this region */ handler_desc = region_obj->region.handler; if (!handler_desc) { ACPI_ERROR((AE_INFO, "No handler for Region [%4.4s] (%p) [%s]", acpi_ut_get_node_name(region_obj->region.node), region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); return_ACPI_STATUS(AE_NOT_EXIST); } /* * It may be the case that the region has never been initialized * Some types of regions require special init code */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { /* * This region has not been initialized yet, do it */ region_setup = handler_desc->address_space.setup; if (!region_setup) { /* No initialization routine, exit with error */ ACPI_ERROR((AE_INFO, "No init routine for region(%p) [%s]", region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); return_ACPI_STATUS(AE_NOT_EXIST); } /* * We must exit the interpreter because the region * setup will potentially execute control methods * (e.g., _REG method for this region) */ acpi_ex_exit_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, handler_desc->address_space.context, ®ion_context); /* Re-enter the interpreter */ status2 = acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status2)) { return_ACPI_STATUS(status2); } /* Check for failure of the Region Setup */ if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During region initialization: [%s]", acpi_ut_get_region_name(region_obj-> region. space_id))); return_ACPI_STATUS(status); } /* * Region initialization may have been completed by region_setup */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; if (region_obj2->extra.region_context) { /* The handler for this region was already installed */ ACPI_FREE(region_context); } else { /* * Save the returned context for use in all accesses to * this particular region */ region_obj2->extra.region_context = region_context; } } } /* We have everything we need, we can invoke the address space handler */ handler = handler_desc->address_space.handler; ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", ®ion_obj->region.handler->address_space, handler, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(region_obj->region. space_id))); if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * For handlers other than the default (supplied) handlers, we must * exit the interpreter because the handler *might* block -- we don't * know what it will do, so we can't hold the lock on the intepreter. */ acpi_ex_exit_interpreter(); } /* Call the handler */ status = handler(function, address, bit_width, value, handler_desc->address_space.context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]", acpi_ut_get_region_name(region_obj->region. space_id))); } if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* * We just returned from a non-default handler, we must re-enter the * interpreter */ status2 = acpi_ex_enter_interpreter(); if (ACPI_FAILURE(status2)) { return_ACPI_STATUS(status2); } } 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; }
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj, u8 acpi_ns_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { return_ACPI_STATUS(AE_OK); } acpi_ev_associate_reg_method(region_obj); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; node = region_obj->region.node->parent; space_id = region_obj->region.space_id; /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->Parent being set to NULL */ while (node) { /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_THERMAL: handler_obj = obj_desc->common_notify.handler; break; case ACPI_TYPE_METHOD: /* * If we are executing module level code, the original * Node's object was replaced by this Method object and we * saved the handler in the method object. * * See acpi_ns_exec_module_code */ if (obj_desc->method. info_flags & ACPI_METHOD_MODULE_LEVEL) { handler_obj = obj_desc->method.dispatch.handler; } break; default: /* Ignore other objects */ break; } handler_obj = acpi_ev_find_region_handler(space_id, handler_obj); if (handler_obj) { /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler %p for region %p in obj %p\n", handler_obj, region_obj, obj_desc)); status = acpi_ev_attach_region(handler_obj, region_obj, acpi_ns_locked); /* * Tell all users that this region is usable by * running the _REG method */ if (acpi_ns_locked) { status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } status = acpi_ev_execute_reg_method(region_obj, ACPI_REG_CONNECT); if (acpi_ns_locked) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } } return_ACPI_STATUS(AE_OK); } } /* This node does not have the handler we need; Pop up one level */ node = node->parent; } /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); }
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u32 new_value32, old_value32; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* Convert access_width into number of bits based */ access_width = acpi_hw_get_access_bit_width(reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { /* * Use offset style bit reads because "Index * AccessWidth" is * ensured to be less than 32-bits by acpi_hw_validate_register(). */ new_value32 = ACPI_GET_BITS(&value, index * access_width, ACPI_MASK_BITS_ABOVE_32 (access_width)); if (bit_offset >= access_width) { bit_offset -= access_width; } else { /* * Use offset style bit masks because access_width is ensured * to be less than 32-bits by acpi_hw_validate_register() and * bit_offset/bit_width is less than access_width here. */ if (bit_offset) { new_value32 &= ACPI_MASK_BITS_BELOW(bit_offset); } if (bit_width < access_width) { new_value32 &= ACPI_MASK_BITS_ABOVE(bit_width); } if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { if (bit_offset || bit_width < access_width) { /* * Read old values in order not to modify the bits that * are beyond the register bit_width/bit_offset setting. */ status = acpi_os_read_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), &value64, access_width); old_value32 = (u32)value64; /* * Use offset style bit masks because access_width is * ensured to be less than 32-bits by * acpi_hw_validate_register() and bit_offset/bit_width is * less than access_width here. */ if (bit_offset) { old_value32 &= ACPI_MASK_BITS_ABOVE (bit_offset); bit_offset = 0; } if (bit_width < access_width) { old_value32 &= ACPI_MASK_BITS_BELOW (bit_width); } new_value32 |= old_value32; } value64 = (u64)new_value32; status = acpi_os_write_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), value64, access_width); } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ if (bit_offset || bit_width < access_width) { /* * Read old values in order not to modify the bits that * are beyond the register bit_width/bit_offset setting. */ status = acpi_hw_read_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), &old_value32, access_width); /* * Use offset style bit masks because access_width is * ensured to be less than 32-bits by * acpi_hw_validate_register() and bit_offset/bit_width is * less than access_width here. */ if (bit_offset) { old_value32 &= ACPI_MASK_BITS_ABOVE (bit_offset); bit_offset = 0; } if (bit_width < access_width) { old_value32 &= ACPI_MASK_BITS_BELOW (bit_width); } new_value32 |= old_value32; } status = acpi_hw_write_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), new_value32, access_width); } } /* * Index * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
acpi_status acpi_ns_dump_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { struct acpi_walk_info *info = (struct acpi_walk_info *)context; struct acpi_namespace_node *this_node; union acpi_operand_object *obj_desc = NULL; acpi_object_type obj_type; acpi_object_type type; u32 bytes_to_dump; u32 dbg_level; u32 i; ACPI_FUNCTION_NAME(ns_dump_one_object); if (!(acpi_dbg_level & info->debug_level)) { return (AE_OK); } if (!obj_handle) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null object handle\n")); return (AE_OK); } this_node = acpi_ns_validate_handle(obj_handle); if (!this_node) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", obj_handle)); return (AE_OK); } type = this_node->type; if ((info->owner_id != ACPI_OWNER_ID_MAX) && (info->owner_id != this_node->owner_id)) { return (AE_OK); } if (!(info->display_type & ACPI_DISPLAY_SHORT)) { acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " "); if (type > ACPI_TYPE_LOCAL_MAX) { ACPI_WARNING((AE_INFO, "Invalid ACPI Object Type 0x%08X", type)); } if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { this_node->name.integer = acpi_ut_repair_name(this_node->name.ascii); ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); } acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); } acpi_os_printf(" %-12s %p %2.2X ", acpi_ut_get_type_name(type), this_node, this_node->owner_id); dbg_level = acpi_dbg_level; acpi_dbg_level = 0; obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; if (this_node->flags & ANOBJ_TEMPORARY) { acpi_os_printf("(T) "); } switch (info->display_type & ACPI_DISPLAY_MASK) { case ACPI_DISPLAY_SUMMARY: if (!obj_desc) { switch (type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_PACKAGE: case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: case ACPI_TYPE_METHOD: acpi_os_printf("<No attached object>"); break; default: break; } acpi_os_printf("\n"); return (AE_OK); } switch (type) { case ACPI_TYPE_PROCESSOR: acpi_os_printf("ID %X Len %.4X Addr %p\n", obj_desc->processor.proc_id, obj_desc->processor.length, ACPI_CAST_PTR(void, obj_desc->processor. address)); break; case ACPI_TYPE_DEVICE: acpi_os_printf("Notify Object: %p\n", obj_desc); break; case ACPI_TYPE_METHOD: acpi_os_printf("Args %X Len %.4X Aml %p\n", (u32) obj_desc->method.param_count, obj_desc->method.aml_length, obj_desc->method.aml_start); break; case ACPI_TYPE_INTEGER: acpi_os_printf("= %8.8X%8.8X\n", ACPI_FORMAT_UINT64(obj_desc->integer. value)); break; case ACPI_TYPE_PACKAGE: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Elements %.2X\n", obj_desc->package.count); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_BUFFER: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Len %.2X", obj_desc->buffer.length); if (obj_desc->buffer.length > 0) { acpi_os_printf(" ="); for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { acpi_os_printf(" %.2hX", obj_desc->buffer. pointer[i]); } } acpi_os_printf("\n"); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_STRING: acpi_os_printf("Len %.2X ", obj_desc->string.length); acpi_ut_print_string(obj_desc->string.pointer, 32); acpi_os_printf("\n"); break; case ACPI_TYPE_REGION: acpi_os_printf("[%s]", acpi_ut_get_region_name(obj_desc->region. space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", ACPI_FORMAT_NATIVE_UINT (obj_desc->region.address), obj_desc->region.length); } else { acpi_os_printf (" [Address/Length not yet evaluated]\n"); } break; case ACPI_TYPE_LOCAL_REFERENCE: acpi_os_printf("[%s]\n", acpi_ut_get_reference_name(obj_desc)); break; case ACPI_TYPE_BUFFER_FIELD: if (obj_desc->buffer_field.buffer_obj && obj_desc->buffer_field.buffer_obj->buffer.node) { acpi_os_printf("Buf [%4.4s]", acpi_ut_get_node_name(obj_desc-> buffer_field. buffer_obj-> buffer. node)); } break; case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf("Rgn [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: acpi_os_printf("Rgn [%4.4s] Bnk [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node), acpi_ut_get_node_name(obj_desc-> bank_field. bank_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf("Idx [%4.4s] Dat [%4.4s]", acpi_ut_get_node_name(obj_desc-> index_field. index_obj-> common_field.node), acpi_ut_get_node_name(obj_desc-> index_field. data_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_ALIAS: case ACPI_TYPE_LOCAL_METHOD_ALIAS: acpi_os_printf("Target %4.4s (%p)\n", acpi_ut_get_node_name(obj_desc), obj_desc); break; default: acpi_os_printf("Object %p\n", obj_desc); break; } switch (type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf(" Off %.3X Len %.2X Acc %.2hd\n", (obj_desc->common_field. base_byte_offset * 8) + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field.bit_length, obj_desc->common_field. access_byte_width); break; default: break; } break; case ACPI_DISPLAY_OBJECTS: acpi_os_printf("O:%p", obj_desc); if (!obj_desc) { acpi_os_printf("\n"); return (AE_OK); } acpi_os_printf("(R%u)", obj_desc->common.reference_count); switch (type) { case ACPI_TYPE_METHOD: acpi_os_printf(" M:%p-%X\n", obj_desc->method.aml_start, obj_desc->method.aml_length); break; case ACPI_TYPE_INTEGER: acpi_os_printf(" I:%8.8X8.8%X\n", ACPI_FORMAT_UINT64(obj_desc->integer. value)); break; case ACPI_TYPE_STRING: acpi_os_printf(" S:%p-%X\n", obj_desc->string.pointer, obj_desc->string.length); break; case ACPI_TYPE_BUFFER: acpi_os_printf(" B:%p-%X\n", obj_desc->buffer.pointer, obj_desc->buffer.length); break; default: acpi_os_printf("\n"); break; } break; default: acpi_os_printf("\n"); break; } if (!(acpi_dbg_level & ACPI_LV_VALUES)) { return (AE_OK); } dbg_level = acpi_dbg_level; acpi_dbg_level = 0; obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; while (obj_desc) { obj_type = ACPI_TYPE_INVALID; acpi_os_printf("Attached Object %p: ", obj_desc); switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { case ACPI_DESC_TYPE_NAMED: acpi_os_printf("(Ptr to Node)\n"); bytes_to_dump = sizeof(struct acpi_namespace_node); ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); break; case ACPI_DESC_TYPE_OPERAND: obj_type = obj_desc->common.type; if (obj_type > ACPI_TYPE_LOCAL_MAX) { acpi_os_printf ("(Pointer to ACPI Object type %.2X [UNKNOWN])\n", obj_type); bytes_to_dump = 32; } else { acpi_os_printf ("(Pointer to ACPI Object type %.2X [%s])\n", obj_type, acpi_ut_get_type_name(obj_type)); bytes_to_dump = sizeof(union acpi_operand_object); } ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); break; default: break; } if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { goto cleanup; } switch (obj_type) { case ACPI_TYPE_BUFFER: case ACPI_TYPE_STRING: bytes_to_dump = obj_desc->string.length; obj_desc = (void *)obj_desc->string.pointer; acpi_os_printf("(Buffer/String pointer %p length %X)\n", obj_desc, bytes_to_dump); ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); goto cleanup; case ACPI_TYPE_BUFFER_FIELD: obj_desc = (union acpi_operand_object *)obj_desc->buffer_field. buffer_obj; break; case ACPI_TYPE_PACKAGE: obj_desc = (void *)obj_desc->package.elements; break; case ACPI_TYPE_METHOD: obj_desc = (void *)obj_desc->method.aml_start; break; case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc = (void *)obj_desc->field.region_obj; break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc = (void *)obj_desc->bank_field.region_obj; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: obj_desc = (void *)obj_desc->index_field.index_obj; break; default: goto cleanup; } obj_type = ACPI_TYPE_INVALID; } cleanup: acpi_os_printf("\n"); return (AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_remove_address_space_handler * * PARAMETERS: device - Handle for the device * space_id - The address space ID * handler - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a previously installed handler. * ******************************************************************************/ acpi_status acpi_remove_address_space_handler(acpi_handle device, acpi_adr_space_type space_id, acpi_adr_space_handler handler) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; union acpi_operand_object *region_obj; union acpi_operand_object **last_obj_ptr; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler); /* Parameter validation */ if (!device) { 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 || ((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; } /* Make sure the internal object exists */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Find the address handler the user requested */ handler_obj = obj_desc->device.handler; last_obj_ptr = &obj_desc->device.handler; while (handler_obj) { /* We have a handler, see if user requested this one */ if (handler_obj->address_space.space_id == space_id) { /* Handler must be the same as the installed handler */ if (handler_obj->address_space.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Matched space_id, first dereference this in the Regions */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Removing address handler %p(%p) for region %s " "on Device %p(%p)\n", handler_obj, handler, acpi_ut_get_region_name(space_id), node, obj_desc)); region_obj = handler_obj->address_space.region_list; /* Walk the handler's region list */ while (region_obj) { /* * First disassociate the handler from the region. * * NOTE: this doesn't mean that the region goes away * The region is just inaccessible as indicated to * the _REG method */ acpi_ev_detach_region(region_obj, TRUE); /* * Walk the list: Just grab the head because the * detach_region removed the previous head. */ region_obj = handler_obj->address_space.region_list; } /* Remove this Handler object from the list */ *last_obj_ptr = handler_obj->address_space.next; /* Now we can delete the handler object */ acpi_ut_remove_reference(handler_obj); goto unlock_and_exit; } /* Walk the linked list of handlers */ last_obj_ptr = &handler_obj->address_space.next; handler_obj = handler_obj->address_space.next; } /* The handler does not exist */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n", handler, acpi_ut_get_region_name(space_id), space_id, node, obj_desc)); status = AE_NOT_EXIST; unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
acpi_status acpi_hw_write(u64 value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 64, &address); if (ACPI_FAILURE(status)) { return (status); } /* Convert access_width into number of bits based */ access_width = acpi_hw_get_access_bit_width(address, reg, 64); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { /* * Use offset style bit reads because "Index * AccessWidth" is * ensured to be less than 64-bits by acpi_hw_validate_register(). */ value64 = ACPI_GET_BITS(&value, index * access_width, ACPI_MASK_BITS_ABOVE_64(access_width)); if (bit_offset >= access_width) { bit_offset -= access_width; } else { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_write_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), value64, access_width); } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_write_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), (u32)value64, access_width); } } /* * Index * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", ACPI_FORMAT_UINT64(value), access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
void acpi_db_display_handlers(void) { union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; acpi_adr_space_type space_id; u32 i; /* Operation region handlers */ acpi_os_printf("\nOperation Region Handlers at the namespace root:\n"); obj_desc = acpi_ns_get_attached_object(acpi_gbl_root_node); if (obj_desc) { for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_space_id_list); i++) { space_id = acpi_gbl_space_id_list[i]; acpi_os_printf(ACPI_PREDEFINED_PREFIX, acpi_ut_get_region_name((u8)space_id), space_id); handler_obj = acpi_ev_find_region_handler(space_id, obj_desc->common_notify. handler); if (handler_obj) { acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, (handler_obj->address_space. handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default" : "User", handler_obj->address_space. handler); goto found_handler; } /* There is no handler for this space_id */ acpi_os_printf("None\n"); found_handler: ; } /* Find all handlers for user-defined space_IDs */ handler_obj = obj_desc->common_notify.handler; while (handler_obj) { if (handler_obj->address_space.space_id >= ACPI_USER_REGION_BEGIN) { acpi_os_printf(ACPI_PREDEFINED_PREFIX, "User-defined ID", handler_obj->address_space. space_id); acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, (handler_obj->address_space. handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) ? "Default" : "User", handler_obj->address_space. handler); } handler_obj = handler_obj->address_space.next; } } #if (!ACPI_REDUCED_HARDWARE) /* Fixed event handlers */ acpi_os_printf("\nFixed Event Handlers:\n"); for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_os_printf(ACPI_PREDEFINED_PREFIX, acpi_ut_get_event_name(i), i); if (acpi_gbl_fixed_event_handlers[i].handler) { acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User", acpi_gbl_fixed_event_handlers[i]. handler); } else { acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None"); } } #endif /* !ACPI_REDUCED_HARDWARE */ /* Miscellaneous global handlers */ acpi_os_printf("\nMiscellaneous Global Handlers:\n"); for (i = 0; i < ACPI_ARRAY_LENGTH(acpi_gbl_handler_list); i++) { acpi_os_printf(ACPI_HANDLER_NAME_STRING, acpi_gbl_handler_list[i].name); if (acpi_gbl_handler_list[i].handler) { acpi_os_printf(ACPI_HANDLER_PRESENT_STRING, "User", acpi_gbl_handler_list[i].handler); } else { acpi_os_printf(ACPI_HANDLER_NOT_PRESENT_STRING, "None"); } } /* Other handlers that are installed throughout the namespace */ acpi_os_printf("\nOperation Region Handlers for specific devices:\n"); (void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, acpi_db_display_non_root_handlers, NULL, NULL, NULL); }
static acpi_status acpi_db_test_one_object(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_namespace_node *node; union acpi_operand_object *obj_desc; union acpi_operand_object *region_obj; acpi_object_type local_type; u32 bit_length = 0; u32 byte_length = 0; acpi_status status = AE_OK; node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); obj_desc = node->object; /* * For the supported types, get the actual bit length or * byte length. Map the type to one of Integer/String/Buffer. */ switch (node->type) { case ACPI_TYPE_INTEGER: /* Integer width is either 32 or 64 */ local_type = ACPI_TYPE_INTEGER; bit_length = acpi_gbl_integer_bit_width; break; case ACPI_TYPE_STRING: local_type = ACPI_TYPE_STRING; byte_length = obj_desc->string.length; break; case ACPI_TYPE_BUFFER: local_type = ACPI_TYPE_BUFFER; byte_length = obj_desc->buffer.length; bit_length = byte_length * 8; break; case ACPI_TYPE_FIELD_UNIT: case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: local_type = ACPI_TYPE_INTEGER; if (obj_desc) { /* * Returned object will be a Buffer if the field length * is larger than the size of an Integer (32 or 64 bits * depending on the DSDT version). */ bit_length = obj_desc->common_field.bit_length; byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length); if (bit_length > acpi_gbl_integer_bit_width) { local_type = ACPI_TYPE_BUFFER; } } break; default: /* Ignore all other types */ return (AE_OK); } /* Emit the common prefix: Type:Name */ acpi_os_printf("%14s: %4.4s", acpi_ut_get_type_name(node->type), node->name.ascii); if (!obj_desc) { acpi_os_printf(" Ignoring, no attached object\n"); return (AE_OK); } /* * Check for unsupported region types. Note: acpi_exec simulates * access to system_memory, system_IO, PCI_Config, and EC. */ switch (node->type) { case ACPI_TYPE_LOCAL_REGION_FIELD: region_obj = obj_desc->field.region_obj; switch (region_obj->region.space_id) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: case ACPI_ADR_SPACE_PCI_CONFIG: case ACPI_ADR_SPACE_EC: break; default: acpi_os_printf (" %s space is not supported [%4.4s]\n", acpi_ut_get_region_name(region_obj->region. space_id), region_obj->region.node->name.ascii); return (AE_OK); } break; default: break; } /* At this point, we have resolved the object to one of the major types */ switch (local_type) { case ACPI_TYPE_INTEGER: status = acpi_db_test_integer_type(node, bit_length); break; case ACPI_TYPE_STRING: status = acpi_db_test_string_type(node, byte_length); break; case ACPI_TYPE_BUFFER: status = acpi_db_test_buffer_type(node, bit_length); break; default: acpi_os_printf(" Ignoring, type not implemented (%2.2X)", local_type); break; } switch (node->type) { case ACPI_TYPE_LOCAL_REGION_FIELD: region_obj = obj_desc->field.region_obj; acpi_os_printf(" (%s)", acpi_ut_get_region_name(region_obj->region. space_id)); break; default: break; } acpi_os_printf("\n"); return (status); }
acpi_status acpi_ns_dump_one_object(acpi_handle obj_handle, u32 level, void *context, void **return_value) { struct acpi_walk_info *info = (struct acpi_walk_info *)context; struct acpi_namespace_node *this_node; union acpi_operand_object *obj_desc = NULL; acpi_object_type obj_type; acpi_object_type type; u32 bytes_to_dump; u32 dbg_level; u32 i; ACPI_FUNCTION_NAME(ns_dump_one_object); /* Is output enabled? */ if (!(acpi_dbg_level & info->debug_level)) { return (AE_OK); } if (!obj_handle) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null object handle\n")); return (AE_OK); } this_node = acpi_ns_validate_handle(obj_handle); if (!this_node) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", obj_handle)); return (AE_OK); } type = this_node->type; /* Check if the owner matches */ if ((info->owner_id != ACPI_OWNER_ID_MAX) && (info->owner_id != this_node->owner_id)) { return (AE_OK); } if (!(info->display_type & ACPI_DISPLAY_SHORT)) { /* Indent the object according to the level */ acpi_os_printf("%2d%*s", (u32) level - 1, (int)level * 2, " "); /* Check the node type and name */ if (type > ACPI_TYPE_LOCAL_MAX) { ACPI_WARNING((AE_INFO, "Invalid ACPI Object Type 0x%08X", type)); } if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { this_node->name.integer = acpi_ut_repair_name(this_node->name.ascii); ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", this_node->name.integer)); } acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); } /* Now we can print out the pertinent information */ acpi_os_printf(" %-12s %p %2.2X ", acpi_ut_get_type_name(type), this_node, this_node->owner_id); dbg_level = acpi_dbg_level; acpi_dbg_level = 0; obj_desc = acpi_ns_get_attached_object(this_node); acpi_dbg_level = dbg_level; /* Temp nodes are those nodes created by a control method */ if (this_node->flags & ANOBJ_TEMPORARY) { acpi_os_printf("(T) "); } switch (info->display_type & ACPI_DISPLAY_MASK) { case ACPI_DISPLAY_SUMMARY: if (!obj_desc) { /* No attached object, we are done */ acpi_os_printf("\n"); return (AE_OK); } switch (type) { case ACPI_TYPE_PROCESSOR: acpi_os_printf("ID %X Len %.4X Addr %p\n", obj_desc->processor.proc_id, obj_desc->processor.length, ACPI_CAST_PTR(void, obj_desc->processor. address)); break; case ACPI_TYPE_DEVICE: acpi_os_printf("Notify Object: %p\n", obj_desc); break; case ACPI_TYPE_METHOD: acpi_os_printf("Args %X Len %.4X Aml %p\n", (u32) obj_desc->method.param_count, obj_desc->method.aml_length, obj_desc->method.aml_start); break; case ACPI_TYPE_INTEGER: acpi_os_printf("= %8.8X%8.8X\n", ACPI_FORMAT_UINT64(obj_desc->integer. value)); break; case ACPI_TYPE_PACKAGE: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Elements %.2X\n", obj_desc->package.count); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_BUFFER: if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { acpi_os_printf("Len %.2X", obj_desc->buffer.length); /* Dump some of the buffer */ if (obj_desc->buffer.length > 0) { acpi_os_printf(" ="); for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { acpi_os_printf(" %.2hX", obj_desc->buffer. pointer[i]); } } acpi_os_printf("\n"); } else { acpi_os_printf("[Length not yet evaluated]\n"); } break; case ACPI_TYPE_STRING: acpi_os_printf("Len %.2X ", obj_desc->string.length); acpi_ut_print_string(obj_desc->string.pointer, 32); acpi_os_printf("\n"); break; case ACPI_TYPE_REGION: acpi_os_printf("[%s]", acpi_ut_get_region_name(obj_desc->region. space_id)); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n", ACPI_FORMAT_NATIVE_UINT (obj_desc->region.address), obj_desc->region.length); } else { acpi_os_printf (" [Address/Length not yet evaluated]\n"); } break; case ACPI_TYPE_LOCAL_REFERENCE: acpi_os_printf("[%s]\n", acpi_ut_get_reference_name(obj_desc)); break; case ACPI_TYPE_BUFFER_FIELD: if (obj_desc->buffer_field.buffer_obj && obj_desc->buffer_field.buffer_obj->buffer.node) { acpi_os_printf("Buf [%4.4s]", acpi_ut_get_node_name(obj_desc-> buffer_field. buffer_obj-> buffer. node)); } break; case ACPI_TYPE_LOCAL_REGION_FIELD: acpi_os_printf("Rgn [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: acpi_os_printf("Rgn [%4.4s] Bnk [%4.4s]", acpi_ut_get_node_name(obj_desc-> common_field. region_obj->region. node), acpi_ut_get_node_name(obj_desc-> bank_field. bank_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf("Idx [%4.4s] Dat [%4.4s]", acpi_ut_get_node_name(obj_desc-> index_field. index_obj-> common_field.node), acpi_ut_get_node_name(obj_desc-> index_field. data_obj-> common_field. node)); break; case ACPI_TYPE_LOCAL_ALIAS: case ACPI_TYPE_LOCAL_METHOD_ALIAS: acpi_os_printf("Target %4.4s (%p)\n", acpi_ut_get_node_name(obj_desc), obj_desc); break; default: acpi_os_printf("Object %p\n", obj_desc); break; } /* Common field handling */ switch (type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: acpi_os_printf(" Off %.3X Len %.2X Acc %.2hd\n", (obj_desc->common_field. base_byte_offset * 8) + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field.bit_length, obj_desc->common_field. access_byte_width); break; default: break; } break; case ACPI_DISPLAY_OBJECTS: acpi_os_printf("O:%p", obj_desc); if (!obj_desc) { /* No attached object, we are done */ acpi_os_printf("\n"); return (AE_OK); } <<<<<<< HEAD acpi_os_printf("(R%u)", obj_desc->common.reference_count); =======