|  | // 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 busses. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | 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); | 
|  | } |