static acpi_status acpi_ns_find_ini_methods(acpi_handle obj_handle, u32 nesting_level, void *context, void **return_value) { struct acpi_device_walk_info *info = ACPI_CAST_PTR(struct acpi_device_walk_info, context); struct acpi_namespace_node *node; struct acpi_namespace_node *parent_node; /* Keep count of device/processor/thermal objects */ node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); if ((node->type == ACPI_TYPE_DEVICE) || (node->type == ACPI_TYPE_PROCESSOR) || (node->type == ACPI_TYPE_THERMAL)) { info->device_count++; return (AE_OK); } /* We are only looking for methods named _INI */ if (!ACPI_COMPARE_NAME(node->name.ascii, METHOD_NAME__INI)) { return (AE_OK); } /* * The only _INI methods that we care about are those that are * present under Device, Processor, and Thermal objects. */ parent_node = acpi_ns_get_parent_node(node); switch (parent_node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_THERMAL: /* Mark parent and bubble up the INI present flag to the root */ while (parent_node) { parent_node->flags |= ANOBJ_SUBTREE_HAS_INI; parent_node = acpi_ns_get_parent_node(parent_node); } break; default: break; } return (AE_OK); }
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); }
void acpi_ex_dump_node ( struct acpi_namespace_node *node, u32 flags) { ACPI_FUNCTION_ENTRY (); if (!flags) { if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } } acpi_os_printf ("%20s : %4.4s\n", "Name", acpi_ut_get_node_name (node)); acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type)); acpi_ex_out_integer ("Flags", node->flags); acpi_ex_out_integer ("Owner Id", node->owner_id); acpi_ex_out_integer ("Reference Count", node->reference_count); acpi_ex_out_pointer ("Attached Object", acpi_ns_get_attached_object (node)); acpi_ex_out_pointer ("child_list", node->child); acpi_ex_out_pointer ("next_peer", node->peer); acpi_ex_out_pointer ("Parent", acpi_ns_get_parent_node (node)); }
acpi_status acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) { union acpi_operand_object *extra_desc; struct acpi_namespace_node *node; acpi_status status; ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc); if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); } /* Get the AML pointer (method object) and buffer_field node */ extra_desc = acpi_ns_get_secondary_object(obj_desc); node = obj_desc->buffer_field.node; ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL)); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", acpi_ut_get_node_name(node))); /* Execute the AML code for the term_arg arguments */ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node), extra_desc->extra.aml_length, extra_desc->extra.aml_start); return_ACPI_STATUS(status); }
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) { acpi_size size; struct acpi_namespace_node *next_node; ACPI_FUNCTION_ENTRY(); /* * Compute length of pathname as 5 * number of name segments. * Go back up the parent tree to the root */ size = 0; next_node = node; while (next_node && (next_node != acpi_gbl_root_node)) { if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "Invalid Namespace Node (%p) while traversing namespace", next_node)); return 0; } size += ACPI_PATH_SEGMENT_LENGTH; next_node = acpi_ns_get_parent_node(next_node); } if (!size) { size = 1; /* Root node case */ } return (size + 1); /* +1 for null string terminator */ }
acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) { acpi_size size; struct acpi_namespace_node *next_node; ACPI_FUNCTION_ENTRY(); /* * Compute length of pathname as 5 * number of name segments. * Go back up the parent tree to the root */ size = 0; next_node = node; while (next_node && (next_node != acpi_gbl_root_node)) { size += ACPI_PATH_SEGMENT_LENGTH; next_node = acpi_ns_get_parent_node(next_node); } if (!size) { size = 1; /* Root node case */ } return (size + 1); /* +1 for null string terminator */ }
acpi_name acpi_ns_find_parent_name ( struct acpi_namespace_node *child_node) { struct acpi_namespace_node *parent_node; ACPI_FUNCTION_TRACE ("ns_find_parent_name"); if (child_node) { /* Valid entry. Get the parent Node */ parent_node = acpi_ns_get_parent_node (child_node); if (parent_node) { ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Parent of %p [%4.4s] is %p [%4.4s]\n", child_node, acpi_ut_get_node_name (child_node), parent_node, acpi_ut_get_node_name (parent_node))); if (parent_node->name.integer) { return_VALUE ((acpi_name) parent_node->name.integer); } } ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Unable to find parent of %p (%4.4s)\n", child_node, acpi_ut_get_node_name (child_node))); } return_VALUE (ACPI_UNKNOWN_NAME); }
acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) { struct acpi_namespace_node *node; acpi_status status; union acpi_operand_object *extra_desc; ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc); if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { return_ACPI_STATUS(AE_OK); } extra_desc = acpi_ns_get_secondary_object(obj_desc); if (!extra_desc) { return_ACPI_STATUS(AE_NOT_EXIST); } /* Get the Region node */ node = obj_desc->region.node; ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", acpi_ut_get_node_name(node), extra_desc->extra.aml_start)); /* Execute the argument AML */ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node), extra_desc->extra.aml_length, extra_desc->extra.aml_start); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* Validate the region address/length via the host OS */ status = acpi_os_validate_address(obj_desc->region.space_id, obj_desc->region.address, (acpi_size) obj_desc->region.length); if (ACPI_FAILURE(status)) { /* * Invalid address/length. We will emit an error message and mark * the region as invalid, so that it will cause an additional error if * it is ever used. Then return AE_OK. */ ACPI_EXCEPTION((AE_INFO, status, "During address validation of OpRegion [%4.4s]", node->name.ascii)); obj_desc->common.flags |= AOPOBJ_INVALID; status = AE_OK; } return_ACPI_STATUS(status); }
void acpi_ns_delete_node ( struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; ACPI_FUNCTION_TRACE_PTR ("ns_delete_node", node); parent_node = acpi_ns_get_parent_node (node); prev_node = NULL; next_node = parent_node->child; /* Find the node that is the previous peer in the parent's child list */ while (next_node != node) { prev_node = next_node; next_node = prev_node->peer; } if (prev_node) { /* Node is not first child, unlink it */ prev_node->peer = next_node->peer; if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { prev_node->flags |= ANOBJ_END_OF_PEER_LIST; } } else { /* Node is first child (has no previous peer) */ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { /* No peers at all */ parent_node->child = NULL; } else { /* Link peer list to parent */ parent_node->child = next_node->peer; } } ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); /* * Detach an object if there is one then delete the node */ acpi_ns_detach_object (node); ACPI_MEM_FREE (node); return_VOID; }
void acpi_ns_build_external_path ( struct acpi_namespace_node *node, acpi_size size, char *name_buffer) { acpi_size index; struct acpi_namespace_node *parent_node; ACPI_FUNCTION_NAME ("ns_build_external_path"); /* Special case for root */ index = size - 1; if (index < ACPI_NAME_SIZE) { name_buffer[0] = AML_ROOT_PREFIX; name_buffer[1] = 0; return; } /* Store terminator byte, then build name backwards */ parent_node = node; name_buffer[index] = 0; while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) { index -= ACPI_NAME_SIZE; /* Put the name into the buffer */ ACPI_MOVE_32_TO_32 ((name_buffer + index), &parent_node->name); parent_node = acpi_ns_get_parent_node (parent_node); /* Prefix name with the path separator */ index--; name_buffer[index] = ACPI_PATH_SEPARATOR; } /* Overwrite final separator with the root prefix character */ name_buffer[index] = AML_ROOT_PREFIX; if (index != 0) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not construct pathname; index=%X, size=%X, Path=%s\n", (u32) index, (u32) size, &name_buffer[size])); } return; }
void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node = NULL; u32 level = 1; ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); if (!parent_node) { return_VOID; } while (level > 0) { child_node = acpi_ns_get_next_node(parent_node, child_node); if (child_node) { acpi_ns_detach_object(child_node); if (child_node->child) { level++; parent_node = child_node; child_node = NULL; } } else { level--; acpi_ns_delete_children(parent_node); child_node = parent_node; parent_node = acpi_ns_get_parent_node(parent_node); } } return_VOID; }
void acpi_ns_remove_node(struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); parent_node = acpi_ns_get_parent_node(node); prev_node = NULL; next_node = parent_node->child; while (next_node != node) { prev_node = next_node; next_node = prev_node->peer; } if (prev_node) { prev_node->peer = next_node->peer; if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { prev_node->flags |= ANOBJ_END_OF_PEER_LIST; } } else { if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { parent_node->child = NULL; } else { parent_node->child = next_node->peer; } } acpi_ns_delete_node(node); return_VOID; }
void acpi_ns_remove_node(struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *prev_node; struct acpi_namespace_node *next_node; ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node); parent_node = acpi_ns_get_parent_node(node); prev_node = NULL; next_node = parent_node->child; /* Find the node that is the previous peer in the parent's child list */ while (next_node != node) { prev_node = next_node; next_node = prev_node->peer; } if (prev_node) { /* Node is not first child, unlink it */ prev_node->peer = next_node->peer; if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { prev_node->flags |= ANOBJ_END_OF_PEER_LIST; } } else { /* Node is first child (has no previous peer) */ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { /* No peers at all */ parent_node->child = NULL; } else { /* Link peer list to parent */ parent_node->child = next_node->peer; } } /* Delete the node and any attached objects */ acpi_ns_delete_node(node); return_VOID; }
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); }
void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags) { ACPI_FUNCTION_ENTRY(); if (!flags) { if (! ((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } } acpi_os_printf("%20s : %4.4s\n", "Name", acpi_ut_get_node_name(node)); acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type)); acpi_ex_out_pointer("Attached Object", acpi_ns_get_attached_object(node)); acpi_ex_out_pointer("Parent", acpi_ns_get_parent_node(node)); acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node), acpi_ex_dump_node); }
void acpi_ns_remove_reference ( struct acpi_namespace_node *node) { struct acpi_namespace_node *parent_node; struct acpi_namespace_node *this_node; ACPI_FUNCTION_ENTRY (); /* * Decrement the reference count(s) of this node and all * nodes up to the root, Delete anything with zero remaining references. */ this_node = node; while (this_node) { /* Prepare to move up to parent */ parent_node = acpi_ns_get_parent_node (this_node); /* Decrement the reference count on this node */ this_node->reference_count--; /* Delete the node if no more references */ if (!this_node->reference_count) { /* Delete all children and delete the node */ acpi_ns_delete_children (this_node); acpi_ns_delete_node (this_node); } this_node = parent_node; } }
acpi_status acpi_ns_lookup(union acpi_generic_state *scope_info, char *pathname, acpi_object_type type, acpi_interpreter_mode interpreter_mode, u32 flags, struct acpi_walk_state *walk_state, struct acpi_namespace_node **return_node) { acpi_status status; char *path = pathname; struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *current_node = NULL; struct acpi_namespace_node *this_node = NULL; u32 num_segments; u32 num_carats; acpi_name simple_name; acpi_object_type type_to_check_for; acpi_object_type this_search_type; u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; u32 local_flags; ACPI_FUNCTION_TRACE(ns_lookup); if (!return_node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); *return_node = ACPI_ENTRY_NOT_FOUND; acpi_gbl_ns_lookup_count++; if (!acpi_gbl_root_node) { return_ACPI_STATUS(AE_NO_NAMESPACE); } if ((!scope_info) || (!scope_info->scope.node)) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null scope prefix, using root node (%p)\n", acpi_gbl_root_node)); prefix_node = acpi_gbl_root_node; } else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", prefix_node, acpi_ut_get_descriptor_name(prefix_node))); return_ACPI_STATUS(AE_AML_INTERNAL); } if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) { while (!acpi_ns_opens_scope(prefix_node->type) && prefix_node->type != ACPI_TYPE_ANY) { prefix_node = acpi_ns_get_parent_node(prefix_node); } } } type_to_check_for = type; if (!pathname) { num_segments = 0; this_node = acpi_gbl_root_node; path = ""; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null Pathname (Zero segments), Flags=%X\n", flags)); } else { if (*path == (u8) AML_ROOT_PREFIX) { this_node = acpi_gbl_root_node; search_parent_flag = ACPI_NS_NO_UPSEARCH; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Path is absolute from root [%p]\n", this_node)); } else { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching relative to prefix scope [%4.4s] (%p)\n", acpi_ut_get_node_name(prefix_node), prefix_node)); this_node = prefix_node; num_carats = 0; while (*path == (u8) AML_PARENT_PREFIX) { search_parent_flag = ACPI_NS_NO_UPSEARCH; path++; num_carats++; this_node = acpi_ns_get_parent_node(this_node); if (!this_node) { ACPI_ERROR((AE_INFO, "ACPI path has too many parent prefixes (^) " "- reached beyond root node")); return_ACPI_STATUS(AE_NOT_FOUND); } } if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Search scope is [%4.4s], path has %d carat(s)\n", acpi_ut_get_node_name (this_node), num_carats)); } } switch (*path) { case 0: num_segments = 0; type = this_node->type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags)); break; case AML_DUAL_NAME_PREFIX: search_parent_flag = ACPI_NS_NO_UPSEARCH; num_segments = 2; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Dual Pathname (2 segments, Flags=%X)\n", flags)); break; case AML_MULTI_NAME_PREFIX_OP: search_parent_flag = ACPI_NS_NO_UPSEARCH; path++; num_segments = (u32) (u8) * path; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Multi Pathname (%d Segments, Flags=%X)\n", num_segments, flags)); break; default: num_segments = 1; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Simple Pathname (1 segment, Flags=%X)\n", flags)); break; } ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); } this_search_type = ACPI_TYPE_ANY; current_node = this_node; while (num_segments && current_node) { num_segments--; if (!num_segments) { this_search_type = type; if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && (flags & ACPI_NS_SEARCH_PARENT)) { local_flags |= ACPI_NS_SEARCH_PARENT; } if (flags & ACPI_NS_ERROR_IF_FOUND) { local_flags |= ACPI_NS_ERROR_IF_FOUND; } } ACPI_MOVE_32_TO_32(&simple_name, path); status = acpi_ns_search_and_enter(simple_name, walk_state, current_node, interpreter_mode, this_search_type, local_flags, &this_node); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] not found in scope [%4.4s] %p\n", (char *)&simple_name, (char *)¤t_node->name, current_node)); } *return_node = this_node; return_ACPI_STATUS(status); } if (num_segments > 0) { if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { if (!this_node->object) { return_ACPI_STATUS(AE_NOT_EXIST); } if (acpi_ns_opens_scope (((struct acpi_namespace_node *) this_node->object)->type)) { this_node = (struct acpi_namespace_node *) this_node->object; } } } else { if ((type_to_check_for != ACPI_TYPE_ANY) && (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { ACPI_WARNING((AE_INFO, "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", ACPI_CAST_PTR(char, &simple_name), acpi_ut_get_type_name(this_node-> type), acpi_ut_get_type_name (type_to_check_for))); } if (type == ACPI_TYPE_ANY) { type = this_node->type; } } path += ACPI_NAME_SIZE; current_node = this_node; }
acpi_status acpi_ev_initialize_region(union acpi_operand_object *region_obj, u8 acpi_ns_locked) { union acpi_operand_object *handler_obj; union acpi_operand_object *obj_desc; acpi_adr_space_type space_id; struct acpi_namespace_node *node; acpi_status status; struct acpi_namespace_node *method_node; acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; union acpi_operand_object *region_obj2; ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); if (!region_obj) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { return_ACPI_STATUS(AE_OK); } region_obj2 = acpi_ns_get_secondary_object(region_obj); if (!region_obj2) { return_ACPI_STATUS(AE_NOT_EXIST); } node = acpi_ns_get_parent_node(region_obj->region.node); space_id = region_obj->region.space_id; /* Setup defaults */ region_obj->region.handler = NULL; region_obj2->extra.method_REG = NULL; region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; /* Find any "_REG" method associated with this region definition */ status = acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, &method_node); if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region * definition. This will be executed when the handler is attached * or removed */ region_obj2->extra.method_REG = method_node; } /* * The following loop depends upon the root Node having no parent * ie: acpi_gbl_root_node->parent_entry being set to NULL */ while (node) { /* Check to see if a handler exists */ handler_obj = NULL; obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* Can only be a handler if the object exists */ switch (node->type) { case ACPI_TYPE_DEVICE: handler_obj = obj_desc->device.handler; break; case ACPI_TYPE_PROCESSOR: handler_obj = obj_desc->processor.handler; break; case ACPI_TYPE_THERMAL: handler_obj = obj_desc->thermal_zone.handler; break; default: /* Ignore other objects */ break; } while (handler_obj) { /* Is this handler of the correct type? */ if (handler_obj->address_space.space_id == space_id) { /* Found correct handler */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Found handler %p for region %p in obj %p\n", handler_obj, region_obj, obj_desc)); status = acpi_ev_attach_region(handler_obj, region_obj, acpi_ns_locked); /* * Tell all users that this region is usable by running the _REG * method */ if (acpi_ns_locked) { status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } status = acpi_ev_execute_reg_method (region_obj, 1); if (acpi_ns_locked) { status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { return_ACPI_STATUS (status); } } return_ACPI_STATUS(AE_OK); } /* Try next handler in the list */ handler_obj = handler_obj->address_space.next; } } /* * This node does not have the handler we need; * Pop up one level */ node = acpi_ns_get_parent_node(node); } /* If we get here, there is no handler for this region */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "No handler for RegionType %s(%X) (RegionObj %p)\n", acpi_ut_get_region_name(space_id), space_id, region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); }
acpi_status acpi_ev_pci_config_region_setup(acpi_handle handle, u32 function, void *handler_context, void **region_context) { acpi_status status = AE_OK; acpi_integer pci_value; struct acpi_pci_id *pci_id = *region_context; union acpi_operand_object *handler_obj; struct acpi_namespace_node *parent_node; struct acpi_namespace_node *pci_root_node; union acpi_operand_object *region_obj = (union acpi_operand_object *)handle; struct acpi_device_id object_hID; ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); handler_obj = region_obj->region.handler; if (!handler_obj) { /* * No installed handler. This shouldn't happen because the dispatch * routine checks before we get here, but we check again just in case. */ ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, "Attempting to init a region %p, with no handler\n", region_obj)); return_ACPI_STATUS(AE_NOT_EXIST); } *region_context = NULL; if (function == ACPI_REGION_DEACTIVATE) { if (pci_id) { ACPI_FREE(pci_id); } return_ACPI_STATUS(status); } parent_node = acpi_ns_get_parent_node(region_obj->region.node); /* * Get the _SEG and _BBN values from the device upon which the handler * is installed. * * We need to get the _SEG and _BBN objects relative to the PCI BUS device. * This is the device the handler has been registered to handle. */ /* * If the address_space.Node is still pointing to the root, we need * to scan upward for a PCI Root bridge and re-associate the op_region * handlers with that device. */ if (handler_obj->address_space.node == acpi_gbl_root_node) { /* Start search from the parent object */ pci_root_node = parent_node; while (pci_root_node != acpi_gbl_root_node) { status = acpi_ut_execute_HID(pci_root_node, &object_hID); if (ACPI_SUCCESS(status)) { /* * Got a valid _HID string, check if this is a PCI root. * New for ACPI 3.0: check for a PCI Express root also. */ if (! (ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING, sizeof(PCI_ROOT_HID_STRING)) || !(ACPI_STRNCMP (object_hID.value, PCI_EXPRESS_ROOT_HID_STRING, sizeof(PCI_EXPRESS_ROOT_HID_STRING))))) { /* Install a handler for this PCI root bridge */ status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* * It is OK if the handler is already installed on the root * bridge. Still need to return a context object for the * new PCI_Config operation region, however. */ status = AE_OK; } else { ACPI_EXCEPTION((AE_INFO, status, "Could not install PciConfig handler for Root Bridge %4.4s", acpi_ut_get_node_name (pci_root_node))); } } break; } } pci_root_node = acpi_ns_get_parent_node(pci_root_node); } /* PCI root bridge not found, use namespace root node */ } else { pci_root_node = handler_obj->address_space.node; } /* * If this region is now initialized, we are done. * (install_address_space_handler could have initialized it) */ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { return_ACPI_STATUS(AE_OK); } /* Region is still not initialized. Create a new context */ pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); if (!pci_id) { return_ACPI_STATUS(AE_NO_MEMORY); } /* * For PCI_Config space access, we need the segment, bus, * device and function numbers. Acquire them here. */ /* * Get the PCI device and function numbers from the _ADR object * contained in the parent's scope. */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node, &pci_value); /* * The default is zero, and since the allocation above zeroed * the data, just do nothing on failure. */ if (ACPI_SUCCESS(status)) { pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); } /* The PCI segment number comes from the _SEG method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, pci_root_node, &pci_value); if (ACPI_SUCCESS(status)) { pci_id->segment = ACPI_LOWORD(pci_value); } /* The PCI bus number comes from the _BBN method */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, pci_root_node, &pci_value); if (ACPI_SUCCESS(status)) { pci_id->bus = ACPI_LOWORD(pci_value); } /* Complete this device's pci_id */ acpi_os_derive_pci_id(pci_root_node, region_obj->region.node, &pci_id); *region_context = pci_id; return_ACPI_STATUS(AE_OK); }
/**ltl * 功能: 遍历以start_node为始的节点,分别调用user_function * 参数: type ->要遍历的节点类型 * start_node ->起始节点 * max_depth ->深度 * unlock_before_callback-> * user_function ->每个遍历到的节点调用的回调函数 * context ->给回调函数传递的参数 * return_value ->[out]返回值 * 返回值: * 说明: */ acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u8 unlock_before_callback, acpi_walk_callback user_function, 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; 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 = 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) { /* Get the next node in this scope. Null if not found */ status = AE_OK; /* 获取下一个节点 */ child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, child_node); if (child_node) { /* 子节点不为NULL */ /* * Found node, Get the type if we are not * searching for ANY */ if (type != ACPI_TYPE_ANY) { child_type = child_node->type; } if (child_type == type) { /* 节点类型一致 */ /* * Found a matching node, invoke the user * callback function */ if (unlock_before_callback) { mutex_status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(mutex_status)) { return_ACPI_STATUS(mutex_status); } } /* 调用回调函数 */ status = user_function(child_node, level, context, return_value); if (unlock_before_callback) { 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 ((level < max_depth) && (status != AE_CTRL_DEPTH)) { if (acpi_ns_get_next_node(ACPI_TYPE_ANY, child_node, NULL)) { /*存在下一个子节点*/ /* * There is at least one child of this * node, visit the onde */ level++; /* 递增深度 */ parent_node = child_node; /* 以子节点做为起始,开始新的遍历 */ child_node = NULL; } } } 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 = acpi_ns_get_parent_node(parent_node); /* 获取父节点 */ } } /* Complete walk, not terminated by user function */ 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 = acpi_ns_get_parent_node(parent_node); } } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; }
void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node = NULL; u32 level = 1; ACPI_FUNCTION_TRACE(ns_delete_namespace_subtree); if (!parent_node) { 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 = acpi_ns_get_parent_node(parent_node); } } return_VOID; }
void acpi_ns_install_node ( struct acpi_walk_state *walk_state, struct acpi_namespace_node *parent_node, /* Parent */ struct acpi_namespace_node *node, /* New Child*/ acpi_object_type type) { u16 owner_id = 0; struct acpi_namespace_node *child_node; #ifdef ACPI_ALPHABETIC_NAMESPACE struct acpi_namespace_node *previous_child_node; #endif ACPI_FUNCTION_TRACE ("ns_install_node"); /* * Get the owner ID from the Walk state * The owner ID is used to track table deletion and * deletion of objects created by methods */ if (walk_state) { owner_id = walk_state->owner_id; } /* Link the new entry into the parent and existing children */ child_node = parent_node->child; if (!child_node) { parent_node->child = node; node->flags |= ANOBJ_END_OF_PEER_LIST; node->peer = parent_node; } else { #ifdef ACPI_ALPHABETIC_NAMESPACE /* * Walk the list whilst searching for the correct * alphabetic placement. */ previous_child_node = NULL; while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) { if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { /* Last peer; Clear end-of-list flag */ child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; /* This node is the new peer to the child node */ child_node->peer = node; /* This node is the new end-of-list */ node->flags |= ANOBJ_END_OF_PEER_LIST; node->peer = parent_node; break; } /* Get next peer */ previous_child_node = child_node; child_node = child_node->peer; } /* Did the node get inserted at the end-of-list? */ if (!(node->flags & ANOBJ_END_OF_PEER_LIST)) { /* * Loop above terminated without reaching the end-of-list. * Insert the new node at the current location */ if (previous_child_node) { /* Insert node alphabetically */ node->peer = child_node; previous_child_node->peer = node; } else { /* Insert node alphabetically at start of list */ node->peer = child_node; parent_node->child = node; } } #else while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { child_node = child_node->peer; } child_node->peer = node; /* Clear end-of-list flag */ child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; node->flags |= ANOBJ_END_OF_PEER_LIST; node->peer = parent_node; #endif } /* Init the new entry */ node->owner_id = owner_id; node->type = (u8) type; ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id, acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type), parent_node)); /* * Increment the reference count(s) of all parents up to * the root! */ while ((node = acpi_ns_get_parent_node (node)) != NULL) { node->reference_count++; } return_VOID; }
void acpi_ns_delete_children ( struct acpi_namespace_node *parent_node) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *next_node; struct acpi_namespace_node *node; u8 flags; ACPI_FUNCTION_TRACE_PTR ("ns_delete_children", parent_node); if (!parent_node) { return_VOID; } /* If no children, all done! */ child_node = parent_node->child; if (!child_node) { return_VOID; } /* * Deallocate all children at this level */ do { /* Get the things we need */ next_node = child_node->peer; flags = child_node->flags; /* Grandchildren should have all been deleted already */ if (child_node->child) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found a grandchild! P=%p C=%p\n", parent_node, child_node)); } /* Now we can free this child object */ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p, Remaining %X\n", child_node, acpi_gbl_current_node_count)); /* * Detach an object if there is one, then free the child node */ acpi_ns_detach_object (child_node); /* * Decrement the reference count(s) of all parents up to * the root! (counts were incremented when the node was created) */ node = child_node; while ((node = acpi_ns_get_parent_node (node)) != NULL) { node->reference_count--; } /* There should be only one reference remaining on this node */ if (child_node->reference_count != 1) { ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n", child_node->reference_count, child_node)); } /* Now we can delete the node */ ACPI_MEM_FREE (child_node); /* And move on to the next child in the list */ child_node = next_node; } while (!(flags & ANOBJ_END_OF_PEER_LIST)); /* Clear the parent's child pointer */ parent_node->child = NULL; return_VOID; }
acpi_status acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u32 flags, acpi_walk_callback user_function, 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; 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 = 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) { /* Get the next node in this scope. Null if not found */ status = AE_OK; child_node = acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, child_node); if (child_node) { /* 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); } } status = user_function(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 ((level < max_depth) && (status != AE_CTRL_DEPTH)) { if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { /* There is at least one child of this node, visit it */ level++; parent_node = child_node; child_node = NULL; } } } 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 = acpi_ns_get_parent_node(parent_node); } } /* Complete walk, not terminated by user function */ 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; } 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; while (level > 0) { 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) { acpi_ns_detach_object(child_node); } if (child_node->child) { level++; parent_node = child_node; child_node = NULL; } else if (child_node->owner_id == owner_id) { deletion_node = child_node; } } else { level--; if (level != 0) { if (parent_node->owner_id == owner_id) { deletion_node = parent_node; } } child_node = parent_node; parent_node = acpi_ns_get_parent_node(parent_node); } } (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_VOID; }
acpi_status acpi_ns_lookup(union acpi_generic_state *scope_info, char *pathname, acpi_object_type type, acpi_interpreter_mode interpreter_mode, u32 flags, struct acpi_walk_state *walk_state, struct acpi_namespace_node **return_node) { acpi_status status; char *path = pathname; struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *current_node = NULL; struct acpi_namespace_node *this_node = NULL; u32 num_segments; u32 num_carats; acpi_name simple_name; acpi_object_type type_to_check_for; acpi_object_type this_search_type; u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; u32 local_flags; ACPI_FUNCTION_TRACE(ns_lookup); if (!return_node) { return_ACPI_STATUS(AE_BAD_PARAMETER); } local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_SEARCH_PARENT); *return_node = ACPI_ENTRY_NOT_FOUND; acpi_gbl_ns_lookup_count++; if (!acpi_gbl_root_node) { return_ACPI_STATUS(AE_NO_NAMESPACE); } /* * Get the prefix scope. * A null scope means use the root scope */ if ((!scope_info) || (!scope_info->scope.node)) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null scope prefix, using root node (%p)\n", acpi_gbl_root_node)); prefix_node = acpi_gbl_root_node; } else { prefix_node = scope_info->scope.node; if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", prefix_node, acpi_ut_get_descriptor_name(prefix_node))); return_ACPI_STATUS(AE_AML_INTERNAL); } if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) { /* * This node might not be a actual "scope" node (such as a * Device/Method, etc.) It could be a Package or other object node. * Backup up the tree to find the containing scope node. */ while (!acpi_ns_opens_scope(prefix_node->type) && prefix_node->type != ACPI_TYPE_ANY) { prefix_node = acpi_ns_get_parent_node(prefix_node); } } } /* Save type TBD: may be no longer necessary */ type_to_check_for = type; /* * Begin examination of the actual pathname */ if (!pathname) { /* A Null name_path is allowed and refers to the root */ num_segments = 0; this_node = acpi_gbl_root_node; path = ""; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Null Pathname (Zero segments), Flags=%X\n", flags)); } else { /* * Name pointer is valid (and must be in internal name format) * * Check for scope prefixes: * * As represented in the AML stream, a namepath consists of an * optional scope prefix followed by a name segment part. * * If present, the scope prefix is either a Root Prefix (in * which case the name is fully qualified), or one or more * Parent Prefixes (in which case the name's scope is relative * to the current scope). */ if (*path == (u8) AML_ROOT_PREFIX) { /* Pathname is fully qualified, start from the root */ this_node = acpi_gbl_root_node; search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Point to name segment part */ path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Path is absolute from root [%p]\n", this_node)); } else { /* Pathname is relative to current scope, start there */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Searching relative to prefix scope [%4.4s] (%p)\n", acpi_ut_get_node_name(prefix_node), prefix_node)); /* * Handle multiple Parent Prefixes (carat) by just getting * the parent node for each prefix instance. */ this_node = prefix_node; num_carats = 0; while (*path == (u8) AML_PARENT_PREFIX) { /* Name is fully qualified, no search rules apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* * Point past this prefix to the name segment * part or the next Parent Prefix */ path++; /* Backup to the parent node */ num_carats++; this_node = acpi_ns_get_parent_node(this_node); if (!this_node) { /* Current scope has no parent scope */ ACPI_ERROR((AE_INFO, "ACPI path has too many parent prefixes (^) - reached beyond root node")); return_ACPI_STATUS(AE_NOT_FOUND); } } if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Search scope is [%4.4s], path has %d carat(s)\n", acpi_ut_get_node_name (this_node), num_carats)); } } /* * Determine the number of ACPI name segments in this pathname. * * The segment part consists of either: * - A Null name segment (0) * - A dual_name_prefix followed by two 4-byte name segments * - A multi_name_prefix followed by a byte indicating the * number of segments and the segments themselves. * - A single 4-byte name segment * * Examine the name prefix opcode, if any, to determine the number of * segments. */ switch (*path) { case 0: /* * Null name after a root or parent prefixes. We already * have the correct target node and there are no name segments. */ num_segments = 0; type = this_node->type; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Prefix-only Pathname (Zero name segments), Flags=%X\n", flags)); break; case AML_DUAL_NAME_PREFIX: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Two segments, point to first name segment */ num_segments = 2; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Dual Pathname (2 segments, Flags=%X)\n", flags)); break; case AML_MULTI_NAME_PREFIX_OP: /* More than one name_seg, search rules do not apply */ search_parent_flag = ACPI_NS_NO_UPSEARCH; /* Extract segment count, point to first name segment */ path++; num_segments = (u32) (u8) * path; path++; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Multi Pathname (%d Segments, Flags=%X)\n", num_segments, flags)); break; default: /* * Not a Null name, no Dual or Multi prefix, hence there is * only one name segment and Pathname is already pointing to it. */ num_segments = 1; ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Simple Pathname (1 segment, Flags=%X)\n", flags)); break; } ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); } /* * Search namespace for each segment of the name. Loop through and * verify (or add to the namespace) each name segment. * * The object type is significant only at the last name * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; current_node = this_node; while (num_segments && current_node) { num_segments--; if (!num_segments) { /* * This is the last segment, enable typechecking */ this_search_type = type; /* * Only allow automatic parent search (search rules) if the caller * requested it AND we have a single, non-fully-qualified name_seg */ if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && (flags & ACPI_NS_SEARCH_PARENT)) { local_flags |= ACPI_NS_SEARCH_PARENT; } /* Set error flag according to caller */ if (flags & ACPI_NS_ERROR_IF_FOUND) { local_flags |= ACPI_NS_ERROR_IF_FOUND; } } /* Extract one ACPI name from the front of the pathname */ ACPI_MOVE_32_TO_32(&simple_name, path); /* Try to find the single (4 character) ACPI name */ status = acpi_ns_search_and_enter(simple_name, walk_state, current_node, interpreter_mode, this_search_type, local_flags, &this_node); if (ACPI_FAILURE(status)) { if (status == AE_NOT_FOUND) { /* Name not found in ACPI namespace */ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Name [%4.4s] not found in scope [%4.4s] %p\n", (char *)&simple_name, (char *)¤t_node->name, current_node)); } *return_node = this_node; return_ACPI_STATUS(status); } /* More segments to follow? */ if (num_segments > 0) { /* * If we have an alias to an object that opens a scope (such as a * device or processor), we need to dereference the alias here so that * we can access any children of the original node (via the remaining * segments). */ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { if (!this_node->object) { return_ACPI_STATUS(AE_NOT_EXIST); } if (acpi_ns_opens_scope (((struct acpi_namespace_node *)this_node-> object)->type)) { this_node = (struct acpi_namespace_node *) this_node->object; } } } /* Special handling for the last segment (num_segments == 0) */ else { /* * Sanity typecheck of the target object: * * If 1) This is the last segment (num_segments == 0) * 2) And we are looking for a specific type * (Not checking for TYPE_ANY) * 3) Which is not an alias * 4) Which is not a local type (TYPE_SCOPE) * 5) And the type of target object is known (not TYPE_ANY) * 6) And target object does not match what we are looking for * * Then we have a type mismatch. Just warn and ignore it. */ if ((type_to_check_for != ACPI_TYPE_ANY) && (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && (this_node->type != ACPI_TYPE_ANY) && (this_node->type != type_to_check_for)) { /* Complain about a type mismatch */ ACPI_WARNING((AE_INFO, "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", ACPI_CAST_PTR(char, &simple_name), acpi_ut_get_type_name(this_node-> type), acpi_ut_get_type_name (type_to_check_for))); } /* * If this is the last name segment and we are not looking for a * specific type, but the type of found object is known, use that type * to (later) see if it opens a scope. */ if (type == ACPI_TYPE_ANY) { type = this_node->type; } } /* Point to next name segment and make this node current */ path += ACPI_NAME_SIZE; current_node = this_node; }
void acpi_ns_delete_namespace_by_owner ( u16 owner_id) { struct acpi_namespace_node *child_node; struct acpi_namespace_node *deletion_node; u32 level; struct acpi_namespace_node *parent_node; ACPI_FUNCTION_TRACE_U32 ("ns_delete_namespace_by_owner", owner_id); parent_node = acpi_gbl_root_node; child_node = NULL; deletion_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 (ACPI_TYPE_ANY, parent_node, child_node); if (deletion_node) { acpi_ns_remove_reference (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 (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { /* * 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 = acpi_ns_get_parent_node (parent_node); } } return_VOID; }