acpi_status acpi_get_next_object(acpi_object_type type, acpi_handle parent, acpi_handle child, acpi_handle * ret_handle) { acpi_status status; struct acpi_namespace_node *node; struct acpi_namespace_node *parent_node = NULL; struct acpi_namespace_node *child_node = NULL; if (type > ACPI_TYPE_EXTERNAL_MAX) { return (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } if (!child) { parent_node = acpi_ns_map_handle_to_node(parent); if (!parent_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } } else { child_node = acpi_ns_map_handle_to_node(child); if (!child_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } } node = acpi_ns_get_next_node_typed(type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; } if (ret_handle) { *ret_handle = acpi_ns_convert_entry_to_handle(node); } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
/******************************************************************************* * * FUNCTION: acpi_get_next_object * * PARAMETERS: Type - Type of object to be searched for * Parent - Parent object whose children we are getting * last_child - Previous child that was found. * The NEXT child will be returned * ret_handle - Where handle to the next object is placed * * RETURN: Status * * DESCRIPTION: Return the next peer object within the namespace. If Handle is * valid, Scope is ignored. Otherwise, the first object within * Scope is returned. * ******************************************************************************/ acpi_status acpi_get_next_object(acpi_object_type type, acpi_handle parent, acpi_handle child, acpi_handle * ret_handle) { acpi_status status; struct acpi_namespace_node *node; struct acpi_namespace_node *parent_node = NULL; struct acpi_namespace_node *child_node = NULL; /* Parameter validation */ if (type > ACPI_TYPE_EXTERNAL_MAX) { return (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } /* If null handle, use the parent */ if (!child) { /* Start search at the beginning of the specified scope */ parent_node = acpi_ns_map_handle_to_node(parent); if (!parent_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } } else { /* Non-null handle, ignore the parent */ /* Convert and validate the handle */ child_node = acpi_ns_map_handle_to_node(child); if (!child_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } } /* Internal function does the real work */ node = acpi_ns_get_next_node(type, parent_node, child_node); if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; } if (ret_handle) { *ret_handle = acpi_ns_convert_entry_to_handle(node); } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) { struct acpi_namespace_node *node; acpi_status status; if (!ret_type) { return (AE_BAD_PARAMETER); } if (handle == ACPI_ROOT_OBJECT) { *ret_type = ACPI_TYPE_ANY; return (AE_OK); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } *ret_type = node->type; status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
/****************************************************************************** * * FUNCTION: acpi_get_handle * * PARAMETERS: Parent - Object to search under (search scope). * Pathname - Pointer to an asciiz string containing the * name * ret_handle - Where the return handle is returned * * RETURN: Status * * DESCRIPTION: This routine will search for a caller specified name in the * name space. The caller can restrict the search region by * specifying a non NULL parent. The parent value is itself a * namespace handle. * ******************************************************************************/ acpi_status acpi_get_handle(acpi_handle parent, acpi_string pathname, acpi_handle * ret_handle) { acpi_status status; struct acpi_namespace_node *node = NULL; struct acpi_namespace_node *prefix_node = NULL; ACPI_FUNCTION_ENTRY(); /* Parameter Validation */ if (!ret_handle || !pathname) { return (AE_BAD_PARAMETER); } /* Convert a parent handle to a prefix node */ if (parent) { prefix_node = acpi_ns_map_handle_to_node(parent); if (!prefix_node) { return (AE_BAD_PARAMETER); } } /* * Valid cases are: * 1) Fully qualified pathname * 2) Parent + Relative pathname * * Error for <null Parent + relative path> */ if (acpi_ns_valid_root_prefix(pathname[0])) { /* Pathname is fully qualified (starts with '\') */ /* Special case for root-only, since we can't search for it */ if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { *ret_handle = acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); return (AE_OK); } } else if (!prefix_node) { /* Relative path with null prefix is disallowed */ return (AE_BAD_PARAMETER); } /* Find the Node and convert to a handle */ status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); if (ACPI_SUCCESS(status)) { *ret_handle = acpi_ns_convert_entry_to_handle(node); } return (status); }
acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) { struct acpi_namespace_node *node; acpi_status status; if (!ret_id) { return (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } *ret_id = node->owner_id; status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
acpi_status acpi_get_handle ( acpi_handle parent, acpi_string pathname, acpi_handle *ret_handle) { acpi_status status; struct acpi_namespace_node *node = NULL; struct acpi_namespace_node *prefix_node = NULL; ACPI_FUNCTION_ENTRY (); /* Parameter Validation */ if (!ret_handle || !pathname) { return (AE_BAD_PARAMETER); } /* Convert a parent handle to a prefix node */ if (parent) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return (status); } prefix_node = acpi_ns_map_handle_to_node (parent); if (!prefix_node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return (status); } } /* Special case for root, since we can't search for it */ if (ACPI_STRCMP (pathname, ACPI_NS_ROOT_PATH) == 0) { *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node); return (AE_OK); } /* * Find the Node and convert to a handle */ status = acpi_ns_get_node_by_path (pathname, prefix_node, ACPI_NS_NO_UPSEARCH, &node); *ret_handle = NULL; if (ACPI_SUCCESS (status)) { *ret_handle = acpi_ns_convert_entry_to_handle (node); } return (status); }
acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; acpi_size required_size; ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); node = acpi_ns_map_handle_to_node(target_handle); if (!node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Determine size required for the caller buffer */ required_size = acpi_ns_get_pathname_length(node); /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer(buffer, required_size); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Build the path in the caller buffer */ acpi_ns_build_external_path(node, required_size, buffer->pointer); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", (char *)buffer->pointer, (u32) required_size)); return_ACPI_STATUS(AE_OK); }
/******************************************************************************* * * FUNCTION: acpi_get_data * * PARAMETERS: obj_handle - Namespace node * Handler - Handler used in call to attach_data * Data - Where the data is returned * * RETURN: Status * * DESCRIPTION: Retrieve data that was previously attached to a namespace node. * ******************************************************************************/ acpi_status acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) { struct acpi_namespace_node *node; acpi_status status; /* Parameter validation */ if (!obj_handle || !handler || !data) { return (AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } /* Convert and validate the handle */ node = acpi_ns_map_handle_to_node(obj_handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } status = acpi_ns_get_attached_data(node, handler, data); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
/****************************************************************************** * * FUNCTION: acpi_get_name * * PARAMETERS: Handle - Handle to be converted to a pathname * name_type - Full pathname or single segment * Buffer - Buffer for returned path * * RETURN: Pointer to a string containing the fully qualified Name. * * DESCRIPTION: This routine returns the fully qualified name associated with * the Handle parameter. This and the acpi_pathname_to_handle are * complementary functions. * ******************************************************************************/ acpi_status acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; /* Parameter validation */ if (name_type > ACPI_NAME_TYPE_MAX) { return (AE_BAD_PARAMETER); } status = acpi_ut_validate_buffer(buffer); if (ACPI_FAILURE(status)) { return (status); } if (name_type == ACPI_FULL_PATHNAME) { /* Get the full pathname (From the namespace root) */ status = acpi_ns_handle_to_pathname(handle, buffer); return (status); } /* * Wants the single segment ACPI name. * Validate handle and convert to a namespace Node */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Just copy the ACPI name from the Node and zero terminate it */ ACPI_STRNCPY(buffer->pointer, acpi_ut_get_node_name(node), ACPI_NAME_SIZE); ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; status = AE_OK; unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
static acpi_status acpi_ev_reg_run(acpi_handle obj_handle, u32 level, void *context, void **return_value) { union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; acpi_adr_space_type space_id; acpi_status status; space_id = *ACPI_CAST_PTR(acpi_adr_space_type, context); /* 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_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); } /* Object is a Region */ if (obj_desc->region.space_id != space_id) { /* * This region is for a different address space * -- just ignore it */ return (AE_OK); } status = acpi_ev_execute_reg_method(obj_desc, 1); return (status); }
acpi_status acpi_get_parent ( acpi_handle handle, acpi_handle *ret_handle) { struct acpi_namespace_node *node; acpi_status status; if (!ret_handle) { return (AE_BAD_PARAMETER); } /* Special case for the predefined Root Node (no parent) */ if (handle == ACPI_ROOT_OBJECT) { return (AE_NULL_ENTRY); } status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return (status); } /* Convert and validate the handle */ node = acpi_ns_map_handle_to_node (handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Get the parent entry */ *ret_handle = acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_node (node)); /* Return exception if parent is null */ if (!acpi_ns_get_parent_node (node)) { status = AE_NULL_ENTRY; } unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); }
/******************************************************************************* * * FUNCTION: acpi_install_address_space_handler * * PARAMETERS: Device - Handle for the device * space_id - The address space ID * Handler - Address of the handler * Setup - Address of the setup function * Context - Value passed to the handler on each access * * RETURN: Status * * DESCRIPTION: Install a handler for all op_regions of a given space_id. * ******************************************************************************/ acpi_status acpi_install_address_space_handler(acpi_handle device, acpi_adr_space_type space_id, acpi_adr_space_handler handler, acpi_adr_space_setup setup, void *context) { struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_install_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; } /* Install the handler for all Regions for this Space ID */ status = acpi_ev_install_space_handler(node, space_id, handler, setup, context); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Run all _REG methods for this address space */ status = acpi_ev_execute_reg_methods(node, space_id); unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
acpi_status acpi_ns_evaluate_by_handle ( struct acpi_parameter_info *info) { acpi_status status; ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle"); /* Check if namespace has been initialized */ if (!acpi_gbl_root_node) { return_ACPI_STATUS (AE_NO_NAMESPACE); } /* Parameter Validation */ if (!info) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Initialize the return value to an invalid object */ info->return_object = NULL; /* Get the prefix handle and Node */ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } info->node = acpi_ns_map_handle_to_node (info->node); if (!info->node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * For a method alias, we must grab the actual method node so that proper * scoping context will be established before execution. */ if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object); }
acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) { struct acpi_namespace_node *node; struct acpi_namespace_node *parent_node; acpi_status status; if (!ret_handle) { return (AE_BAD_PARAMETER); } if (handle == ACPI_ROOT_OBJECT) { return (AE_NULL_ENTRY); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } parent_node = acpi_ns_get_parent_node(node); *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); if (!parent_node) { status = AE_NULL_ENTRY; } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return (status); }
acpi_status acpi_get_type ( acpi_handle handle, acpi_object_type *ret_type) { struct acpi_namespace_node *node; acpi_status status; /* Parameter Validation */ if (!ret_type) { return (AE_BAD_PARAMETER); } /* * Special case for the predefined Root Node * (return type ANY) */ if (handle == ACPI_ROOT_OBJECT) { *ret_type = ACPI_TYPE_ANY; return (AE_OK); } status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { return (status); } /* Convert and validate the handle */ node = acpi_ns_map_handle_to_node (handle); if (!node) { (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } *ret_type = node->type; status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); }
/******************************************************************************* * * FUNCTION: acpi_remove_gpe_block * * PARAMETERS: gpe_device - Handle to the parent GPE Block Device * * RETURN: Status * * DESCRIPTION: Remove a previously installed block of GPE registers * ******************************************************************************/ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) { union acpi_operand_object *obj_desc; acpi_status status; struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(acpi_remove_gpe_block); if (!gpe_device) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(gpe_device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Get the device_object attached to the node */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc || !obj_desc->device.gpe_block) { return_ACPI_STATUS(AE_NULL_OBJECT); } /* Delete the GPE block (but not the device_object) */ status = acpi_ev_delete_gpe_block(obj_desc->device.gpe_block); if (ACPI_SUCCESS(status)) { obj_desc->device.gpe_block = NULL; } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); }
static acpi_status acpi_rs_validate_parameters(acpi_handle device_handle, struct acpi_buffer *buffer, struct acpi_namespace_node **return_node) { acpi_status status; struct acpi_namespace_node *node; ACPI_FUNCTION_TRACE(rs_validate_parameters); /* * Must have a valid handle to an ACPI device */ if (!device_handle) { return_ACPI_STATUS(AE_BAD_PARAMETER); } node = acpi_ns_map_handle_to_node(device_handle); if (!node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (node->type != ACPI_TYPE_DEVICE) { return_ACPI_STATUS(AE_TYPE); } /* * Validate the user buffer object * * if there is a non-zero buffer length we also need a valid pointer in * the buffer. If it's a zero buffer length, we'll be returning the * needed buffer size (later), so keep going. */ status = acpi_ut_validate_buffer(buffer); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } *return_node = node; return_ACPI_STATUS(AE_OK); }
/****************************************************************************** * * FUNCTION: acpi_get_object_info * * PARAMETERS: Handle - Object Handle * Buffer - Where the info is returned * * RETURN: Status * * DESCRIPTION: Returns information about an object as gleaned from the * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * ******************************************************************************/ acpi_status acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) { acpi_status status; struct acpi_namespace_node *node; struct acpi_device_info *info; struct acpi_device_info *return_info; struct acpi_compatible_id_list *cid_list = NULL; acpi_size size; /* Parameter validation */ if (!handle || !buffer) { return (AE_BAD_PARAMETER); } status = acpi_ut_validate_buffer(buffer); if (ACPI_FAILURE(status)) { return (status); } info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_device_info)); if (!info) { return (AE_NO_MEMORY); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; } node = acpi_ns_map_handle_to_node(handle); if (!node) { (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; } /* Init return structure */ size = sizeof(struct acpi_device_info); info->type = node->type; info->name = node->name.integer; info->valid = 0; if (node->type == ACPI_TYPE_METHOD) { info->param_count = node->object->method.param_count; } status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto cleanup; } /* If not a device, we are all done */ if (info->type == ACPI_TYPE_DEVICE) { /* * Get extra info for ACPI Devices objects only: * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used * to indicate which methods were found and ran successfully. */ /* Execute the Device._HID method */ status = acpi_ut_execute_HID(node, &info->hardware_id); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_HID; } /* Execute the Device._UID method */ status = acpi_ut_execute_UID(node, &info->unique_id); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_UID; } /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); if (ACPI_SUCCESS(status)) { size += cid_list->size; info->valid |= ACPI_VALID_CID; } /* Execute the Device._STA method */ status = acpi_ut_execute_STA(node, &info->current_status); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_STA; } /* Execute the Device._ADR method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, &info->address); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_ADR; } /* Execute the Device._sx_d methods */ status = acpi_ut_execute_sxds(node, info->highest_dstates); if (ACPI_SUCCESS(status)) { info->valid |= ACPI_VALID_SXDS; } } /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer(buffer, size); if (ACPI_FAILURE(status)) { goto cleanup; } /* Populate the return buffer */ return_info = buffer->pointer; ACPI_MEMCPY(return_info, info, sizeof(struct acpi_device_info)); if (cid_list) { ACPI_MEMCPY(&return_info->compatibility_id, cid_list, cid_list->size); } cleanup: ACPI_FREE(info); if (cid_list) { ACPI_FREE(cid_list); } return (status); }
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); 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); } node = acpi_ns_map_handle_to_node(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (device == ACPI_ROOT_OBJECT) { 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; } } else { if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { 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 { obj_desc = acpi_ut_create_internal_object(node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } status = acpi_ns_attach_object(device, obj_desc, node->type); acpi_ut_remove_reference(obj_desc); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } } 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) { acpi_ut_add_reference(notify_obj); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 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_get_object_info ( acpi_handle handle, acpi_device_info *info) { acpi_device_id hid; acpi_device_id uid; acpi_status status; u32 device_status = 0; acpi_integer address = 0; acpi_namespace_node *node; /* Parameter validation */ if (!handle || !info) { return (AE_BAD_PARAMETER); } acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); node = acpi_ns_map_handle_to_node (handle); if (!node) { acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (AE_BAD_PARAMETER); } info->type = node->type; info->name = node->name; acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); /* * If not a device, we are all done. */ if (info->type != ACPI_TYPE_DEVICE) { return (AE_OK); } /* * Get extra info for ACPI devices only. Run the * _HID, _UID, _STA, and _ADR methods. Note: none * of these methods are required, so they may or may * not be present. The Info->Valid bits are used * to indicate which methods ran successfully. */ info->valid = 0; /* Execute the _HID method and save the result */ status = acpi_ut_execute_HID (node, &hid); if (ACPI_SUCCESS (status)) { STRNCPY (info->hardware_id, hid.buffer, sizeof(info->hardware_id)); info->valid |= ACPI_VALID_HID; } /* Execute the _UID method and save the result */ status = acpi_ut_execute_UID (node, &uid); if (ACPI_SUCCESS (status)) { STRCPY (info->unique_id, uid.buffer); info->valid |= ACPI_VALID_UID; } /* * Execute the _STA method and save the result * _STA is not always present */ status = acpi_ut_execute_STA (node, &device_status); if (ACPI_SUCCESS (status)) { info->current_status = device_status; info->valid |= ACPI_VALID_STA; } /* * Execute the _ADR method and save result if successful * _ADR is not always present */ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node, &address); if (ACPI_SUCCESS (status)) { info->address = address; info->valid |= ACPI_VALID_ADR; } return (AE_OK); }
acpi_status acpi_get_name ( acpi_handle handle, u32 name_type, acpi_buffer *ret_path_ptr) { acpi_status status; acpi_namespace_node *node; /* Buffer pointer must be valid always */ if (!ret_path_ptr || (name_type > ACPI_NAME_TYPE_MAX)) { return (AE_BAD_PARAMETER); } /* Allow length to be zero and ignore the pointer */ if ((ret_path_ptr->length) && (!ret_path_ptr->pointer)) { return (AE_BAD_PARAMETER); } if (name_type == ACPI_FULL_PATHNAME) { /* Get the full pathname (From the namespace root) */ status = acpi_ns_handle_to_pathname (handle, &ret_path_ptr->length, ret_path_ptr->pointer); return (status); } /* * Wants the single segment ACPI name. * Validate handle and convert to an Node */ acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); node = acpi_ns_map_handle_to_node (handle); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Check if name will fit in buffer */ if (ret_path_ptr->length < PATH_SEGMENT_LENGTH) { ret_path_ptr->length = PATH_SEGMENT_LENGTH; status = AE_BUFFER_OVERFLOW; goto unlock_and_exit; } /* Just copy the ACPI name from the Node and zero terminate it */ STRNCPY (ret_path_ptr->pointer, (NATIVE_CHAR *) &node->name, ACPI_NAME_SIZE); ((NATIVE_CHAR *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0; status = AE_OK; unlock_and_exit: acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return (status); }
acpi_status acpi_ns_handle_to_pathname ( acpi_handle target_handle, u32 *buf_size, NATIVE_CHAR *user_buffer) { acpi_status status = AE_OK; acpi_namespace_node *node; u32 path_length; u32 user_buf_size; acpi_name name; u32 size; FUNCTION_TRACE_PTR ("Ns_handle_to_pathname", target_handle); if (!acpi_gbl_root_node) { /* * If the name space has not been initialized, * this function should not have been called. */ return_ACPI_STATUS (AE_NO_NAMESPACE); } node = acpi_ns_map_handle_to_node (target_handle); if (!node) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Set return length to the required path length */ path_length = acpi_ns_get_pathname_length (node); size = path_length - 1; user_buf_size = *buf_size; *buf_size = path_length; /* Check if the user buffer is sufficiently large */ if (path_length > user_buf_size) { status = AE_BUFFER_OVERFLOW; goto exit; } /* Store null terminator */ user_buffer[size] = 0; size -= ACPI_NAME_SIZE; /* Put the original ACPI name at the end of the path */ MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &node->name); user_buffer[--size] = PATH_SEPARATOR; /* Build name backwards, putting "." between segments */ while ((size > ACPI_NAME_SIZE) && node) { size -= ACPI_NAME_SIZE; name = acpi_ns_find_parent_name (node); MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &name); user_buffer[--size] = PATH_SEPARATOR; node = acpi_ns_get_parent_object (node); } /* * Overlay the "." preceding the first segment with * the root name "\" */ user_buffer[size] = '\\'; ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Len=%X, %s \n", path_length, user_buffer)); exit: 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; } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* 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 namespace root object\n")); if (((handler_type & ACPI_SYSTEM_NOTIFY) && !acpi_gbl_system_notify.handler) || ((handler_type & ACPI_DEVICE_NOTIFY) && !acpi_gbl_device_notify.handler)) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } /* All Other Objects */ else { /* Notifies allowed on this object? */ if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } /* Check for an existing internal object */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } /* Object exists - make sure there's an existing handler */ if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Remove the handler */ obj_desc->common_notify.system_notify = NULL; acpi_ut_remove_reference(notify_obj); } if (handler_type & ACPI_DEVICE_NOTIFY) { notify_obj = obj_desc->common_notify.device_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } /* Make sure all deferred tasks are completed */ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } /* Remove the handler */ obj_desc->common_notify.device_notify = NULL; acpi_ut_remove_reference(notify_obj); } } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); exit: if (ACPI_FAILURE(status)) ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler")); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_install_notify_handler * * PARAMETERS: Device - The device for which notifies will be handled * handler_type - The type of handler: * ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_ALL_NOTIFY: both system and device * Handler - Address of the handler * Context - Value passed to the handler on each GPE * * RETURN: Status * * DESCRIPTION: Install a handler for notifies on an ACPI device * ******************************************************************************/ acpi_status acpi_install_notify_handler(acpi_handle device, u32 handler_type, acpi_notify_handler handler, void *context) { union acpi_operand_object *obj_desc; union acpi_operand_object *notify_obj; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE(acpi_install_notify_handler); /* Parameter validation */ if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Convert and validate the device handle */ node = acpi_ns_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); }
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_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); if ((!device) || (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { status = AE_BAD_PARAMETER; goto exit; } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } node = acpi_ns_map_handle_to_node(device); if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } 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; } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_system_notify.node = NULL; acpi_gbl_system_notify.handler = NULL; acpi_gbl_system_notify.context = NULL; } if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_device_notify.node = NULL; acpi_gbl_device_notify.handler = NULL; acpi_gbl_device_notify.context = NULL; } } else { if (!acpi_ev_is_notify_object(node)) { status = AE_TYPE; goto unlock_and_exit; } obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (handler_type & ACPI_SYSTEM_NOTIFY) { notify_obj = obj_desc->common_notify.system_notify; if (!notify_obj) { status = AE_NOT_EXIST; goto unlock_and_exit; } if (notify_obj->notify.handler != handler) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } 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; } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_os_wait_events_complete(NULL); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } 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); }
/******************************************************************************* * * FUNCTION: acpi_install_gpe_block * * PARAMETERS: gpe_device - Handle to the parent GPE Block Device * gpe_block_address - Address and space_iD * register_count - Number of GPE register pairs in the block * interrupt_number - H/W interrupt for the block * * RETURN: Status * * DESCRIPTION: Create and Install a block of GPE registers * ******************************************************************************/ acpi_status acpi_install_gpe_block(acpi_handle gpe_device, struct acpi_generic_address *gpe_block_address, u32 register_count, u32 interrupt_number) { acpi_status status; union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; struct acpi_gpe_block_info *gpe_block; ACPI_FUNCTION_TRACE(acpi_install_gpe_block); if ((!gpe_device) || (!gpe_block_address) || (!register_count)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(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; } /* Run the _PRW methods and enable the GPEs */ status = acpi_ev_initialize_gpe_block(node, gpe_block); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } /* Get the device_object attached to the node */ obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { /* No object, create a new one */ 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; } } /* 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); }
/******************************************************************************* * * FUNCTION: acpi_evaluate_object * * PARAMETERS: Handle - Object handle (optional) * Pathname - Object pathname (optional) * external_params - List of parameters to pass to method, * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if * any). If NULL, no value is returned. * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ acpi_status acpi_evaluate_object(acpi_handle handle, acpi_string pathname, struct acpi_object_list *external_params, struct acpi_buffer *return_buffer) { acpi_status status; struct acpi_evaluate_info *info; acpi_size buffer_space_needed; u32 i; ACPI_FUNCTION_TRACE(acpi_evaluate_object); /* Allocate and initialize the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { return_ACPI_STATUS(AE_NO_MEMORY); } info->pathname = pathname; info->parameter_type = ACPI_PARAM_ARGS; /* Convert and validate the device handle */ info->prefix_node = acpi_ns_map_handle_to_node(handle); if (!info->prefix_node) { status = AE_BAD_PARAMETER; goto cleanup; } /* * If there are parameters to be passed to a control method, the external * objects must all be converted to internal objects */ if (external_params && external_params->count) { /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list */ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) external_params-> count + 1) * sizeof(void *)); if (!info->parameters) { status = AE_NO_MEMORY; goto cleanup; } /* Convert each external object in the list to an internal object */ for (i = 0; i < external_params->count; i++) { status = acpi_ut_copy_eobject_to_iobject(&external_params-> pointer[i], &info-> parameters[i]); if (ACPI_FAILURE(status)) { goto cleanup; } } info->parameters[external_params->count] = NULL; } /* * Three major cases: * 1) Fully qualified pathname * 2) No handle, not fully qualified pathname (error) * 3) Valid handle */ if ((pathname) && (acpi_ns_valid_root_prefix(pathname[0]))) { /* The path is fully qualified, just evaluate by name */ info->prefix_node = NULL; status = acpi_ns_evaluate(info); } else if (!handle) { /* * A handle is optional iff a fully qualified pathname is specified. * Since we've already handled fully qualified names above, this is * an error */ if (!pathname) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Both Handle and Pathname are NULL")); } else { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null Handle with relative pathname [%s]", pathname)); } status = AE_BAD_PARAMETER; } else { /* We have a namespace a node and a possible relative path */ status = acpi_ns_evaluate(info); } /* * If we are expecting a return value, and all went well above, * copy the return value to an external object. */ if (return_buffer) { if (!info->return_object) { return_buffer->length = 0; } else { if (ACPI_GET_DESCRIPTOR_TYPE(info->return_object) == ACPI_DESC_TYPE_NAMED) { /* * If we received a NS Node as a return object, this means that * the object we are evaluating has nothing interesting to * return (such as a mutex, etc.) We return an error because * these types are essentially unsupported by this interface. * We don't check up front because this makes it easier to add * support for various types at a later date if necessary. */ status = AE_TYPE; info->return_object = NULL; /* No need to delete a NS Node */ return_buffer->length = 0; } if (ACPI_SUCCESS(status)) { /* Get the size of the returned object */ status = acpi_ut_get_object_size(info->return_object, &buffer_space_needed); if (ACPI_SUCCESS(status)) { /* Validate/Allocate/Clear caller buffer */ status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); if (ACPI_FAILURE(status)) { /* * Caller's buffer is too small or a new one can't * be allocated */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Needed buffer size %X, %s\n", (u32) buffer_space_needed, acpi_format_exception (status))); } else { /* We have enough space for the object, build it */ status = acpi_ut_copy_iobject_to_eobject (info->return_object, return_buffer); } } } } } if (info->return_object) { /* * Delete the internal return object. NOTE: Interpreter must be * locked to avoid race condition. */ acpi_ex_enter_interpreter(); /* Remove one reference on the return object (should delete it) */ acpi_ut_remove_reference(info->return_object); acpi_ex_exit_interpreter(); } cleanup: /* Free the input parameter list (if we created one) */ if (info->parameters) { /* Free the allocated parameter block */ acpi_ut_delete_internal_object_list(info->parameters); } ACPI_FREE(info); return_ACPI_STATUS(status); }
/******************************************************************************* * * FUNCTION: acpi_ns_get_device_callback * * PARAMETERS: Callback from acpi_get_device * * RETURN: Status * * DESCRIPTION: Takes callbacks from walk_namespace and filters out all non- * present devices, or if they specified a HID, it filters based * on that. * ******************************************************************************/ static acpi_status acpi_ns_get_device_callback(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_get_devices_info *info = context; acpi_status status; struct acpi_namespace_node *node; u32 flags; struct acpica_device_id hid; struct acpi_compatible_id_list *cid; acpi_native_uint i; status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } node = acpi_ns_map_handle_to_node(obj_handle); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return (status); } if (!node) { return (AE_BAD_PARAMETER); } /* Run _STA to determine if device is present */ status = acpi_ut_execute_STA(node, &flags); if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } if (!(flags & ACPI_STA_DEVICE_PRESENT)) { /* Don't examine children of the device if not present */ return (AE_CTRL_DEPTH); } /* Filter based on device HID & CID */ if (info->hid != NULL) { status = acpi_ut_execute_HID(node, &hid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } if (ACPI_STRNCMP(hid.value, info->hid, sizeof(hid.value)) != 0) { /* Get the list of Compatible IDs */ status = acpi_ut_execute_CID(node, &cid); if (status == AE_NOT_FOUND) { return (AE_OK); } else if (ACPI_FAILURE(status)) { return (AE_CTRL_DEPTH); } /* Walk the CID list */ for (i = 0; i < cid->count; i++) { if (ACPI_STRNCMP(cid->id[i].value, info->hid, sizeof(struct acpi_compatible_id)) != 0) { ACPI_FREE(cid); return (AE_OK); } } ACPI_FREE(cid); } } status = info->user_function(obj_handle, nesting_level, info->context, return_value); return (status); }