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_ns_load_table(acpi_native_uint table_index, struct acpi_namespace_node *node) { acpi_status status; ACPI_FUNCTION_TRACE(ns_load_table); /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed * at this time. In fact, the control methods cannot be * parsed until the entire namespace is loaded, because * if a control method makes a forward reference (call) * to another control method, we can't continue parsing * because we don't know how many arguments to parse next! */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* If table already loaded into namespace, just return */ if (acpi_tb_is_table_loaded(table_index)) { status = AE_ALREADY_EXISTS; goto unlock; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Loading table into namespace ****\n")); status = acpi_tb_allocate_owner_id(table_index); if (ACPI_FAILURE(status)) { goto unlock; } status = acpi_ns_parse_table(table_index, node->child); if (ACPI_SUCCESS(status)) { acpi_tb_set_table_loaded_flag(table_index, TRUE); } else { acpi_tb_release_owner_id(table_index); } unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Now we can parse the control methods. We always parse * them here for a sanity check, and if configured for * just-in-time parsing, we delete the control method * parse trees. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Begin Table Method Parsing and Object Initialization ****\n")); status = acpi_ds_initialize_objects(table_index, node); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Method Parsing and Object Initialization ****\n")); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_tb_load_namespace * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in * the RSDT/XSDT. * ******************************************************************************/ static acpi_status acpi_tb_load_namespace(void) { acpi_status status; struct acpi_table_header *table; acpi_native_uint i; ACPI_FUNCTION_TRACE(tb_load_namespace); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* * Load the namespace. The DSDT is required, but any SSDT and PSDT tables * are optional. */ if (!acpi_gbl_root_table_list.count || !ACPI_COMPARE_NAME(& (acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT].signature), ACPI_SIG_DSDT) || ACPI_FAILURE(acpi_tb_verify_table (&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT]))) { status = AE_NO_ACPI_TABLES; goto unlock_and_exit; } /* * Find DSDT table */ status = acpi_os_table_override(acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT].pointer, &table); if (ACPI_SUCCESS(status) && table) { /* * DSDT table has been found */ acpi_tb_delete_table(&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT]); acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer = table; acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length = table->length; acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags = ACPI_TABLE_ORIGIN_UNKNOWN; ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS")); acpi_tb_print_table_header(0, table); } status = acpi_tb_verify_table(&acpi_gbl_root_table_list. tables[ACPI_TABLE_INDEX_DSDT]); if (ACPI_FAILURE(status)) { /* A valid DSDT is required */ status = AE_NO_ACPI_TABLES; goto unlock_and_exit; } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); /* * Load and parse tables. */ status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if ((!ACPI_COMPARE_NAME (&(acpi_gbl_root_table_list.tables[i].signature), ACPI_SIG_SSDT) && !ACPI_COMPARE_NAME(& (acpi_gbl_root_table_list.tables[i]. signature), ACPI_SIG_PSDT)) || ACPI_FAILURE(acpi_tb_verify_table (&acpi_gbl_root_table_list.tables[i]))) { continue; } /* Ignore errors while loading tables, get as many as possible */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ns_load_table(i, acpi_gbl_root_node); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); } ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n")); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_unload_parent_table * * PARAMETERS: object - Handle to any namespace object owned by * the table to be unloaded * * RETURN: Status * * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads * the table and deletes all namespace objects associated with * that table. Unloading of the DSDT is not allowed. * Note: Mainly intended to support hotplug removal of SSDTs. * ******************************************************************************/ acpi_status acpi_unload_parent_table(acpi_handle object) { struct acpi_namespace_node *node = ACPI_CAST_PTR(struct acpi_namespace_node, object); acpi_status status = AE_NOT_EXIST; acpi_owner_id owner_id; u32 i; ACPI_FUNCTION_TRACE(acpi_unload_parent_table); /* Parameter validation */ if (!object) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* * The node owner_id is currently the same as the parent table ID. * However, this could change in the future. */ owner_id = node->owner_id; if (!owner_id) { /* owner_id==0 means DSDT is the owner. DSDT cannot be unloaded */ return_ACPI_STATUS(AE_TYPE); } /* Must acquire the table lock during this operation */ status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Find the table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { if (owner_id != acpi_gbl_root_table_list.tables[i].owner_id) { continue; } /* * Allow unload of SSDT and OEMx tables only. Do not allow unload * of the DSDT. No other types of tables should get here, since * only these types can contain AML and thus are the only types * that can create namespace objects. */ if (ACPI_COMPARE_NAME (acpi_gbl_root_table_list.tables[i].signature.ascii, ACPI_SIG_DSDT)) { status = AE_TYPE; break; } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); status = acpi_tb_unload_table(i); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); break; } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u32 flags, acpi_walk_callback pre_order_visit, acpi_walk_callback post_order_visit, void *context, void **return_value) { acpi_status status; acpi_status mutex_status; struct acpi_namespace_node *child_node; struct acpi_namespace_node *parent_node; acpi_object_type child_type; u32 level; u8 node_previously_visited = FALSE; ACPI_FUNCTION_TRACE(ns_walk_namespace); /* Special case for the namespace Root Node */ if (start_node == ACPI_ROOT_OBJECT) { start_node = acpi_gbl_root_node; } /* Null child means "get first node" */ parent_node = start_node; child_node = acpi_ns_get_next_node(parent_node, NULL); child_type = ACPI_TYPE_ANY; level = 1; /* * Traverse the tree of nodes until we bubble back up to where we * started. When Level is zero, the loop is done because we have * bubbled up to (and passed) the original parent handle (start_entry) */ while (level > 0 && child_node) { status = AE_OK; /* Found next child, get the type if we are not searching for ANY */ if (type != ACPI_TYPE_ANY) { child_type = child_node->type; } /* * Ignore all temporary namespace nodes (created during control * method execution) unless told otherwise. These temporary nodes * can cause a race condition because they can be deleted during * the execution of the user function (if the namespace is * unlocked before invocation of the user function.) Only the * debugger namespace dump will examine the temporary nodes. */ if ((child_node->flags & ANOBJ_TEMPORARY) && !(flags & ACPI_NS_WALK_TEMP_NODES)) { status = AE_CTRL_DEPTH; } /* Type must match requested type */ else if (child_type == type) { /* * Found a matching node, invoke the user callback function. * Unlock the namespace if flag is set. */ if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(mutex_status)) { return_ACPI_STATUS(mutex_status); } } /* * Invoke the user function, either pre-order or post-order * or both. */ if (!node_previously_visited) { if (pre_order_visit) { status = pre_order_visit(child_node, level, context, return_value); } } else { if (post_order_visit) { status = post_order_visit(child_node, level, context, return_value); } } if (flags & ACPI_NS_WALK_UNLOCK) { mutex_status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(mutex_status)) { return_ACPI_STATUS(mutex_status); } } switch (status) { case AE_OK: case AE_CTRL_DEPTH: /* Just keep going */ break; case AE_CTRL_TERMINATE: /* Exit now, with OK status */ return_ACPI_STATUS(AE_OK); default: /* All others are valid exceptions */ return_ACPI_STATUS(status); } } /* * Depth first search: Attempt to go down another level in the * namespace if we are allowed to. Don't go any further if we have * reached the caller specified maximum depth or if the user * function has specified that the maximum depth has been reached. */ if (!node_previously_visited && (level < max_depth) && (status != AE_CTRL_DEPTH)) { if (child_node->child) { /* There is at least one child of this node, visit it */ level++; parent_node = child_node; child_node = acpi_ns_get_next_node(parent_node, NULL); continue; } } /* No more children, re-visit this node */ if (!node_previously_visited) { node_previously_visited = TRUE; continue; } /* No more children, visit peers */ child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { node_previously_visited = FALSE; } /* No peers, re-visit parent */ else { /* * No more children of this node (acpi_ns_get_next_node failed), go * back upwards in the namespace tree to the node's parent. */ level--; child_node = parent_node; parent_node = parent_node->parent; node_previously_visited = TRUE; } } /* Complete walk, not terminated by user function */ return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ns_get_node(struct acpi_namespace_node *prefix_node, const char *pathname, u32 flags, struct acpi_namespace_node **return_node) { union acpi_generic_state scope_info; acpi_status status; char *internal_path; ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname)); /* Simplest case is a null pathname */ if (!pathname) { *return_node = prefix_node; if (!prefix_node) { *return_node = acpi_gbl_root_node; } return_ACPI_STATUS(AE_OK); } /* Quick check for a reference to the root */ if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) { *return_node = acpi_gbl_root_node; return_ACPI_STATUS(AE_OK); } /* Convert path to internal representation */ status = acpi_ns_internalize_name(pathname, &internal_path); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Must lock namespace during lookup */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; } /* Setup lookup scope (search starting point) */ scope_info.scope.node = prefix_node; /* Lookup the name in the namespace */ status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL, return_node); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s, %s\n", pathname, acpi_format_exception(status))); } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); cleanup: ACPI_FREE(internal_path); 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; }
/******************************************************************************* * * FUNCTION: acpi_remove_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The event to remove a handler * address - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for a General Purpose acpi_event. * ******************************************************************************/ acpi_status acpi_remove_gpe_handler(acpi_handle gpe_device, u32 gpe_number, acpi_gpe_handler address) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler); /* Parameter validation */ if (!address) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure that a handler is indeed installed */ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_HANDLER) && (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) != ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Remove the handler */ handler = gpe_event_info->dispatch.handler; gpe_event_info->dispatch.handler = NULL; /* Restore Method node (if any), set dispatch flags */ gpe_event_info->dispatch.method_node = handler->method_node; gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); gpe_event_info->flags |= handler->original_flags; /* * If the GPE was previously associated with a method and it was * enabled, it should be enabled at this point to restore the * post-initialization configuration. */ if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == ACPI_GPE_DISPATCH_METHOD) || (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) { (void)acpi_ev_add_gpe_reference(gpe_event_info); } acpi_os_release_lock(acpi_gbl_gpe_lock, flags); (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); /* Make sure all deferred GPE tasks are completed */ acpi_os_wait_events_complete(); /* Now we can free the handler object */ ACPI_FREE(handler); return_ACPI_STATUS(status); unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); }
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_map_handle_to_node(device); if (!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) { /* 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), dev_node %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); }
/******************************************************************************* * * FUNCTION: acpi_ev_install_gpe_handler * * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT * defined GPEs) * gpe_number - The GPE number within the GPE block * type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. * is_raw_handler - Whether this GPE should be handled using * the special GPE handler mode. * address - Address of the handler * context - Value passed to the handler on each GPE * * RETURN: Status * * DESCRIPTION: Internal function to install a handler for a General Purpose * Event. * ******************************************************************************/ static acpi_status acpi_ev_install_gpe_handler(acpi_handle gpe_device, u32 gpe_number, u32 type, u8 is_raw_handler, acpi_gpe_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_handler_info *handler; acpi_status status; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(ev_install_gpe_handler); /* Parameter validation */ if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Allocate and init handler object (before lock) */ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info)); if (!handler) { status = AE_NO_MEMORY; goto unlock_and_exit; } flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto free_and_exit; } /* Make sure that there isn't a handler there already */ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_HANDLER) || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) == ACPI_GPE_DISPATCH_RAW_HANDLER)) { status = AE_ALREADY_EXISTS; goto free_and_exit; } handler->address = address; handler->context = context; handler->method_node = gpe_event_info->dispatch.method_node; handler->original_flags = (u8)(gpe_event_info->flags & (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK)); /* * If the GPE is associated with a method, it may have been enabled * automatically during initialization, in which case it has to be * disabled now to avoid spurious execution of the handler. */ if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == ACPI_GPE_DISPATCH_METHOD) || (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) == ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) { handler->originally_enabled = TRUE; (void)acpi_ev_remove_gpe_reference(gpe_event_info); /* Sanity check of original type against new type */ if (type != (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) { ACPI_WARNING((AE_INFO, "GPE type mismatch (level/edge)")); } } /* Install the handler */ gpe_event_info->dispatch.handler = handler; /* Setup up dispatch flags to indicate handler (vs. method/notify) */ gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); gpe_event_info->flags |= (u8)(type | (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER : ACPI_GPE_DISPATCH_HANDLER)); acpi_os_release_lock(acpi_gbl_gpe_lock, flags); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_ACPI_STATUS(status); free_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); ACPI_FREE(handler); goto unlock_and_exit; }
acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler, void *context) { struct acpi_namespace_node *node = ACPI_CAST_PTR(struct acpi_namespace_node, device); union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; acpi_status status; u32 i; ACPI_FUNCTION_TRACE(acpi_install_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (!handler_type) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Root Object: * Registering a notify handler on the root object indicates that the * caller wishes to receive notifications for all objects. Note that * only one global handler can be registered per notify type. * Ensure that a handler is not already installed. */ if (device == ACPI_ROOT_OBJECT) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { if (acpi_gbl_global_notify[i].handler) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } acpi_gbl_global_notify[i].handler = handler; acpi_gbl_global_notify[i].context = context; } } goto unlock_and_exit; /* Global notify handler installed, all done */ } /* * All Other Objects: * Caller will only receive notifications specific to the target * object. Note that only certain object types are allowed to * receive notifications. */ /* Are Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object, might not exist */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* Create a new object */ obj_desc = acpi_ut_create_internal_object(node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Attach new object to the Node, remove local reference */ status = acpi_ns_attach_object(device, obj_desc, node->type); acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } /* Ensure that the handler is not already installed in the lists */ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { handler_obj = obj_desc->common_notify.notify_list[i]; while (handler_obj) { if (handler_obj->notify.handler == handler) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } handler_obj = handler_obj->notify.next[i]; } } } /* Create and populate a new notify handler object */ handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY); if (!handler_obj) { status = AE_NO_MEMORY; goto unlock_and_exit; } handler_obj->notify.node = node; handler_obj->notify.handler_type = handler_type; handler_obj->notify.handler = handler; handler_obj->notify.context = context; /* Install the handler at the list head(s) */ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { handler_obj->notify.next[i] = obj_desc->common_notify.notify_list[i]; obj_desc->common_notify.notify_list[i] = handler_obj; } } /* Add an extra reference if handler was installed in both lists */ if (handler_type == ACPI_ALL_NOTIFY) { acpi_ut_add_reference(handler_obj); } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_remove_notify_handler * * PARAMETERS: device - The device for which the handler is installed * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: System Handler (00-7F) * ACPI_DEVICE_NOTIFY: Device Handler (80-FF) * ACPI_ALL_NOTIFY: Both System and Device * handler - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for notifies on an ACPI device * ******************************************************************************/ acpi_status acpi_remove_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler) { struct acpi_namespace_node *node = ACPI_CAST_PTR(struct acpi_namespace_node, device); union acpi_operand_object *obj_desc; union acpi_operand_object *handler_obj; union acpi_operand_object *previous_handler_obj; acpi_status status = AE_OK; u32 i; ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (!handler_type) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Root Object. Global handlers are removed here */ if (device == ACPI_ROOT_OBJECT) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (!acpi_gbl_global_notify[i].handler || (acpi_gbl_global_notify[i].handler != handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Removing global notify handler\n")); acpi_gbl_global_notify[i].handler = NULL; acpi_gbl_global_notify[i].context = NULL; (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Make sure all deferred notify tasks are completed */ acpi_os_wait_events_complete(); } } return_ACPI_STATUS(AE_OK); } /* All other objects: Are Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { return_ACPI_STATUS(AE_TYPE); } /* Must have an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { return_ACPI_STATUS(AE_NOT_EXIST); } /* Internal object exists. Find the handler and remove it */ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { if (handler_type & (i + 1)) { status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } handler_obj = obj_desc->common_notify.notify_list[i]; previous_handler_obj = NULL; /* Attempt to find the handler in the handler list */ while (handler_obj && (handler_obj->notify.handler != handler)) { previous_handler_obj = handler_obj; handler_obj = handler_obj->notify.next[i]; } if (!handler_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Remove the handler object from the list */ if (previous_handler_obj) { /* Handler is not at the list head */ previous_handler_obj->notify.next[i] = handler_obj->notify.next[i]; } else { /* Handler is at the list head */ obj_desc->common_notify.notify_list[i] = handler_obj->notify.next[i]; } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Make sure all deferred notify tasks are completed */ acpi_os_wait_events_complete(); acpi_ut_remove_reference(handler_obj); } } return_ACPI_STATUS(status); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
acpi_status acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) { acpi_status status; ACPI_FUNCTION_TRACE(ns_load_table); acpi_ex_enter_interpreter(); /* * Parse the table and load the namespace with all named * objects found within. Control methods are NOT parsed * at this time. In fact, the control methods cannot be * parsed until the entire namespace is loaded, because * if a control method makes a forward reference (call) * to another control method, we can't continue parsing * because we don't know how many arguments to parse next! */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto unlock_interp; } /* If table already loaded into namespace, just return */ if (acpi_tb_is_table_loaded(table_index)) { status = AE_ALREADY_EXISTS; goto unlock; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Loading table into namespace ****\n")); status = acpi_tb_allocate_owner_id(table_index); if (ACPI_FAILURE(status)) { goto unlock; } status = acpi_ns_parse_table(table_index, node); if (ACPI_SUCCESS(status)) { acpi_tb_set_table_loaded_flag(table_index, TRUE); } else { /* * On error, delete any namespace objects created by this table. * We cannot initialize these objects, so delete them. There are * a couple of expecially bad cases: * AE_ALREADY_EXISTS - namespace collision. * AE_NOT_FOUND - the target of a Scope operator does not * exist. This target of Scope must already exist in the * namespace, as per the ACPI specification. */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list. tables[table_index].owner_id); acpi_tb_release_owner_id(table_index); return_ACPI_STATUS(status); } unlock: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); unlock_interp: (void)acpi_ex_exit_interpreter(); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Now we can parse the control methods. We always parse * them here for a sanity check, and if configured for * just-in-time parsing, we delete the control method * parse trees. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Begin Table Object Initialization\n")); status = acpi_ds_initialize_objects(table_index, node); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "**** Completed Table Object Initialization\n")); /* * Execute any module-level code that was detected during the table load * phase. Although illegal since ACPI 2.0, there are many machines that * contain this type of code. Each block of detected executable AML code * outside of any control method is wrapped with a temporary control * method object and placed on a global list. The methods on this list * are executed below. * * This case executes the module-level code for each table immediately * after the table has been loaded. This provides compatibility with * other ACPI implementations. Optionally, the execution can be deferred * until later, see acpi_initialize_objects. */ if (!acpi_gbl_group_module_level_code) { acpi_ns_exec_module_code_list(); } return_ACPI_STATUS(status); }
static void acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node) { acpi_handle reg_method; struct acpi_namespace_node *next_node; acpi_status status; struct acpi_object_list args; union acpi_object objects[2]; ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method); if (!ec_device_node) { return_VOID; } /* Namespace is currently locked, must release */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Get a handle to a _REG method immediately under the EC device */ status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, ®_method); if (ACPI_FAILURE(status)) { goto exit; /* There is no _REG method present */ } /* * Execute the _REG method only if there is no Operation Region in * this scope with the Embedded Controller space ID. Otherwise, it * will already have been executed. Note, this allows for Regions * with other space IDs to be present; but the code below will then * execute the _REG method with the embedded_control space_ID argument. */ next_node = acpi_ns_get_next_node(ec_device_node, NULL); while (next_node) { if ((next_node->type == ACPI_TYPE_REGION) && (next_node->object) && (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) { goto exit; /* Do not execute the _REG */ } next_node = acpi_ns_get_next_node(ec_device_node, next_node); } /* Evaluate the _REG(embedded_control,Connect) method */ args.count = 2; args.pointer = objects; objects[0].type = ACPI_TYPE_INTEGER; objects[0].integer.value = ACPI_ADR_SPACE_EC; objects[1].type = ACPI_TYPE_INTEGER; objects[1].integer.value = ACPI_REG_CONNECT; status = acpi_evaluate_object(reg_method, NULL, &args, NULL); exit: /* We ignore all errors from above, don't care */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); return_VOID; }
void acpi_tb_delete_tables_by_type(acpi_table_type type) { struct acpi_table_desc *table_desc; u32 count; u32 i; ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type); if (type > ACPI_TABLE_ID_MAX) { return_VOID; } if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) { return; } /* Clear the appropriate "typed" global table pointer */ switch (type) { case ACPI_TABLE_ID_RSDP: acpi_gbl_RSDP = NULL; break; case ACPI_TABLE_ID_DSDT: acpi_gbl_DSDT = NULL; break; case ACPI_TABLE_ID_FADT: acpi_gbl_FADT = NULL; break; case ACPI_TABLE_ID_FACS: acpi_gbl_FACS = NULL; break; case ACPI_TABLE_ID_XSDT: acpi_gbl_XSDT = NULL; break; case ACPI_TABLE_ID_SSDT: case ACPI_TABLE_ID_PSDT: default: break; } /* * Free the table * 1) Get the head of the list */ table_desc = acpi_gbl_table_lists[type].next; count = acpi_gbl_table_lists[type].count; /* * 2) Walk the entire list, deleting both the allocated tables * and the table descriptors */ for (i = 0; i < count; i++) { table_desc = acpi_tb_uninstall_table(table_desc); } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_VOID; }
acpi_status acpi_install_notify_handler ( acpi_handle device, u32 handler_type, acpi_notify_handler handler, void *context) { union acpi_operand_object *obj_desc; union acpi_operand_object *notify_obj; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE ("acpi_install_notify_handler"); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Convert and validate the device handle */ node = acpi_ns_map_handle_to_node (device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* * Root Object: * Registering a notify handler on the root object indicates that the * caller wishes to receive notifications for all objects. Note that * only one <external> global handler can be regsitered (per notify type). */ if (device == ACPI_ROOT_OBJECT) { /* Make sure the handler is not already installed */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && acpi_gbl_device_notify.handler)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = node; acpi_gbl_system_notify.handler = handler; acpi_gbl_system_notify.context = context; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = node; acpi_gbl_device_notify.handler = handler; acpi_gbl_device_notify.context = context; } /* Global notify handler installed */ } /* * All Other Objects: * Caller will only receive notifications specific to the target object. * Note that only certain object types can receive notifications. */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object (node); if (obj_desc) { /* Object exists - make sure there's no handler */ if (((handler_type & ACPI_SYSTEM_NOTIFY) && obj_desc->common_notify.system_notify) || ((handler_type & ACPI_DEVICE_NOTIFY) && obj_desc->common_notify.device_notify)) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } } else { /* Create a new object */ obj_desc = acpi_ut_create_internal_object (node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* Attach new object to the Node */ status = acpi_ns_attach_object (device, obj_desc, node->type); /* Remove local reference to the object */ acpi_ut_remove_reference (obj_desc); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } } /* Install the handler */ notify_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_NOTIFY); if (!notify_obj) { status = AE_NO_MEMORY; goto unlock_and_exit; } notify_obj->notify.node = node; notify_obj->notify.handler = handler; notify_obj->notify.context = context; if (handler_type & ACPI_SYSTEM_NOTIFY) { obj_desc->common_notify.system_notify = notify_obj; } if (handler_type & ACPI_DEVICE_NOTIFY) { obj_desc->common_notify.device_notify = notify_obj; } if (handler_type == ACPI_ALL_NOTIFY) { /* Extra ref if installed in both */ acpi_ut_add_reference (notify_obj); } } unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); }
acpi_status acpi_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_remove_notify_handler ( acpi_handle device, u32 handler_type, acpi_notify_handler handler) { union acpi_operand_object *notify_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE ("acpi_remove_notify_handler"); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { 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_map_handle_to_node (device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Root Object */ if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } /* All Other Objects */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object (node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object (node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; if ((!notify_obj) || (notify_obj->notify.handler != handler)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Remove the handler */ obj_desc->common_notify.system_notify = NULL; acpi_ut_remove_reference (notify_obj); } if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; if ((!notify_obj) || (notify_obj->notify.handler != handler)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; acpi_ut_remove_reference (notify_obj); } } unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); }
void *acpi_os_acquire_object(struct acpi_memory_list *cache) { acpi_status status; void *object; ACPI_FUNCTION_TRACE(os_acquire_object); if (!cache) { return_PTR(NULL); } status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { return_PTR(NULL); } ACPI_MEM_TRACKING(cache->requests++); /* Check the cache first */ if (cache->list_head) { /* There is an object available, use it */ object = cache->list_head; cache->list_head = ACPI_GET_DESCRIPTOR_PTR(object); cache->current_depth--; ACPI_MEM_TRACKING(cache->hits++); ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "%s: Object %p from %s cache\n", ACPI_GET_FUNCTION_NAME, object, cache->list_name)); status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { return_PTR(NULL); } /* Clear (zero) the previously used Object */ memset(object, 0, cache->object_size); } else { /* The cache is empty, create a new object */ ACPI_MEM_TRACKING(cache->total_allocated++); #ifdef ACPI_DBG_TRACK_ALLOCATIONS if ((cache->total_allocated - cache->total_freed) > cache->max_occupied) { cache->max_occupied = cache->total_allocated - cache->total_freed; } #endif /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ status = acpi_ut_release_mutex(ACPI_MTX_CACHES); if (ACPI_FAILURE(status)) { return_PTR(NULL); } object = ACPI_ALLOCATE_ZEROED(cache->object_size); if (!object) { return_PTR(NULL); } } return_PTR(object); }
acpi_status acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, acpi_event_handler address, void *context) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_handler_info *handler; acpi_status status; ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler"); /* Parameter validation */ if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure that there isn't a handler there already */ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) { status = AE_ALREADY_EXISTS; goto unlock_and_exit; } /* Allocate and init handler object */ handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info)); if (!handler) { status = AE_NO_MEMORY; goto unlock_and_exit; } handler->address = address; handler->context = context; handler->method_node = gpe_event_info->dispatch.method_node; /* Disable the GPE before installing the handler */ status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Install the handler */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); gpe_event_info->dispatch.handler = handler; /* Setup up dispatch flags to indicate handler (vs. method) */ gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */ gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); }
/******************************************************************************* * * FUNCTION: acpi_tb_load_namespace * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in * the RSDT/XSDT. * ******************************************************************************/ acpi_status acpi_tb_load_namespace(void) { acpi_status status; u32 i; struct acpi_table_header *new_dsdt; struct acpi_table_desc *table; u32 tables_loaded = 0; u32 tables_failed = 0; ACPI_FUNCTION_TRACE(tb_load_namespace); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* * Load the namespace. The DSDT is required, but any SSDT and * PSDT tables are optional. Verify the DSDT. */ table = &acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index]; if (!acpi_gbl_root_table_list.current_table_count || !ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_DSDT) || ACPI_FAILURE(acpi_tb_validate_table(table))) { status = AE_NO_ACPI_TABLES; goto unlock_and_exit; } /* * Save the DSDT pointer for simple access. This is the mapped memory * address. We must take care here because the address of the .Tables * array can change dynamically as tables are loaded at run-time. Note: * .Pointer field is not validated until after call to acpi_tb_validate_table. */ acpi_gbl_DSDT = table->pointer; /* * Optionally copy the entire DSDT to local memory (instead of simply * mapping it.) There are some BIOSs that corrupt or replace the original * DSDT, creating the need for this option. Default is FALSE, do not copy * the DSDT. */ if (acpi_gbl_copy_dsdt_locally) { new_dsdt = acpi_tb_copy_dsdt(acpi_gbl_dsdt_index); if (new_dsdt) { acpi_gbl_DSDT = new_dsdt; } } /* * Save the original DSDT header for detection of table corruption * and/or replacement of the DSDT from outside the OS. */ memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, sizeof(struct acpi_table_header)); /* Load and parse tables */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed")); tables_failed++; } else { tables_loaded++; } /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { table = &acpi_gbl_root_table_list.tables[i]; if (!table->address || (!ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_SSDT) && !ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_PSDT) && !ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_OSDT)) || ACPI_FAILURE(acpi_tb_validate_table(table))) { continue; } /* Ignore errors while loading tables, get as many as possible */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); status = acpi_ns_load_table(i, acpi_gbl_root_node); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "(%4.4s:%8.8s) while loading table", table->signature.ascii, table->pointer->oem_table_id)); tables_failed++; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Table [%4.4s:%8.8s] (id FF) - Table namespace load failed\n\n", table->signature.ascii, table->pointer->oem_table_id)); } else { tables_loaded++; } } if (!tables_failed) { ACPI_INFO(("%u ACPI AML tables successfully acquired and loaded", tables_loaded)); } else { ACPI_ERROR((AE_INFO, "%u table load failures, %u successful", tables_failed, tables_loaded)); /* Indicate at least one failure */ status = AE_CTRL_TERMINATE; } #ifdef ACPI_APPLICATION ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\n")); #endif unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, acpi_event_handler address) { struct acpi_gpe_event_info *gpe_event_info; struct acpi_handler_info *handler; acpi_status status; ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler"); /* Parameter validation */ if (!address) { return_ACPI_STATUS (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure that a handler is indeed installed */ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure that the installed handler is the same */ if (gpe_event_info->dispatch.handler->address != address) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Disable the GPE before removing the handler */ status = acpi_ev_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Remove the handler */ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); handler = gpe_event_info->dispatch.handler; /* Restore Method node (if any), set dispatch flags */ gpe_event_info->dispatch.method_node = handler->method_node; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */ if (handler->method_node) { gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD; } acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); /* Now we can free the handler object */ ACPI_MEM_FREE (handler); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); }
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = context; acpi_status status; struct acpi_gpe_event_info *local_gpe_event_info; struct acpi_evaluate_info *info; struct acpi_gpe_notify_object *notify_object; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); /* Allocate a local GPE block */ local_gpe_event_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info)); if (!local_gpe_event_info) { ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE")); return_VOID; } status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { ACPI_FREE(local_gpe_event_info); return_VOID; } /* Must revalidate the gpe_number/gpe_block */ if (!acpi_ev_valid_gpe_event(gpe_event_info)) { status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); ACPI_FREE(local_gpe_event_info); return_VOID; } /* * Take a snapshot of the GPE info for this level - we copy the info to * prevent a race condition with remove_handler/remove_block. */ ACPI_MEMCPY(local_gpe_event_info, gpe_event_info, sizeof(struct acpi_gpe_event_info)); status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_VOID; } /* Do the correct dispatch - normal method or implicit notify */ switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_NOTIFY: /* * Implicit notify. * Dispatch a DEVICE_WAKE notify to the appropriate handler. * NOTE: the request is queued for execution after this method * completes. The notify handlers are NOT invoked synchronously * from this thread -- because handlers may in turn run other * control methods. */ status = acpi_ev_queue_notify_request( local_gpe_event_info->dispatch.device.node, ACPI_NOTIFY_DEVICE_WAKE); notify_object = local_gpe_event_info->dispatch.device.next; while (ACPI_SUCCESS(status) && notify_object) { status = acpi_ev_queue_notify_request( notify_object->node, ACPI_NOTIFY_DEVICE_WAKE); notify_object = notify_object->next; } break; case ACPI_GPE_DISPATCH_METHOD: /* Allocate the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { status = AE_NO_MEMORY; } else { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx * control method that corresponds to this GPE */ info->prefix_node = local_gpe_event_info->dispatch.method_node; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); ACPI_FREE(info); } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info->dispatch. method_node))); } break; default: return_VOID; /* Should never happen */ } /* Defer enabling of GPE until all notify handlers are done */ status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe, local_gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_FREE(local_gpe_event_info); } return_VOID; }
acpi_status acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index) { u32 i; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(tb_add_table); if (!table_desc->pointer) { status = acpi_tb_verify_table(table_desc); if (ACPI_FAILURE(status) || !table_desc->pointer) { return_ACPI_STATUS(status); } } /* * Validate the incoming table signature. * * 1) Originally, we checked the table signature for "SSDT" or "PSDT". * 2) We added support for OEMx tables, signature "OEM". * 3) Valid tables were encountered with a null signature, so we just * gave up on validating the signature, (05/2008). * 4) We encountered non-AML tables such as the MADT, which caused * interpreter errors and kernel faults. So now, we once again allow * only "SSDT", "OEMx", and now, also a null signature. (05/2011). */ if ((table_desc->pointer->signature[0] != 0x00) && (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)) && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) { ACPI_BIOS_ERROR((AE_INFO, "Table has invalid signature [%4.4s] (0x%8.8X), " "must be SSDT or OEMx", acpi_ut_valid_acpi_name(*(u32 *)table_desc-> pointer-> signature) ? table_desc->pointer->signature : "????", *(u32 *)table_desc->pointer->signature)); return_ACPI_STATUS(AE_BAD_SIGNATURE); } (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* Check if table is already registered */ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { if (!acpi_gbl_root_table_list.tables[i].pointer) { status = acpi_tb_verify_table(&acpi_gbl_root_table_list. tables[i]); if (ACPI_FAILURE(status) || !acpi_gbl_root_table_list.tables[i].pointer) { continue; } } /* * Check for a table match on the entire table length, * not just the header. */ if (table_desc->length != acpi_gbl_root_table_list.tables[i].length) { continue; } if (ACPI_MEMCMP(table_desc->pointer, acpi_gbl_root_table_list.tables[i].pointer, acpi_gbl_root_table_list.tables[i].length)) { continue; } /* * Note: the current mechanism does not unregister a table if it is * dynamically unloaded. The related namespace entries are deleted, * but the table remains in the root table list. * * The assumption here is that the number of different tables that * will be loaded is actually small, and there is minimal overhead * in just keeping the table in case it is needed again. * * If this assumption changes in the future (perhaps on large * machines with many table load/unload operations), tables will * need to be unregistered when they are unloaded, and slots in the * root table list should be reused when empty. */ /* * Table is already registered. * We can delete the table that was passed as a parameter. */ acpi_tb_delete_table(table_desc); *table_index = i; if (acpi_gbl_root_table_list.tables[i]. flags & ACPI_TABLE_IS_LOADED) { /* Table is still loaded, this is an error */ status = AE_ALREADY_EXISTS; goto release; } else { /* Table was unloaded, allow it to be reloaded */ table_desc->pointer = acpi_gbl_root_table_list.tables[i].pointer; table_desc->address = acpi_gbl_root_table_list.tables[i].address; status = AE_OK; goto print_header; } } /* * ACPI Table Override: * Allow the host to override dynamically loaded tables. * NOTE: the table is fully mapped at this point, and the mapping will * be deleted by tb_table_override if the table is actually overridden. */ (void)acpi_tb_table_override(table_desc->pointer, table_desc); /* Add the table to the global root table list */ status = acpi_tb_store_table(table_desc->address, table_desc->pointer, table_desc->length, table_desc->flags, table_index); if (ACPI_FAILURE(status)) { goto release; } print_header: acpi_tb_print_table_header(table_desc->address, table_desc->pointer); release: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_gpe_block * * PARAMETERS: gpe_device - Handle to the parent GPE Block Device * gpe_block_address - Address and space_iD * register_count - Number of GPE register pairs in the block * interrupt_number - H/W interrupt for the block * * RETURN: Status * * DESCRIPTION: Create and Install a block of GPE registers. The GPEs are not * enabled here. * ******************************************************************************/ acpi_status acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, u32 register_count, u32 interrupt_number) { acpi_status status; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; struct acpi_gpe_block_info *gpe_block; ACPI_FUNCTION_TRACE(acpi_install_gpe_block); if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_validate_handle(gpe_device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* * For user-installed GPE Block Devices, the gpe_block_base_number * is always zero */ status = acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0, interrupt_number, &gpe_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Install block in the device_object attached to the node */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* * No object, create a new one (Device nodes do not always have * an attached object) */ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_DEVICE); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } /* Now install the GPE block in the device_object */ obj_desc->device.gpe_block = gpe_block; unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node = NULL; u32 level = 1; acpi_status status; ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); if (!parent_node) { return_VOID; } /* Lock namespace for possible update */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_VOID; } /* * Traverse the tree of objects until we bubble back up * to where we started. */ while (level > 0) { /* Get the next node in this scope (NULL if none) */ child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { /* Found a child node - detach any attached object */ acpi_ns_detach_object(child_node); /* Check if this node has any children */ if (child_node->child) { /* * There is at least one child of this node, * visit the node */ level++; parent_node = child_node; child_node = NULL; } } else { /* * No more children of this parent node. * Move up to the grandparent. */ level--; /* * Now delete all of the children of this parent * all at the same time. */ acpi_ns_delete_children(parent_node); /* New "last child" is this parent node */ child_node = parent_node; /* Move up the tree to the grandparent */ parent_node = parent_node->parent; } } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; }
acpi_status acpi_ev_gpe_initialize(void) { u32 register_count0 = 0; u32 register_count1 = 0; u32 gpe_number_max = 0; acpi_status status; ACPI_FUNCTION_TRACE(ev_gpe_initialize); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Initialize the GPE Block(s) defined in the FADT * * Why the GPE register block lengths are divided by 2: From the ACPI * Spec, section "General-Purpose Event Registers", we have: * * "Each register block contains two registers of equal length * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN * The length of the GPE1_STS and GPE1_EN registers is equal to * half the GPE1_LEN. If a generic register block is not supported * then its respective block pointer and block length values in the * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need * to be the same size." */ /* * Determine the maximum GPE number for this machine. * * Note: both GPE0 and GPE1 are optional, and either can exist without * the other. * * If EITHER the register length OR the block address are zero, then that * particular block is not supported. */ if (acpi_gbl_FADT.gpe0_block_length && acpi_gbl_FADT.xgpe0_block.address) { /* GPE block 0 exists (has both length and address > 0) */ register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2); gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; /* Install GPE Block 0 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT.xgpe0_block, register_count0, 0, acpi_gbl_FADT.sci_interrupt, &acpi_gbl_gpe_fadt_blocks[0]); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not create GPE Block 0")); } } if (acpi_gbl_FADT.gpe1_block_length && acpi_gbl_FADT.xgpe1_block.address) { /* GPE block 1 exists (has both length and address > 0) */ register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2); /* Check for GPE0/GPE1 overlap (if both banks exist) */ if ((register_count0) && (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) { ACPI_ERROR((AE_INFO, "GPE0 block (GPE 0 to %d) overlaps the GPE1 block " "(GPE %d to %d) - Ignoring GPE1", gpe_number_max, acpi_gbl_FADT.gpe1_base, acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1))); /* Ignore GPE1 block by setting the register count to zero */ register_count1 = 0; } else { /* Install GPE Block 1 */ status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT.xgpe1_block, register_count1, acpi_gbl_FADT.gpe1_base, acpi_gbl_FADT. sci_interrupt, &acpi_gbl_gpe_fadt_blocks [1]); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not create GPE Block 1")); } /* * GPE0 and GPE1 do not have to be contiguous in the GPE number * space. However, GPE0 always starts at GPE number zero. */ gpe_number_max = acpi_gbl_FADT.gpe1_base + ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); } } /* Exit if there are no GPE registers */ if ((register_count0 + register_count1) == 0) { /* GPEs are not required by ACPI, this is OK */ ACPI_DEBUG_PRINT((ACPI_DB_INIT, "There are no GPE blocks defined in the FADT\n")); status = AE_OK; goto cleanup; } /* Check for Max GPE number out-of-range */ if (gpe_number_max > ACPI_GPE_MAX) { ACPI_ERROR((AE_INFO, "Maximum GPE number from FADT is too large: 0x%X", gpe_number_max)); status = AE_BAD_VALUE; goto cleanup; } cleanup: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(AE_OK); }
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *deletion_node; struct acpi_namespace_node *parent_node; u32 level; acpi_status status; ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id); if (owner_id == 0) { return_VOID; } /* Lock namespace for possible update */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_VOID; } deletion_node = NULL; parent_node = acpi_gbl_root_node; child_node = NULL; level = 1; /* * Traverse the tree of nodes until we bubble back up * to where we started. */ while (level > 0) { /* * Get the next child of this parent node. When child_node is NULL, * the first child of the parent is returned */ child_node = acpi_ns_get_next_node(parent_node, child_node); if (deletion_node) { acpi_ns_delete_children(deletion_node); acpi_ns_remove_node(deletion_node); deletion_node = NULL; } if (child_node) { if (child_node->owner_id == owner_id) { /* Found a matching child node - detach any attached object */ acpi_ns_detach_object(child_node); } /* Check if this node has any children */ if (child_node->child) { /* * There is at least one child of this node, * visit the node */ level++; parent_node = child_node; child_node = NULL; } else if (child_node->owner_id == owner_id) { deletion_node = child_node; } } else { /* * No more children of this parent node. * Move up to the grandparent. */ level--; if (level != 0) { if (parent_node->owner_id == owner_id) { deletion_node = parent_node; } } /* New "last child" is this parent node */ child_node = parent_node; /* Move up the tree to the grandparent */ parent_node = parent_node->parent; } } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; }
/******************************************************************************* * * FUNCTION: acpi_ns_root_initialize * * PARAMETERS: None * * RETURN: Status * * DESCRIPTION: Allocate and initialize the default root named objects * * MUTEX: Locks namespace for entire execution * ******************************************************************************/ acpi_status acpi_ns_root_initialize(void) { acpi_status status; const struct acpi_predefined_names *init_val = NULL; struct acpi_namespace_node *new_node; union acpi_operand_object *obj_desc; acpi_string val = NULL; ACPI_FUNCTION_TRACE(ns_root_initialize); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * The global root ptr is initially NULL, so a non-NULL value indicates * that acpi_ns_root_initialize() has already been called; just return. */ if (acpi_gbl_root_node) { status = AE_OK; goto unlock_and_exit; } /* * Tell the rest of the subsystem that the root is initialized * (This is OK because the namespace is locked) */ acpi_gbl_root_node = &acpi_gbl_root_node_struct; /* Enter the pre-defined names in the name table */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { /* _OSI is optional for now, will be permanent later */ if (!ACPI_STRCMP(init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { continue; } status = acpi_ns_lookup(NULL, init_val->name, init_val->type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); if (ACPI_FAILURE(status) || (!new_node)) { /* Must be on same line for code converter */ ACPI_EXCEPTION((AE_INFO, status, "Could not create predefined name %s", init_val->name)); } /* * Name entered successfully. If entry in pre_defined_names[] specifies * an initial value, create the initial value. */ if (init_val->val) { status = acpi_os_predefined_override(init_val, &val); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not override predefined %s", init_val->name)); } if (!val) { val = init_val->val; } /* * Entry requests an initial value, allocate a * descriptor for it. */ obj_desc = acpi_ut_create_internal_object(init_val->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } /* * Convert value string from table entry to * internal representation. Only types actually * used for initial values are implemented here. */ switch (init_val->type) { case ACPI_TYPE_METHOD: obj_desc->method.param_count = (u8) ACPI_TO_INTEGER(val); obj_desc->common.flags |= AOPOBJ_DATA_VALID; #if defined (ACPI_ASL_COMPILER) /* Save the parameter count for the iASL compiler */ new_node->value = obj_desc->method.param_count; #else /* Mark this as a very SPECIAL method */ obj_desc->method.info_flags = ACPI_METHOD_INTERNAL_ONLY; obj_desc->method.dispatch.implementation = acpi_ut_osi_implementation; #endif break; case ACPI_TYPE_INTEGER: obj_desc->integer.value = ACPI_TO_INTEGER(val); break; case ACPI_TYPE_STRING: /* Build an object around the static string */ obj_desc->string.length = (u32) ACPI_STRLEN(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER(val) - 1); /* Create a mutex */ status = acpi_os_create_mutex(&obj_desc->mutex. os_mutex); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(obj_desc); goto unlock_and_exit; } /* Special case for ACPI Global Lock */ if (ACPI_STRCMP(init_val->name, "_GL_") == 0) { acpi_gbl_global_lock_mutex = obj_desc; /* Create additional counting semaphore for global lock */ status = acpi_os_create_semaphore(1, 0, &acpi_gbl_global_lock_semaphore); if (ACPI_FAILURE(status)) { acpi_ut_remove_reference (obj_desc); goto unlock_and_exit; } } break; default: ACPI_ERROR((AE_INFO, "Unsupported initial type value 0x%X", init_val->type)); acpi_ut_remove_reference(obj_desc); obj_desc = NULL; continue; } /* Store pointer to value descriptor in the Node */ status = acpi_ns_attach_object(new_node, obj_desc, obj_desc->common.type); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); /* Save a handle to "_GPE", it is always present */ if (ACPI_SUCCESS(status)) { status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, &acpi_gbl_fadt_gpe_device); } return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_remove_notify_handler * * PARAMETERS: Device - The device for which notifies will be handled * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * * RETURN: Status * * DESCRIPTION: Remove a handler for notifies on an ACPI device * ******************************************************************************/ acpi_status acpi_remove_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler) { union acpi_operand_object *notify_obj; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { status = AE_BAD_PARAMETER; goto exit; } /* Make sure all deferred tasks are completed */ acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Convert and validate the device handle */ node = acpi_ns_validate_handle(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Root Object */ if (device == ACPI_ROOT_OBJECT) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Removing notify handler for namespace root object\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } /* All Other Objects */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { struct acpi_object_notify_handler *handler_obj; struct acpi_object_notify_handler *parent_obj; notify_obj = obj_desc->common_notify.system_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } handler_obj = ¬ify_obj->notify; parent_obj = NULL; while (handler_obj->handler != handler) { if (handler_obj->next) { parent_obj = handler_obj; handler_obj = handler_obj->next; } else { break; } } if (handler_obj->handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* * Remove the handler. There are three possible cases. * First, we may need to remove a non-embedded object. * Second, we may need to remove the embedded object's * handler data, while non-embedded objects exist. * Finally, we may need to remove the embedded object * entirely along with its container. */ if (parent_obj) { /* Non-embedded object is being removed. */ parent_obj->next = handler_obj->next; ACPI_FREE(handler_obj); } else if (notify_obj->notify.next) { /* * The handler matches the embedded object, but * there are more handler objects in the list. * Replace the embedded object's data with the * first next object's data and remove that * object. */ parent_obj = ¬ify_obj->notify; handler_obj = notify_obj->notify.next; *parent_obj = *handler_obj; ACPI_FREE(handler_obj); } else { /* No more handler objects in the list. */ obj_desc->common_notify.system_notify = NULL; acpi_ut_remove_reference(notify_obj); } } if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; acpi_ut_remove_reference(notify_obj); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler")); return_ACPI_STATUS(status); }