| // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
| /******************************************************************************* |
| * |
| * Module Name: dbnames - Debugger commands for the acpi namespace |
| * |
| ******************************************************************************/ |
| |
| #include <acpi/acpi.h> |
| #include "accommon.h" |
| #include "acnamesp.h" |
| #include "acdebug.h" |
| #include "acpredef.h" |
| |
| #define _COMPONENT ACPI_CA_DEBUGGER |
| ACPI_MODULE_NAME("dbnames") |
| |
| /* Local prototypes */ |
| static acpi_status |
| acpi_db_walk_and_match_name(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_integrity_walk(acpi_handle obj_handle, |
| u32 nesting_level, void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_walk_for_references(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value); |
| |
| static acpi_status |
| acpi_db_bus_walk(acpi_handle obj_handle, |
| u32 nesting_level, void *context, void **return_value); |
| |
| /* |
| * Arguments for the Objects command |
| * These object types map directly to the ACPI_TYPES |
| */ |
| static struct acpi_db_argument_info acpi_db_object_types[] = { |
| {"ANY"}, |
| {"INTEGERS"}, |
| {"STRINGS"}, |
| {"BUFFERS"}, |
| {"PACKAGES"}, |
| {"FIELDS"}, |
| {"DEVICES"}, |
| {"EVENTS"}, |
| {"METHODS"}, |
| {"MUTEXES"}, |
| {"REGIONS"}, |
| {"POWERRESOURCES"}, |
| {"PROCESSORS"}, |
| {"THERMALZONES"}, |
| {"BUFFERFIELDS"}, |
| {"DDBHANDLES"}, |
| {"DEBUG"}, |
| {"REGIONFIELDS"}, |
| {"BANKFIELDS"}, |
| {"INDEXFIELDS"}, |
| {"REFERENCES"}, |
| {"ALIASES"}, |
| {"METHODALIASES"}, |
| {"NOTIFY"}, |
| {"ADDRESSHANDLER"}, |
| {"RESOURCE"}, |
| {"RESOURCEFIELD"}, |
| {"SCOPES"}, |
| {NULL} /* Must be null terminated */ |
| }; |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_set_scope |
| * |
| * PARAMETERS: name - New scope path |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Set the "current scope" as maintained by this utility. |
| * The scope is used as a prefix to ACPI paths. |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_set_scope(char *name) |
| { |
| acpi_status status; |
| struct acpi_namespace_node *node; |
| |
| if (!name || name[0] == 0) { |
| acpi_os_printf("Current scope: %s\n", acpi_gbl_db_scope_buf); |
| return; |
| } |
| |
| acpi_db_prep_namestring(name); |
| |
| if (ACPI_IS_ROOT_PREFIX(name[0])) { |
| |
| /* Validate new scope from the root */ |
| |
| status = acpi_ns_get_node(acpi_gbl_root_node, name, |
| ACPI_NS_NO_UPSEARCH, &node); |
| if (ACPI_FAILURE(status)) { |
| goto error_exit; |
| } |
| |
| acpi_gbl_db_scope_buf[0] = 0; |
| } else { |
| /* Validate new scope relative to old scope */ |
| |
| status = acpi_ns_get_node(acpi_gbl_db_scope_node, name, |
| ACPI_NS_NO_UPSEARCH, &node); |
| if (ACPI_FAILURE(status)) { |
| goto error_exit; |
| } |
| } |
| |
| /* Build the final pathname */ |
| |
| if (acpi_ut_safe_strcat |
| (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), name)) { |
| status = AE_BUFFER_OVERFLOW; |
| goto error_exit; |
| } |
| |
| if (acpi_ut_safe_strcat |
| (acpi_gbl_db_scope_buf, sizeof(acpi_gbl_db_scope_buf), "\\")) { |
| status = AE_BUFFER_OVERFLOW; |
| goto error_exit; |
| } |
| |
| acpi_gbl_db_scope_node = node; |
| acpi_os_printf("New scope: %s\n", acpi_gbl_db_scope_buf); |
| return; |
| |
| error_exit: |
| |
| acpi_os_printf("Could not attach scope: %s, %s\n", |
| name, acpi_format_exception(status)); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_dump_namespace |
| * |
| * PARAMETERS: start_arg - Node to begin namespace dump |
| * depth_arg - Maximum tree depth to be dumped |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Dump entire namespace or a subtree. Each node is displayed |
| * with type and other information. |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_dump_namespace(char *start_arg, char *depth_arg) |
| { |
| acpi_handle subtree_entry = acpi_gbl_root_node; |
| u32 max_depth = ACPI_UINT32_MAX; |
| |
| /* No argument given, just start at the root and dump entire namespace */ |
| |
| if (start_arg) { |
| subtree_entry = acpi_db_convert_to_node(start_arg); |
| if (!subtree_entry) { |
| return; |
| } |
| |
| /* Now we can check for the depth argument */ |
| |
| if (depth_arg) { |
| max_depth = strtoul(depth_arg, NULL, 0); |
| } |
| } |
| |
| acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
| |
| if (((struct acpi_namespace_node *)subtree_entry)->parent) { |
| acpi_os_printf("ACPI Namespace (from %4.4s (%p) subtree):\n", |
| ((struct acpi_namespace_node *)subtree_entry)-> |
| name.ascii, subtree_entry); |
| } else { |
| acpi_os_printf("ACPI Namespace (from %s):\n", |
| ACPI_NAMESPACE_ROOT); |
| } |
| |
| /* Display the subtree */ |
| |
| acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
| acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
| ACPI_OWNER_ID_MAX, subtree_entry); |
| acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_dump_namespace_paths |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Dump entire namespace with full object pathnames and object |
| * type information. Alternative to "namespace" command. |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_dump_namespace_paths(void) |
| { |
| |
| acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
| acpi_os_printf("ACPI Namespace (from root):\n"); |
| |
| /* Display the entire namespace */ |
| |
| acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
| acpi_ns_dump_object_paths(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, |
| ACPI_UINT32_MAX, ACPI_OWNER_ID_MAX, |
| acpi_gbl_root_node); |
| |
| acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_dump_namespace_by_owner |
| * |
| * PARAMETERS: owner_arg - Owner ID whose nodes will be displayed |
| * depth_arg - Maximum tree depth to be dumped |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Dump elements of the namespace that are owned by the owner_id. |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg) |
| { |
| acpi_handle subtree_entry = acpi_gbl_root_node; |
| u32 max_depth = ACPI_UINT32_MAX; |
| acpi_owner_id owner_id; |
| |
| owner_id = (acpi_owner_id)strtoul(owner_arg, NULL, 0); |
| |
| /* Now we can check for the depth argument */ |
| |
| if (depth_arg) { |
| max_depth = strtoul(depth_arg, NULL, 0); |
| } |
| |
| acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
| acpi_os_printf("ACPI Namespace by owner %X:\n", owner_id); |
| |
| /* Display the subtree */ |
| |
| acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
| acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_SUMMARY, max_depth, |
| owner_id, subtree_entry); |
| acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_walk_and_match_name |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Find a particular name/names within the namespace. Wildcards |
| * are supported -- '?' matches any character. |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_walk_and_match_name(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value) |
| { |
| acpi_status status; |
| char *requested_name = (char *)context; |
| u32 i; |
| struct acpi_buffer buffer; |
| struct acpi_walk_info info; |
| |
| /* Check for a name match */ |
| |
| for (i = 0; i < 4; i++) { |
| |
| /* Wildcard support */ |
| |
| if ((requested_name[i] != '?') && |
| (requested_name[i] != ((struct acpi_namespace_node *) |
| obj_handle)->name.ascii[i])) { |
| |
| /* No match, just exit */ |
| |
| return (AE_OK); |
| } |
| } |
| |
| /* Get the full pathname to this object */ |
| |
| buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
| status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
| if (ACPI_FAILURE(status)) { |
| acpi_os_printf("Could Not get pathname for object %p\n", |
| obj_handle); |
| } else { |
| info.count = 0; |
| info.owner_id = ACPI_OWNER_ID_MAX; |
| info.debug_level = ACPI_UINT32_MAX; |
| info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
| |
| acpi_os_printf("%32s", (char *)buffer.pointer); |
| (void)acpi_ns_dump_one_object(obj_handle, nesting_level, &info, |
| NULL); |
| ACPI_FREE(buffer.pointer); |
| } |
| |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_find_name_in_namespace |
| * |
| * PARAMETERS: name_arg - The 4-character ACPI name to find. |
| * wildcards are supported. |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Search the namespace for a given name (with wildcards) |
| * |
| ******************************************************************************/ |
| |
| acpi_status acpi_db_find_name_in_namespace(char *name_arg) |
| { |
| char acpi_name[5] = "____"; |
| char *acpi_name_ptr = acpi_name; |
| |
| if (strlen(name_arg) > ACPI_NAME_SIZE) { |
| acpi_os_printf("Name must be no longer than 4 characters\n"); |
| return (AE_OK); |
| } |
| |
| /* Pad out name with underscores as necessary to create a 4-char name */ |
| |
| acpi_ut_strupr(name_arg); |
| while (*name_arg) { |
| *acpi_name_ptr = *name_arg; |
| acpi_name_ptr++; |
| name_arg++; |
| } |
| |
| /* Walk the namespace from the root */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, acpi_db_walk_and_match_name, |
| NULL, acpi_name, NULL); |
| |
| acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_walk_for_predefined_names |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Detect and display predefined ACPI names (names that start with |
| * an underscore) |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_walk_for_predefined_names(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value) |
| { |
| struct acpi_namespace_node *node = |
| (struct acpi_namespace_node *)obj_handle; |
| u32 *count = (u32 *)context; |
| const union acpi_predefined_info *predefined; |
| const union acpi_predefined_info *package = NULL; |
| char *pathname; |
| char string_buffer[48]; |
| |
| predefined = acpi_ut_match_predefined_method(node->name.ascii); |
| if (!predefined) { |
| return (AE_OK); |
| } |
| |
| pathname = acpi_ns_get_normalized_pathname(node, TRUE); |
| if (!pathname) { |
| return (AE_OK); |
| } |
| |
| /* If method returns a package, the info is in the next table entry */ |
| |
| if (predefined->info.expected_btypes & ACPI_RTYPE_PACKAGE) { |
| package = predefined + 1; |
| } |
| |
| acpi_ut_get_expected_return_types(string_buffer, |
| predefined->info.expected_btypes); |
| |
| acpi_os_printf("%-32s Arguments %X, Return Types: %s", pathname, |
| METHOD_GET_ARG_COUNT(predefined->info.argument_list), |
| string_buffer); |
| |
| if (package) { |
| acpi_os_printf(" (PkgType %2.2X, ObjType %2.2X, Count %2.2X)", |
| package->ret_info.type, |
| package->ret_info.object_type1, |
| package->ret_info.count1); |
| } |
| |
| acpi_os_printf("\n"); |
| |
| /* Check that the declared argument count matches the ACPI spec */ |
| |
| acpi_ns_check_acpi_compliance(pathname, node, predefined); |
| |
| ACPI_FREE(pathname); |
| (*count)++; |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_check_predefined_names |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Validate all predefined names in the namespace |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_check_predefined_names(void) |
| { |
| u32 count = 0; |
| |
| /* Search all nodes in namespace */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, |
| acpi_db_walk_for_predefined_names, NULL, |
| (void *)&count, NULL); |
| |
| acpi_os_printf("Found %u predefined names in the namespace\n", count); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_walk_for_object_counts |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Display short info about objects in the namespace |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_walk_for_object_counts(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value) |
| { |
| struct acpi_object_info *info = (struct acpi_object_info *)context; |
| struct acpi_namespace_node *node = |
| (struct acpi_namespace_node *)obj_handle; |
| |
| if (node->type > ACPI_TYPE_NS_NODE_MAX) { |
| acpi_os_printf("[%4.4s]: Unknown object type %X\n", |
| node->name.ascii, node->type); |
| } else { |
| info->types[node->type]++; |
| } |
| |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_walk_for_specific_objects |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Display short info about objects in the namespace |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_walk_for_specific_objects(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value) |
| { |
| struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
| struct acpi_buffer buffer; |
| acpi_status status; |
| |
| info->count++; |
| |
| /* Get and display the full pathname to this object */ |
| |
| buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
| status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
| if (ACPI_FAILURE(status)) { |
| acpi_os_printf("Could Not get pathname for object %p\n", |
| obj_handle); |
| return (AE_OK); |
| } |
| |
| acpi_os_printf("%32s", (char *)buffer.pointer); |
| ACPI_FREE(buffer.pointer); |
| |
| /* Dump short info about the object */ |
| |
| (void)acpi_ns_dump_one_object(obj_handle, nesting_level, info, NULL); |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_display_objects |
| * |
| * PARAMETERS: obj_type_arg - Type of object to display |
| * display_count_arg - Max depth to display |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Display objects in the namespace of the requested type |
| * |
| ******************************************************************************/ |
| |
| acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg) |
| { |
| struct acpi_walk_info info; |
| acpi_object_type type; |
| struct acpi_object_info *object_info; |
| u32 i; |
| u32 total_objects = 0; |
| |
| /* No argument means display summary/count of all object types */ |
| |
| if (!obj_type_arg) { |
| object_info = |
| ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_object_info)); |
| |
| /* Walk the namespace from the root */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, |
| acpi_db_walk_for_object_counts, NULL, |
| (void *)object_info, NULL); |
| |
| acpi_os_printf("\nSummary of namespace objects:\n\n"); |
| |
| for (i = 0; i < ACPI_TOTAL_TYPES; i++) { |
| acpi_os_printf("%8u %s\n", object_info->types[i], |
| acpi_ut_get_type_name(i)); |
| |
| total_objects += object_info->types[i]; |
| } |
| |
| acpi_os_printf("\n%8u Total namespace objects\n\n", |
| total_objects); |
| |
| ACPI_FREE(object_info); |
| return (AE_OK); |
| } |
| |
| /* Get the object type */ |
| |
| type = acpi_db_match_argument(obj_type_arg, acpi_db_object_types); |
| if (type == ACPI_TYPE_NOT_FOUND) { |
| acpi_os_printf("Invalid or unsupported argument\n"); |
| return (AE_OK); |
| } |
| |
| acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT); |
| acpi_os_printf |
| ("Objects of type [%s] defined in the current ACPI Namespace:\n", |
| acpi_ut_get_type_name(type)); |
| |
| acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT); |
| |
| info.count = 0; |
| info.owner_id = ACPI_OWNER_ID_MAX; |
| info.debug_level = ACPI_UINT32_MAX; |
| info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT; |
| |
| /* Walk the namespace from the root */ |
| |
| (void)acpi_walk_namespace(type, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, |
| acpi_db_walk_for_specific_objects, NULL, |
| (void *)&info, NULL); |
| |
| acpi_os_printf |
| ("\nFound %u objects of type [%s] in the current ACPI Namespace\n", |
| info.count, acpi_ut_get_type_name(type)); |
| |
| acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT); |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_integrity_walk |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Examine one NS node for valid values. |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_integrity_walk(acpi_handle obj_handle, |
| u32 nesting_level, void *context, void **return_value) |
| { |
| struct acpi_integrity_info *info = |
| (struct acpi_integrity_info *)context; |
| struct acpi_namespace_node *node = |
| (struct acpi_namespace_node *)obj_handle; |
| union acpi_operand_object *object; |
| u8 alias = TRUE; |
| |
| info->nodes++; |
| |
| /* Verify the NS node, and dereference aliases */ |
| |
| while (alias) { |
| if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { |
| acpi_os_printf |
| ("Invalid Descriptor Type for Node %p [%s] - " |
| "is %2.2X should be %2.2X\n", node, |
| acpi_ut_get_descriptor_name(node), |
| ACPI_GET_DESCRIPTOR_TYPE(node), |
| ACPI_DESC_TYPE_NAMED); |
| return (AE_OK); |
| } |
| |
| if ((node->type == ACPI_TYPE_LOCAL_ALIAS) || |
| (node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
| node = (struct acpi_namespace_node *)node->object; |
| } else { |
| alias = FALSE; |
| } |
| } |
| |
| if (node->type > ACPI_TYPE_LOCAL_MAX) { |
| acpi_os_printf("Invalid Object Type for Node %p, Type = %X\n", |
| node, node->type); |
| return (AE_OK); |
| } |
| |
| if (!acpi_ut_valid_nameseg(node->name.ascii)) { |
| acpi_os_printf("Invalid AcpiName for Node %p\n", node); |
| return (AE_OK); |
| } |
| |
| object = acpi_ns_get_attached_object(node); |
| if (object) { |
| info->objects++; |
| if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { |
| acpi_os_printf |
| ("Invalid Descriptor Type for Object %p [%s]\n", |
| object, acpi_ut_get_descriptor_name(object)); |
| } |
| } |
| |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_check_integrity |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Check entire namespace for data structure integrity |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_check_integrity(void) |
| { |
| struct acpi_integrity_info info = { 0, 0 }; |
| |
| /* Search all nodes in namespace */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, acpi_db_integrity_walk, NULL, |
| (void *)&info, NULL); |
| |
| acpi_os_printf("Verified %u namespace nodes with %u Objects\n", |
| info.nodes, info.objects); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_walk_for_references |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Check if this namespace object refers to the target object |
| * that is passed in as the context value. |
| * |
| * Note: Currently doesn't check subobjects within the Node's object |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_walk_for_references(acpi_handle obj_handle, |
| u32 nesting_level, |
| void *context, void **return_value) |
| { |
| union acpi_operand_object *obj_desc = |
| (union acpi_operand_object *)context; |
| struct acpi_namespace_node *node = |
| (struct acpi_namespace_node *)obj_handle; |
| |
| /* Check for match against the namespace node itself */ |
| |
| if (node == (void *)obj_desc) { |
| acpi_os_printf("Object is a Node [%4.4s]\n", |
| acpi_ut_get_node_name(node)); |
| } |
| |
| /* Check for match against the object attached to the node */ |
| |
| if (acpi_ns_get_attached_object(node) == obj_desc) { |
| acpi_os_printf("Reference at Node->Object %p [%4.4s]\n", |
| node, acpi_ut_get_node_name(node)); |
| } |
| |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_find_references |
| * |
| * PARAMETERS: object_arg - String with hex value of the object |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Search namespace for all references to the input object |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_find_references(char *object_arg) |
| { |
| union acpi_operand_object *obj_desc; |
| acpi_size address; |
| |
| /* Convert string to object pointer */ |
| |
| address = strtoul(object_arg, NULL, 16); |
| obj_desc = ACPI_TO_POINTER(address); |
| |
| /* Search all nodes in namespace */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, acpi_db_walk_for_references, |
| NULL, (void *)obj_desc, NULL); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_bus_walk |
| * |
| * PARAMETERS: Callback from walk_namespace |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Display info about device objects that have a corresponding |
| * _PRT method. |
| * |
| ******************************************************************************/ |
| |
| static acpi_status |
| acpi_db_bus_walk(acpi_handle obj_handle, |
| u32 nesting_level, void *context, void **return_value) |
| { |
| struct acpi_namespace_node *node = |
| (struct acpi_namespace_node *)obj_handle; |
| acpi_status status; |
| struct acpi_buffer buffer; |
| struct acpi_namespace_node *temp_node; |
| struct acpi_device_info *info; |
| u32 i; |
| |
| if ((node->type != ACPI_TYPE_DEVICE) && |
| (node->type != ACPI_TYPE_PROCESSOR)) { |
| return (AE_OK); |
| } |
| |
| /* Exit if there is no _PRT under this device */ |
| |
| status = acpi_get_handle(node, METHOD_NAME__PRT, |
| ACPI_CAST_PTR(acpi_handle, &temp_node)); |
| if (ACPI_FAILURE(status)) { |
| return (AE_OK); |
| } |
| |
| /* Get the full path to this device object */ |
| |
| buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; |
| status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); |
| if (ACPI_FAILURE(status)) { |
| acpi_os_printf("Could Not get pathname for object %p\n", |
| obj_handle); |
| return (AE_OK); |
| } |
| |
| status = acpi_get_object_info(obj_handle, &info); |
| if (ACPI_FAILURE(status)) { |
| return (AE_OK); |
| } |
| |
| /* Display the full path */ |
| |
| acpi_os_printf("%-32s Type %X", (char *)buffer.pointer, node->type); |
| ACPI_FREE(buffer.pointer); |
| |
| if (info->flags & ACPI_PCI_ROOT_BRIDGE) { |
| acpi_os_printf(" - Is PCI Root Bridge"); |
| } |
| acpi_os_printf("\n"); |
| |
| /* _PRT info */ |
| |
| acpi_os_printf("_PRT: %p\n", temp_node); |
| |
| /* Dump _ADR, _HID, _UID, _CID */ |
| |
| if (info->valid & ACPI_VALID_ADR) { |
| acpi_os_printf("_ADR: %8.8X%8.8X\n", |
| ACPI_FORMAT_UINT64(info->address)); |
| } else { |
| acpi_os_printf("_ADR: <Not Present>\n"); |
| } |
| |
| if (info->valid & ACPI_VALID_HID) { |
| acpi_os_printf("_HID: %s\n", info->hardware_id.string); |
| } else { |
| acpi_os_printf("_HID: <Not Present>\n"); |
| } |
| |
| if (info->valid & ACPI_VALID_UID) { |
| acpi_os_printf("_UID: %s\n", info->unique_id.string); |
| } else { |
| acpi_os_printf("_UID: <Not Present>\n"); |
| } |
| |
| if (info->valid & ACPI_VALID_CID) { |
| for (i = 0; i < info->compatible_id_list.count; i++) { |
| acpi_os_printf("_CID: %s\n", |
| info->compatible_id_list.ids[i].string); |
| } |
| } else { |
| acpi_os_printf("_CID: <Not Present>\n"); |
| } |
| |
| ACPI_FREE(info); |
| return (AE_OK); |
| } |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: acpi_db_get_bus_info |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Display info about system buses. |
| * |
| ******************************************************************************/ |
| |
| void acpi_db_get_bus_info(void) |
| { |
| /* Search all nodes in namespace */ |
| |
| (void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, acpi_db_bus_walk, NULL, NULL, |
| NULL); |
| } |