root/drivers/acpi/acpica/dbcmds.c
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/*******************************************************************************
 *
 * Module Name: dbcmds - Miscellaneous debug commands and output routines
 *
 ******************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"
#include "acevents.h"
#include "acdebug.h"
#include "acnamesp.h"
#include "acresrc.h"
#include "actables.h"

#define _COMPONENT          ACPI_CA_DEBUGGER
ACPI_MODULE_NAME("dbcmds")

/* Local prototypes */
static void
acpi_dm_compare_aml_resources(u8 *aml1_buffer,
                              acpi_rsdesc_size aml1_buffer_length,
                              u8 *aml2_buffer,
                              acpi_rsdesc_size aml2_buffer_length);

static acpi_status
acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name);

static acpi_status
acpi_db_resource_callback(struct acpi_resource *resource, void *context);

static acpi_status
acpi_db_device_resources(acpi_handle obj_handle,
                         u32 nesting_level, void *context, void **return_value);

static void acpi_db_do_one_sleep_state(u8 sleep_state);

static char *acpi_db_trace_method_name = NULL;

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_convert_to_node
 *
 * PARAMETERS:  in_string           - String to convert
 *
 * RETURN:      Pointer to a NS node
 *
 * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or
 *              alphanumeric strings.
 *
 ******************************************************************************/

struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string)
{
        struct acpi_namespace_node *node;
        acpi_size address;

        if ((*in_string >= 0x30) && (*in_string <= 0x39)) {

                /* Numeric argument, convert */

                address = strtoul(in_string, NULL, 16);
                node = ACPI_TO_POINTER(address);
                if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
                        acpi_os_printf("Address %p is invalid", node);
                        return (NULL);
                }

                /* Make sure pointer is valid NS node */

                if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
                        acpi_os_printf
                            ("Address %p is not a valid namespace node [%s]\n",
                             node, acpi_ut_get_descriptor_name(node));
                        return (NULL);
                }
        } else {
                /*
                 * Alpha argument: The parameter is a name string that must be
                 * resolved to a Namespace object.
                 */
                node = acpi_db_local_ns_lookup(in_string);
                if (!node) {
                        acpi_os_printf
                            ("Could not find [%s] in namespace, defaulting to root node\n",
                             in_string);
                        node = acpi_gbl_root_node;
                }
        }

        return (node);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_sleep
 *
 * PARAMETERS:  object_arg          - Desired sleep state (0-5). NULL means
 *                                    invoke all possible sleep states.
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Simulate sleep/wake sequences
 *
 ******************************************************************************/

acpi_status acpi_db_sleep(char *object_arg)
{
        u8 sleep_state;
        u32 i;

        ACPI_FUNCTION_TRACE(acpi_db_sleep);

        /* Null input (no arguments) means to invoke all sleep states */

        if (!object_arg) {
                acpi_os_printf("Invoking all possible sleep states, 0-%d\n",
                               ACPI_S_STATES_MAX);

                for (i = 0; i <= ACPI_S_STATES_MAX; i++) {
                        acpi_db_do_one_sleep_state((u8)i);
                }

                return_ACPI_STATUS(AE_OK);
        }

        /* Convert argument to binary and invoke the sleep state */

        sleep_state = (u8)strtoul(object_arg, NULL, 0);
        acpi_db_do_one_sleep_state(sleep_state);
        return_ACPI_STATUS(AE_OK);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_do_one_sleep_state
 *
 * PARAMETERS:  sleep_state         - Desired sleep state (0-5)
 *
 * RETURN:      None
 *
 * DESCRIPTION: Simulate a sleep/wake sequence
 *
 ******************************************************************************/

static void acpi_db_do_one_sleep_state(u8 sleep_state)
{
        acpi_status status;
        u8 sleep_type_a;
        u8 sleep_type_b;

        /* Validate parameter */

        if (sleep_state > ACPI_S_STATES_MAX) {
                acpi_os_printf("Sleep state %d out of range (%d max)\n",
                               sleep_state, ACPI_S_STATES_MAX);
                return;
        }

        acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n",
                       sleep_state, acpi_gbl_sleep_state_names[sleep_state]);

        /* Get the values for the sleep type registers (for display only) */

        status =
            acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b);
        if (ACPI_FAILURE(status)) {
                acpi_os_printf("Could not evaluate [%s] method, %s\n",
                               acpi_gbl_sleep_state_names[sleep_state],
                               acpi_format_exception(status));
                return;
        }

        acpi_os_printf
            ("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n",
             sleep_state, sleep_type_a, sleep_type_b);

        /* Invoke the various sleep/wake interfaces */

        acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n",
                       sleep_state);
        status = acpi_enter_sleep_state_prep(sleep_state);
        if (ACPI_FAILURE(status)) {
                goto error_exit;
        }

        acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state);
        status = acpi_enter_sleep_state(sleep_state);
        if (ACPI_FAILURE(status)) {
                goto error_exit;
        }

        acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n",
                       sleep_state);
        status = acpi_leave_sleep_state_prep(sleep_state);
        if (ACPI_FAILURE(status)) {
                goto error_exit;
        }

        acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n",
                       sleep_state);
        status = acpi_leave_sleep_state(sleep_state);
        if (ACPI_FAILURE(status)) {
                goto error_exit;
        }

        return;

error_exit:
        ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d",
                        sleep_state));
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_display_locks
 *
 * PARAMETERS:  None
 *
 * RETURN:      None
 *
 * DESCRIPTION: Display information about internal mutexes.
 *
 ******************************************************************************/

void acpi_db_display_locks(void)
{
        u32 i;

        for (i = 0; i < ACPI_MAX_MUTEX; i++) {
                acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i),
                               acpi_gbl_mutex_info[i].thread_id ==
                               ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked");
        }
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_display_table_info
 *
 * PARAMETERS:  table_arg           - Name of table to be displayed
 *
 * RETURN:      None
 *
 * DESCRIPTION: Display information about loaded tables. Current
 *              implementation displays all loaded tables.
 *
 ******************************************************************************/

void acpi_db_display_table_info(char *table_arg)
{
        u32 i;
        struct acpi_table_desc *table_desc;
        acpi_status status;

        /* Header */

        acpi_os_printf("Idx ID  Status Type                    "
                       "TableHeader (Sig, Address, Length, Misc)\n");

        /* Walk the entire root table list */

        for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
                table_desc = &acpi_gbl_root_table_list.tables[i];

                /* Index and Table ID */

                acpi_os_printf("%3u %.2u ", i, table_desc->owner_id);

                /* Decode the table flags */

                if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) {
                        acpi_os_printf("NotLoaded ");
                } else {
                        acpi_os_printf(" Loaded ");
                }

                switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
                case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:

                        acpi_os_printf("External/virtual ");
                        break;

                case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:

                        acpi_os_printf("Internal/physical ");
                        break;

                case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:

                        acpi_os_printf("Internal/virtual ");
                        break;

                default:

                        acpi_os_printf("INVALID TYPE    ");
                        break;
                }

                /* Make sure that the table is mapped */

                status = acpi_tb_validate_table(table_desc);
                if (ACPI_FAILURE(status)) {
                        return;
                }

                /* Dump the table header */

                if (table_desc->pointer) {
                        acpi_tb_print_table_header(table_desc->address,
                                                   table_desc->pointer);
                } else {
                        /* If the pointer is null, the table has been unloaded */

                        ACPI_INFO(("%4.4s - Table has been unloaded",
                                   table_desc->signature.ascii));
                }
        }
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_unload_acpi_table
 *
 * PARAMETERS:  object_name         - Namespace pathname for an object that
 *                                    is owned by the table to be unloaded
 *
 * RETURN:      None
 *
 * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned
 *              by the table.
 *
 ******************************************************************************/

void acpi_db_unload_acpi_table(char *object_name)
{
        struct acpi_namespace_node *node;
        acpi_status status;

        /* Translate name to an Named object */

        node = acpi_db_convert_to_node(object_name);
        if (!node) {
                return;
        }

        status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node));
        if (ACPI_SUCCESS(status)) {
                acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n",
                               object_name, node);
        } else {
                acpi_os_printf("%s, while unloading parent table of [%s]\n",
                               acpi_format_exception(status), object_name);
        }
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_send_notify
 *
 * PARAMETERS:  name                - Name of ACPI object where to send notify
 *              value               - Value of the notify to send.
 *
 * RETURN:      None
 *
 * DESCRIPTION: Send an ACPI notification. The value specified is sent to the
 *              named object as an ACPI notify.
 *
 ******************************************************************************/

void acpi_db_send_notify(char *name, u32 value)
{
        struct acpi_namespace_node *node;
        acpi_status status;

        /* Translate name to an Named object */

        node = acpi_db_convert_to_node(name);
        if (!node) {
                return;
        }

        /* Dispatch the notify if legal */

        if (acpi_ev_is_notify_object(node)) {
                status = acpi_ev_queue_notify_request(node, value);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not queue notify\n");
                }
        } else {
                acpi_os_printf("Named object [%4.4s] Type %s, "
                               "must be Device/Thermal/Processor type\n",
                               acpi_ut_get_node_name(node),
                               acpi_ut_get_type_name(node->type));
        }
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_display_interfaces
 *
 * PARAMETERS:  action_arg          - Null, "install", or "remove"
 *              interface_name_arg  - Name for install/remove options
 *
 * RETURN:      None
 *
 * DESCRIPTION: Display or modify the global _OSI interface list
 *
 ******************************************************************************/

void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg)
{
        struct acpi_interface_info *next_interface;
        char *sub_string;
        acpi_status status;

        /* If no arguments, just display current interface list */

        if (!action_arg) {
                (void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex,
                                            ACPI_WAIT_FOREVER);

                next_interface = acpi_gbl_supported_interfaces;
                while (next_interface) {
                        if (!(next_interface->flags & ACPI_OSI_INVALID)) {
                                acpi_os_printf("%s\n", next_interface->name);
                        }

                        next_interface = next_interface->next;
                }

                acpi_os_release_mutex(acpi_gbl_osi_mutex);
                return;
        }

        /* If action_arg exists, so must interface_name_arg */

        if (!interface_name_arg) {
                acpi_os_printf("Missing Interface Name argument\n");
                return;
        }

        /* Uppercase the action for match below */

        acpi_ut_strupr(action_arg);

        /* install - install an interface */

        sub_string = strstr("INSTALL", action_arg);
        if (sub_string) {
                status = acpi_install_interface(interface_name_arg);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("%s, while installing \"%s\"\n",
                                       acpi_format_exception(status),
                                       interface_name_arg);
                }
                return;
        }

        /* remove - remove an interface */

        sub_string = strstr("REMOVE", action_arg);
        if (sub_string) {
                status = acpi_remove_interface(interface_name_arg);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("%s, while removing \"%s\"\n",
                                       acpi_format_exception(status),
                                       interface_name_arg);
                }
                return;
        }

        /* Invalid action_arg */

        acpi_os_printf("Invalid action argument: %s\n", action_arg);
        return;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_display_template
 *
 * PARAMETERS:  buffer_arg          - Buffer name or address
 *
 * RETURN:      None
 *
 * DESCRIPTION: Dump a buffer that contains a resource template
 *
 ******************************************************************************/

void acpi_db_display_template(char *buffer_arg)
{
        struct acpi_namespace_node *node;
        acpi_status status;
        struct acpi_buffer return_buffer;

        /* Translate buffer_arg to an Named object */

        node = acpi_db_convert_to_node(buffer_arg);
        if (!node || (node == acpi_gbl_root_node)) {
                acpi_os_printf("Invalid argument: %s\n", buffer_arg);
                return;
        }

        /* We must have a buffer object */

        if (node->type != ACPI_TYPE_BUFFER) {
                acpi_os_printf
                    ("Not a Buffer object, cannot be a template: %s\n",
                     buffer_arg);
                return;
        }

        return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
        return_buffer.pointer = acpi_gbl_db_buffer;

        /* Attempt to convert the raw buffer to a resource list */

        status = acpi_rs_create_resource_list(node->object, &return_buffer);

        acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
        acpi_dbg_level |= ACPI_LV_RESOURCES;

        if (ACPI_FAILURE(status)) {
                acpi_os_printf
                    ("Could not convert Buffer to a resource list: %s, %s\n",
                     buffer_arg, acpi_format_exception(status));
                goto dump_buffer;
        }

        /* Now we can dump the resource list */

        acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
                                                 return_buffer.pointer));

dump_buffer:
        acpi_os_printf("\nRaw data buffer:\n");
        acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer,
                                  node->object->buffer.length,
                                  DB_BYTE_DISPLAY, ACPI_UINT32_MAX);

        acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
        return;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_dm_compare_aml_resources
 *
 * PARAMETERS:  aml1_buffer         - Contains first resource list
 *              aml1_buffer_length  - Length of first resource list
 *              aml2_buffer         - Contains second resource list
 *              aml2_buffer_length  - Length of second resource list
 *
 * RETURN:      None
 *
 * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in
 *              order to isolate a miscompare to an individual resource)
 *
 ******************************************************************************/

static void
acpi_dm_compare_aml_resources(u8 *aml1_buffer,
                              acpi_rsdesc_size aml1_buffer_length,
                              u8 *aml2_buffer,
                              acpi_rsdesc_size aml2_buffer_length)
{
        u8 *aml1;
        u8 *aml2;
        u8 *aml1_end;
        u8 *aml2_end;
        acpi_rsdesc_size aml1_length;
        acpi_rsdesc_size aml2_length;
        acpi_rsdesc_size offset = 0;
        u8 resource_type;
        u32 count = 0;
        u32 i;

        /* Compare overall buffer sizes (may be different due to size rounding) */

        if (aml1_buffer_length != aml2_buffer_length) {
                acpi_os_printf("**** Buffer length mismatch in converted "
                               "AML: Original %X, New %X ****\n",
                               aml1_buffer_length, aml2_buffer_length);
        }

        aml1 = aml1_buffer;
        aml2 = aml2_buffer;
        aml1_end = aml1_buffer + aml1_buffer_length;
        aml2_end = aml2_buffer + aml2_buffer_length;

        /* Walk the descriptor lists, comparing each descriptor */

        while ((aml1 < aml1_end) && (aml2 < aml2_end)) {

                /* Get the lengths of each descriptor */

                aml1_length = acpi_ut_get_descriptor_length(aml1);
                aml2_length = acpi_ut_get_descriptor_length(aml2);
                resource_type = acpi_ut_get_resource_type(aml1);

                /* Check for descriptor length match */

                if (aml1_length != aml2_length) {
                        acpi_os_printf
                            ("**** Length mismatch in descriptor [%.2X] type %2.2X, "
                             "Offset %8.8X Len1 %X, Len2 %X ****\n", count,
                             resource_type, offset, aml1_length, aml2_length);
                }

                /* Check for descriptor byte match */

                else if (memcmp(aml1, aml2, aml1_length)) {
                        acpi_os_printf
                            ("**** Data mismatch in descriptor [%.2X] type %2.2X, "
                             "Offset %8.8X ****\n", count, resource_type,
                             offset);

                        for (i = 0; i < aml1_length; i++) {
                                if (aml1[i] != aml2[i]) {
                                        acpi_os_printf
                                            ("Mismatch at byte offset %.2X: is %2.2X, "
                                             "should be %2.2X\n", i, aml2[i],
                                             aml1[i]);
                                }
                        }
                }

                /* Exit on end_tag descriptor */

                if (resource_type == ACPI_RESOURCE_NAME_END_TAG) {
                        return;
                }

                /* Point to next descriptor in each buffer */

                count++;
                offset += aml1_length;
                aml1 += aml1_length;
                aml2 += aml2_length;
        }
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_dm_test_resource_conversion
 *
 * PARAMETERS:  node                - Parent device node
 *              name                - resource method name (_CRS)
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Compare the original AML with a conversion of the AML to
 *              internal resource list, then back to AML.
 *
 ******************************************************************************/

static acpi_status
acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name)
{
        acpi_status status;
        struct acpi_buffer return_buffer;
        struct acpi_buffer resource_buffer;
        struct acpi_buffer new_aml;
        union acpi_object *original_aml;

        acpi_os_printf("Resource Conversion Comparison:\n");

        new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER;
        return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
        resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;

        /* Get the original _CRS AML resource template */

        status = acpi_evaluate_object(node, name, NULL, &return_buffer);
        if (ACPI_FAILURE(status)) {
                acpi_os_printf("Could not obtain %s: %s\n",
                               name, acpi_format_exception(status));
                return (status);
        }

        /* Get the AML resource template, converted to internal resource structs */

        status = acpi_get_current_resources(node, &resource_buffer);
        if (ACPI_FAILURE(status)) {
                acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
                               acpi_format_exception(status));
                goto exit1;
        }

        /* Convert internal resource list to external AML resource template */

        status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml);
        if (ACPI_FAILURE(status)) {
                acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n",
                               acpi_format_exception(status));
                goto exit2;
        }

        /* Compare original AML to the newly created AML resource list */

        original_aml = return_buffer.pointer;

        acpi_dm_compare_aml_resources(original_aml->buffer.pointer,
                                      (acpi_rsdesc_size)original_aml->buffer.
                                      length, new_aml.pointer,
                                      (acpi_rsdesc_size)new_aml.length);

        /* Cleanup and exit */

        ACPI_FREE(new_aml.pointer);
exit2:
        ACPI_FREE(resource_buffer.pointer);
exit1:
        ACPI_FREE(return_buffer.pointer);
        return (status);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_resource_callback
 *
 * PARAMETERS:  acpi_walk_resource_callback
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Simple callback to exercise acpi_walk_resources and
 *              acpi_walk_resource_buffer.
 *
 ******************************************************************************/

static acpi_status
acpi_db_resource_callback(struct acpi_resource *resource, void *context)
{

        return (AE_OK);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_device_resources
 *
 * PARAMETERS:  acpi_walk_callback
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object.
 *
 ******************************************************************************/

static acpi_status
acpi_db_device_resources(acpi_handle obj_handle,
                         u32 nesting_level, void *context, void **return_value)
{
        struct acpi_namespace_node *node;
        struct acpi_namespace_node *prt_node = NULL;
        struct acpi_namespace_node *crs_node = NULL;
        struct acpi_namespace_node *prs_node = NULL;
        struct acpi_namespace_node *aei_node = NULL;
        char *parent_path;
        struct acpi_buffer return_buffer;
        acpi_status status;

        node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
        parent_path = acpi_ns_get_normalized_pathname(node, TRUE);
        if (!parent_path) {
                return (AE_NO_MEMORY);
        }

        /* Get handles to the resource methods for this device */

        (void)acpi_get_handle(node, METHOD_NAME__PRT,
                              ACPI_CAST_PTR(acpi_handle, &prt_node));
        (void)acpi_get_handle(node, METHOD_NAME__CRS,
                              ACPI_CAST_PTR(acpi_handle, &crs_node));
        (void)acpi_get_handle(node, METHOD_NAME__PRS,
                              ACPI_CAST_PTR(acpi_handle, &prs_node));
        (void)acpi_get_handle(node, METHOD_NAME__AEI,
                              ACPI_CAST_PTR(acpi_handle, &aei_node));

        if (!prt_node && !crs_node && !prs_node && !aei_node) {
                goto cleanup;   /* Nothing to do */
        }

        acpi_os_printf("\nDevice: %s\n", parent_path);

        /* Prepare for a return object of arbitrary size */

        return_buffer.pointer = acpi_gbl_db_buffer;
        return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

        /* _PRT */

        if (prt_node) {
                acpi_os_printf("Evaluating _PRT\n");

                status =
                    acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not evaluate _PRT: %s\n",
                                       acpi_format_exception(status));
                        goto get_crs;
                }

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status = acpi_get_irq_routing_table(node, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("GetIrqRoutingTable failed: %s\n",
                                       acpi_format_exception(status));
                        goto get_crs;
                }

                acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer));
        }

        /* _CRS */

get_crs:
        if (crs_node) {
                acpi_os_printf("Evaluating _CRS\n");

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status =
                    acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not evaluate _CRS: %s\n",
                                       acpi_format_exception(status));
                        goto get_prs;
                }

                /* This code exercises the acpi_walk_resources interface */

                status = acpi_walk_resources(node, METHOD_NAME__CRS,
                                             acpi_db_resource_callback, NULL);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiWalkResources failed: %s\n",
                                       acpi_format_exception(status));
                        goto get_prs;
                }

                /* Get the _CRS resource list (test ALLOCATE buffer) */

                return_buffer.pointer = NULL;
                return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;

                status = acpi_get_current_resources(node, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
                                       acpi_format_exception(status));
                        goto get_prs;
                }

                /* This code exercises the acpi_walk_resource_buffer interface */

                status = acpi_walk_resource_buffer(&return_buffer,
                                                   acpi_db_resource_callback,
                                                   NULL);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n",
                                       acpi_format_exception(status));
                        goto end_crs;
                }

                /* Dump the _CRS resource list */

                acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
                                                         return_buffer.
                                                         pointer));

                /*
                 * Perform comparison of original AML to newly created AML. This
                 * tests both the AML->Resource conversion and the Resource->AML
                 * conversion.
                 */
                (void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS);

                /* Execute _SRS with the resource list */

                acpi_os_printf("Evaluating _SRS\n");

                status = acpi_set_current_resources(node, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiSetCurrentResources failed: %s\n",
                                       acpi_format_exception(status));
                        goto end_crs;
                }

end_crs:
                ACPI_FREE(return_buffer.pointer);
        }

        /* _PRS */

get_prs:
        if (prs_node) {
                acpi_os_printf("Evaluating _PRS\n");

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status =
                    acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not evaluate _PRS: %s\n",
                                       acpi_format_exception(status));
                        goto get_aei;
                }

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status = acpi_get_possible_resources(node, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiGetPossibleResources failed: %s\n",
                                       acpi_format_exception(status));
                        goto get_aei;
                }

                acpi_rs_dump_resource_list(ACPI_CAST_PTR
                                           (struct acpi_resource,
                                            acpi_gbl_db_buffer));
        }

        /* _AEI */

get_aei:
        if (aei_node) {
                acpi_os_printf("Evaluating _AEI\n");

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status =
                    acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("Could not evaluate _AEI: %s\n",
                                       acpi_format_exception(status));
                        goto cleanup;
                }

                return_buffer.pointer = acpi_gbl_db_buffer;
                return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;

                status = acpi_get_event_resources(node, &return_buffer);
                if (ACPI_FAILURE(status)) {
                        acpi_os_printf("AcpiGetEventResources failed: %s\n",
                                       acpi_format_exception(status));
                        goto cleanup;
                }

                acpi_rs_dump_resource_list(ACPI_CAST_PTR
                                           (struct acpi_resource,
                                            acpi_gbl_db_buffer));
        }

cleanup:
        ACPI_FREE(parent_path);
        return (AE_OK);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_display_resources
 *
 * PARAMETERS:  object_arg          - String object name or object pointer.
 *                                    NULL or "*" means "display resources for
 *                                    all devices"
 *
 * RETURN:      None
 *
 * DESCRIPTION: Display the resource objects associated with a device.
 *
 ******************************************************************************/

void acpi_db_display_resources(char *object_arg)
{
        struct acpi_namespace_node *node;

        acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
        acpi_dbg_level |= ACPI_LV_RESOURCES;

        /* Asterisk means "display resources for all devices" */

        if (!object_arg || (!strcmp(object_arg, "*"))) {
                (void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                                          ACPI_UINT32_MAX,
                                          acpi_db_device_resources, NULL, NULL,
                                          NULL);
        } else {
                /* Convert string to object pointer */

                node = acpi_db_convert_to_node(object_arg);
                if (node) {
                        if (node->type != ACPI_TYPE_DEVICE) {
                                acpi_os_printf
                                    ("%4.4s: Name is not a device object (%s)\n",
                                     node->name.ascii,
                                     acpi_ut_get_type_name(node->type));
                        } else {
                                (void)acpi_db_device_resources(node, 0, NULL,
                                                               NULL);
                        }
                }
        }

        acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_generate_ged
 *
 * PARAMETERS:  ged_arg             - Raw GED number, ascii string
 *
 * RETURN:      None
 *
 * DESCRIPTION: Simulate firing of a GED
 *
 ******************************************************************************/

void acpi_db_generate_interrupt(char *gsiv_arg)
{
        u32 gsiv_number;
        struct acpi_ged_handler_info *ged_info = acpi_gbl_ged_handler_list;

        if (!ged_info) {
                acpi_os_printf("No GED handling present\n");
        }

        gsiv_number = strtoul(gsiv_arg, NULL, 0);

        while (ged_info) {

                if (ged_info->int_id == gsiv_number) {
                        struct acpi_object_list arg_list;
                        union acpi_object arg0;
                        acpi_handle evt_handle = ged_info->evt_method;
                        acpi_status status;

                        acpi_os_printf("Evaluate GED _EVT (GSIV=%d)\n",
                                       gsiv_number);

                        if (!evt_handle) {
                                acpi_os_printf("Undefined _EVT method\n");
                                return;
                        }

                        arg0.integer.type = ACPI_TYPE_INTEGER;
                        arg0.integer.value = gsiv_number;

                        arg_list.count = 1;
                        arg_list.pointer = &arg0;

                        status =
                            acpi_evaluate_object(evt_handle, NULL, &arg_list,
                                                 NULL);
                        if (ACPI_FAILURE(status)) {
                                acpi_os_printf("Could not evaluate _EVT\n");
                                return;
                        }

                }
                ged_info = ged_info->next;
        }
}

#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
 *
 * FUNCTION:    acpi_db_generate_gpe
 *
 * PARAMETERS:  gpe_arg             - Raw GPE number, ascii string
 *              block_arg           - GPE block number, ascii string
 *                                    0 or 1 for FADT GPE blocks
 *
 * RETURN:      None
 *
 * DESCRIPTION: Simulate firing of a GPE
 *
 ******************************************************************************/

void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
{
        u32 block_number = 0;
        u32 gpe_number;
        struct acpi_gpe_event_info *gpe_event_info;

        gpe_number = strtoul(gpe_arg, NULL, 0);

        /*
         * If no block arg, or block arg == 0 or 1, use the FADT-defined
         * GPE blocks.
         */
        if (block_arg) {
                block_number = strtoul(block_arg, NULL, 0);
                if (block_number == 1) {
                        block_number = 0;
                }
        }

        gpe_event_info =
            acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
                                       gpe_number);
        if (!gpe_event_info) {
                acpi_os_printf("Invalid GPE\n");
                return;
        }

        (void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_generate_sci
 *
 * PARAMETERS:  None
 *
 * RETURN:      None
 *
 * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch.
 *
 ******************************************************************************/

void acpi_db_generate_sci(void)
{
        acpi_ev_sci_dispatch();
}

#endif                          /* !ACPI_REDUCED_HARDWARE */

/*******************************************************************************
 *
 * FUNCTION:    acpi_db_trace
 *
 * PARAMETERS:  enable_arg          - ENABLE/AML to enable tracer
 *                                    DISABLE to disable tracer
 *              method_arg          - Method to trace
 *              once_arg            - Whether trace once
 *
 * RETURN:      None
 *
 * DESCRIPTION: Control method tracing facility
 *
 ******************************************************************************/

void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg)
{
        u32 debug_level = 0;
        u32 debug_layer = 0;
        u32 flags = 0;

        acpi_ut_strupr(enable_arg);
        acpi_ut_strupr(once_arg);

        if (method_arg) {
                if (acpi_db_trace_method_name) {
                        ACPI_FREE(acpi_db_trace_method_name);
                        acpi_db_trace_method_name = NULL;
                }

                acpi_db_trace_method_name =
                    ACPI_ALLOCATE(strlen(method_arg) + 1);
                if (!acpi_db_trace_method_name) {
                        acpi_os_printf("Failed to allocate method name (%s)\n",
                                       method_arg);
                        return;
                }

                strcpy(acpi_db_trace_method_name, method_arg);
        }

        if (!strcmp(enable_arg, "ENABLE") ||
            !strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) {
                if (!strcmp(enable_arg, "ENABLE")) {

                        /* Inherit current console settings */

                        debug_level = acpi_gbl_db_console_debug_level;
                        debug_layer = acpi_dbg_layer;
                } else {
                        /* Restrict console output to trace points only */

                        debug_level = ACPI_LV_TRACE_POINT;
                        debug_layer = ACPI_EXECUTER;
                }

                flags = ACPI_TRACE_ENABLED;

                if (!strcmp(enable_arg, "OPCODE")) {
                        flags |= ACPI_TRACE_OPCODE;
                }

                if (once_arg && !strcmp(once_arg, "ONCE")) {
                        flags |= ACPI_TRACE_ONESHOT;
                }
        }

        (void)acpi_debug_trace(acpi_db_trace_method_name,
                               debug_level, debug_layer, flags);
}