linux/drivers/acpi/acpica/nsxfname.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: nsxfname - Public interfaces to the ACPI subsystem
   5 *                         ACPI Namespace oriented interfaces
   6 *
   7 * Copyright (C) 2000 - 2021, Intel Corp.
   8 *
   9 *****************************************************************************/
  10
  11#define EXPORT_ACPI_INTERFACES
  12
  13#include <acpi/acpi.h>
  14#include "accommon.h"
  15#include "acnamesp.h"
  16#include "acparser.h"
  17#include "amlcode.h"
  18
  19#define _COMPONENT          ACPI_NAMESPACE
  20ACPI_MODULE_NAME("nsxfname")
  21
  22/* Local prototypes */
  23static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
  24                                    struct acpi_pnp_device_id *source,
  25                                    char *string_area);
  26
  27/******************************************************************************
  28 *
  29 * FUNCTION:    acpi_get_handle
  30 *
  31 * PARAMETERS:  parent          - Object to search under (search scope).
  32 *              pathname        - Pointer to an asciiz string containing the
  33 *                                name
  34 *              ret_handle      - Where the return handle is returned
  35 *
  36 * RETURN:      Status
  37 *
  38 * DESCRIPTION: This routine will search for a caller specified name in the
  39 *              name space. The caller can restrict the search region by
  40 *              specifying a non NULL parent. The parent value is itself a
  41 *              namespace handle.
  42 *
  43 ******************************************************************************/
  44
  45acpi_status
  46acpi_get_handle(acpi_handle parent,
  47                acpi_string pathname, acpi_handle *ret_handle)
  48{
  49        acpi_status status;
  50        struct acpi_namespace_node *node = NULL;
  51        struct acpi_namespace_node *prefix_node = NULL;
  52
  53        ACPI_FUNCTION_ENTRY();
  54
  55        /* Parameter Validation */
  56
  57        if (!ret_handle || !pathname) {
  58                return (AE_BAD_PARAMETER);
  59        }
  60
  61        /* Convert a parent handle to a prefix node */
  62
  63        if (parent) {
  64                prefix_node = acpi_ns_validate_handle(parent);
  65                if (!prefix_node) {
  66                        return (AE_BAD_PARAMETER);
  67                }
  68        }
  69
  70        /*
  71         * Valid cases are:
  72         * 1) Fully qualified pathname
  73         * 2) Parent + Relative pathname
  74         *
  75         * Error for <null Parent + relative path>
  76         */
  77        if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
  78
  79                /* Pathname is fully qualified (starts with '\') */
  80
  81                /* Special case for root-only, since we can't search for it */
  82
  83                if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) {
  84                        *ret_handle =
  85                            ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);
  86                        return (AE_OK);
  87                }
  88        } else if (!prefix_node) {
  89
  90                /* Relative path with null prefix is disallowed */
  91
  92                return (AE_BAD_PARAMETER);
  93        }
  94
  95        /* Find the Node and convert to a handle */
  96
  97        status =
  98            acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
  99        if (ACPI_SUCCESS(status)) {
 100                *ret_handle = ACPI_CAST_PTR(acpi_handle, node);
 101        }
 102
 103        return (status);
 104}
 105
 106ACPI_EXPORT_SYMBOL(acpi_get_handle)
 107
 108/******************************************************************************
 109 *
 110 * FUNCTION:    acpi_get_name
 111 *
 112 * PARAMETERS:  handle          - Handle to be converted to a pathname
 113 *              name_type       - Full pathname or single segment
 114 *              buffer          - Buffer for returned path
 115 *
 116 * RETURN:      Pointer to a string containing the fully qualified Name.
 117 *
 118 * DESCRIPTION: This routine returns the fully qualified name associated with
 119 *              the Handle parameter. This and the acpi_pathname_to_handle are
 120 *              complementary functions.
 121 *
 122 ******************************************************************************/
 123acpi_status
 124acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer)
 125{
 126        acpi_status status;
 127
 128        /* Parameter validation */
 129
 130        if (name_type > ACPI_NAME_TYPE_MAX) {
 131                return (AE_BAD_PARAMETER);
 132        }
 133
 134        status = acpi_ut_validate_buffer(buffer);
 135        if (ACPI_FAILURE(status)) {
 136                return (status);
 137        }
 138
 139        /*
 140         * Wants the single segment ACPI name.
 141         * Validate handle and convert to a namespace Node
 142         */
 143        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 144        if (ACPI_FAILURE(status)) {
 145                return (status);
 146        }
 147
 148        if (name_type == ACPI_FULL_PATHNAME ||
 149            name_type == ACPI_FULL_PATHNAME_NO_TRAILING) {
 150
 151                /* Get the full pathname (From the namespace root) */
 152
 153                status = acpi_ns_handle_to_pathname(handle, buffer,
 154                                                    name_type ==
 155                                                    ACPI_FULL_PATHNAME ? FALSE :
 156                                                    TRUE);
 157        } else {
 158                /* Get the single name */
 159
 160                status = acpi_ns_handle_to_name(handle, buffer);
 161        }
 162
 163        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 164        return (status);
 165}
 166
 167ACPI_EXPORT_SYMBOL(acpi_get_name)
 168
 169/******************************************************************************
 170 *
 171 * FUNCTION:    acpi_ns_copy_device_id
 172 *
 173 * PARAMETERS:  dest                - Pointer to the destination PNP_DEVICE_ID
 174 *              source              - Pointer to the source PNP_DEVICE_ID
 175 *              string_area         - Pointer to where to copy the dest string
 176 *
 177 * RETURN:      Pointer to the next string area
 178 *
 179 * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data.
 180 *
 181 ******************************************************************************/
 182static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
 183                                    struct acpi_pnp_device_id *source,
 184                                    char *string_area)
 185{
 186        /* Create the destination PNP_DEVICE_ID */
 187
 188        dest->string = string_area;
 189        dest->length = source->length;
 190
 191        /* Copy actual string and return a pointer to the next string area */
 192
 193        memcpy(string_area, source->string, source->length);
 194        return (string_area + source->length);
 195}
 196
 197/******************************************************************************
 198 *
 199 * FUNCTION:    acpi_get_object_info
 200 *
 201 * PARAMETERS:  handle              - Object Handle
 202 *              return_buffer       - Where the info is returned
 203 *
 204 * RETURN:      Status
 205 *
 206 * DESCRIPTION: Returns information about an object as gleaned from the
 207 *              namespace node and possibly by running several standard
 208 *              control methods (Such as in the case of a device.)
 209 *
 210 * For Device and Processor objects, run the Device _HID, _UID, _CID,
 211 * _CLS, _ADR, _sx_w, and _sx_d methods.
 212 *
 213 * Note: Allocates the return buffer, must be freed by the caller.
 214 *
 215 * Note: This interface is intended to be used during the initial device
 216 * discovery namespace traversal. Therefore, no complex methods can be
 217 * executed, especially those that access operation regions. Therefore, do
 218 * not add any additional methods that could cause problems in this area.
 219 * Because of this reason support for the following methods has been removed:
 220 * 1) _SUB method was removed (11/2015)
 221 * 2) _STA method was removed (02/2018)
 222 *
 223 ******************************************************************************/
 224
 225acpi_status
 226acpi_get_object_info(acpi_handle handle,
 227                     struct acpi_device_info **return_buffer)
 228{
 229        struct acpi_namespace_node *node;
 230        struct acpi_device_info *info;
 231        struct acpi_pnp_device_id_list *cid_list = NULL;
 232        struct acpi_pnp_device_id *hid = NULL;
 233        struct acpi_pnp_device_id *uid = NULL;
 234        struct acpi_pnp_device_id *cls = NULL;
 235        char *next_id_string;
 236        acpi_object_type type;
 237        acpi_name name;
 238        u8 param_count = 0;
 239        u16 valid = 0;
 240        u32 info_size;
 241        u32 i;
 242        acpi_status status;
 243
 244        /* Parameter validation */
 245
 246        if (!handle || !return_buffer) {
 247                return (AE_BAD_PARAMETER);
 248        }
 249
 250        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 251        if (ACPI_FAILURE(status)) {
 252                return (status);
 253        }
 254
 255        node = acpi_ns_validate_handle(handle);
 256        if (!node) {
 257                (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 258                return (AE_BAD_PARAMETER);
 259        }
 260
 261        /* Get the namespace node data while the namespace is locked */
 262
 263        info_size = sizeof(struct acpi_device_info);
 264        type = node->type;
 265        name = node->name.integer;
 266
 267        if (node->type == ACPI_TYPE_METHOD) {
 268                param_count = node->object->method.param_count;
 269        }
 270
 271        status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 272        if (ACPI_FAILURE(status)) {
 273                return (status);
 274        }
 275
 276        if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
 277                /*
 278                 * Get extra info for ACPI Device/Processor objects only:
 279                 * Run the Device _HID, _UID, _CLS, and _CID methods.
 280                 *
 281                 * Note: none of these methods are required, so they may or may
 282                 * not be present for this device. The Info->Valid bitfield is used
 283                 * to indicate which methods were found and run successfully.
 284                 */
 285
 286                /* Execute the Device._HID method */
 287
 288                status = acpi_ut_execute_HID(node, &hid);
 289                if (ACPI_SUCCESS(status)) {
 290                        info_size += hid->length;
 291                        valid |= ACPI_VALID_HID;
 292                }
 293
 294                /* Execute the Device._UID method */
 295
 296                status = acpi_ut_execute_UID(node, &uid);
 297                if (ACPI_SUCCESS(status)) {
 298                        info_size += uid->length;
 299                        valid |= ACPI_VALID_UID;
 300                }
 301
 302                /* Execute the Device._CID method */
 303
 304                status = acpi_ut_execute_CID(node, &cid_list);
 305                if (ACPI_SUCCESS(status)) {
 306
 307                        /* Add size of CID strings and CID pointer array */
 308
 309                        info_size +=
 310                            (cid_list->list_size -
 311                             sizeof(struct acpi_pnp_device_id_list));
 312                        valid |= ACPI_VALID_CID;
 313                }
 314
 315                /* Execute the Device._CLS method */
 316
 317                status = acpi_ut_execute_CLS(node, &cls);
 318                if (ACPI_SUCCESS(status)) {
 319                        info_size += cls->length;
 320                        valid |= ACPI_VALID_CLS;
 321                }
 322        }
 323
 324        /*
 325         * Now that we have the variable-length data, we can allocate the
 326         * return buffer
 327         */
 328        info = ACPI_ALLOCATE_ZEROED(info_size);
 329        if (!info) {
 330                status = AE_NO_MEMORY;
 331                goto cleanup;
 332        }
 333
 334        /* Get the fixed-length data */
 335
 336        if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
 337                /*
 338                 * Get extra info for ACPI Device/Processor objects only:
 339                 * Run the _ADR and, sx_w, and _sx_d methods.
 340                 *
 341                 * Notes: none of these methods are required, so they may or may
 342                 * not be present for this device. The Info->Valid bitfield is used
 343                 * to indicate which methods were found and run successfully.
 344                 */
 345
 346                /* Execute the Device._ADR method */
 347
 348                status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
 349                                                         &info->address);
 350                if (ACPI_SUCCESS(status)) {
 351                        valid |= ACPI_VALID_ADR;
 352                }
 353
 354                /* Execute the Device._sx_w methods */
 355
 356                status = acpi_ut_execute_power_methods(node,
 357                                                       acpi_gbl_lowest_dstate_names,
 358                                                       ACPI_NUM_sx_w_METHODS,
 359                                                       info->lowest_dstates);
 360                if (ACPI_SUCCESS(status)) {
 361                        valid |= ACPI_VALID_SXWS;
 362                }
 363
 364                /* Execute the Device._sx_d methods */
 365
 366                status = acpi_ut_execute_power_methods(node,
 367                                                       acpi_gbl_highest_dstate_names,
 368                                                       ACPI_NUM_sx_d_METHODS,
 369                                                       info->highest_dstates);
 370                if (ACPI_SUCCESS(status)) {
 371                        valid |= ACPI_VALID_SXDS;
 372                }
 373        }
 374
 375        /*
 376         * Create a pointer to the string area of the return buffer.
 377         * Point to the end of the base struct acpi_device_info structure.
 378         */
 379        next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
 380        if (cid_list) {
 381
 382                /* Point past the CID PNP_DEVICE_ID array */
 383
 384                next_id_string +=
 385                    ((acpi_size)cid_list->count *
 386                     sizeof(struct acpi_pnp_device_id));
 387        }
 388
 389        /*
 390         * Copy the HID, UID, and CIDs to the return buffer. The variable-length
 391         * strings are copied to the reserved area at the end of the buffer.
 392         *
 393         * For HID and CID, check if the ID is a PCI Root Bridge.
 394         */
 395        if (hid) {
 396                next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
 397                                                        hid, next_id_string);
 398
 399                if (acpi_ut_is_pci_root_bridge(hid->string)) {
 400                        info->flags |= ACPI_PCI_ROOT_BRIDGE;
 401                }
 402        }
 403
 404        if (uid) {
 405                next_id_string = acpi_ns_copy_device_id(&info->unique_id,
 406                                                        uid, next_id_string);
 407        }
 408
 409        if (cid_list) {
 410                info->compatible_id_list.count = cid_list->count;
 411                info->compatible_id_list.list_size = cid_list->list_size;
 412
 413                /* Copy each CID */
 414
 415                for (i = 0; i < cid_list->count; i++) {
 416                        next_id_string =
 417                            acpi_ns_copy_device_id(&info->compatible_id_list.
 418                                                   ids[i], &cid_list->ids[i],
 419                                                   next_id_string);
 420
 421                        if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
 422                                info->flags |= ACPI_PCI_ROOT_BRIDGE;
 423                        }
 424                }
 425        }
 426
 427        if (cls) {
 428                (void)acpi_ns_copy_device_id(&info->class_code,
 429                                             cls, next_id_string);
 430        }
 431
 432        /* Copy the fixed-length data */
 433
 434        info->info_size = info_size;
 435        info->type = type;
 436        info->name = name;
 437        info->param_count = param_count;
 438        info->valid = valid;
 439
 440        *return_buffer = info;
 441        status = AE_OK;
 442
 443cleanup:
 444        if (hid) {
 445                ACPI_FREE(hid);
 446        }
 447        if (uid) {
 448                ACPI_FREE(uid);
 449        }
 450        if (cid_list) {
 451                ACPI_FREE(cid_list);
 452        }
 453        if (cls) {
 454                ACPI_FREE(cls);
 455        }
 456        return (status);
 457}
 458
 459ACPI_EXPORT_SYMBOL(acpi_get_object_info)
 460
 461/******************************************************************************
 462 *
 463 * FUNCTION:    acpi_install_method
 464 *
 465 * PARAMETERS:  buffer         - An ACPI table containing one control method
 466 *
 467 * RETURN:      Status
 468 *
 469 * DESCRIPTION: Install a control method into the namespace. If the method
 470 *              name already exists in the namespace, it is overwritten. The
 471 *              input buffer must contain a valid DSDT or SSDT containing a
 472 *              single control method.
 473 *
 474 ******************************************************************************/
 475acpi_status acpi_install_method(u8 *buffer)
 476{
 477        struct acpi_table_header *table =
 478            ACPI_CAST_PTR(struct acpi_table_header, buffer);
 479        u8 *aml_buffer;
 480        u8 *aml_start;
 481        char *path;
 482        struct acpi_namespace_node *node;
 483        union acpi_operand_object *method_obj;
 484        struct acpi_parse_state parser_state;
 485        u32 aml_length;
 486        u16 opcode;
 487        u8 method_flags;
 488        acpi_status status;
 489
 490        /* Parameter validation */
 491
 492        if (!buffer) {
 493                return (AE_BAD_PARAMETER);
 494        }
 495
 496        /* Table must be a DSDT or SSDT */
 497
 498        if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) &&
 499            !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) {
 500                return (AE_BAD_HEADER);
 501        }
 502
 503        /* First AML opcode in the table must be a control method */
 504
 505        parser_state.aml = buffer + sizeof(struct acpi_table_header);
 506        opcode = acpi_ps_peek_opcode(&parser_state);
 507        if (opcode != AML_METHOD_OP) {
 508                return (AE_BAD_PARAMETER);
 509        }
 510
 511        /* Extract method information from the raw AML */
 512
 513        parser_state.aml += acpi_ps_get_opcode_size(opcode);
 514        parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
 515        path = acpi_ps_get_next_namestring(&parser_state);
 516
 517        method_flags = *parser_state.aml++;
 518        aml_start = parser_state.aml;
 519        aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
 520
 521        /*
 522         * Allocate resources up-front. We don't want to have to delete a new
 523         * node from the namespace if we cannot allocate memory.
 524         */
 525        aml_buffer = ACPI_ALLOCATE(aml_length);
 526        if (!aml_buffer) {
 527                return (AE_NO_MEMORY);
 528        }
 529
 530        method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
 531        if (!method_obj) {
 532                ACPI_FREE(aml_buffer);
 533                return (AE_NO_MEMORY);
 534        }
 535
 536        /* Lock namespace for acpi_ns_lookup, we may be creating a new node */
 537
 538        status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 539        if (ACPI_FAILURE(status)) {
 540                goto error_exit;
 541        }
 542
 543        /* The lookup either returns an existing node or creates a new one */
 544
 545        status =
 546            acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
 547                           ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
 548                           NULL, &node);
 549
 550        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 551
 552        if (ACPI_FAILURE(status)) {     /* ns_lookup */
 553                if (status != AE_ALREADY_EXISTS) {
 554                        goto error_exit;
 555                }
 556
 557                /* Node existed previously, make sure it is a method node */
 558
 559                if (node->type != ACPI_TYPE_METHOD) {
 560                        status = AE_TYPE;
 561                        goto error_exit;
 562                }
 563        }
 564
 565        /* Copy the method AML to the local buffer */
 566
 567        memcpy(aml_buffer, aml_start, aml_length);
 568
 569        /* Initialize the method object with the new method's information */
 570
 571        method_obj->method.aml_start = aml_buffer;
 572        method_obj->method.aml_length = aml_length;
 573
 574        method_obj->method.param_count = (u8)
 575            (method_flags & AML_METHOD_ARG_COUNT);
 576
 577        if (method_flags & AML_METHOD_SERIALIZED) {
 578                method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
 579
 580                method_obj->method.sync_level = (u8)
 581                    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
 582        }
 583
 584        /*
 585         * Now that it is complete, we can attach the new method object to
 586         * the method Node (detaches/deletes any existing object)
 587         */
 588        status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
 589
 590        /*
 591         * Flag indicates AML buffer is dynamic, must be deleted later.
 592         * Must be set only after attach above.
 593         */
 594        node->flags |= ANOBJ_ALLOCATED_BUFFER;
 595
 596        /* Remove local reference to the method object */
 597
 598        acpi_ut_remove_reference(method_obj);
 599        return (status);
 600
 601error_exit:
 602
 603        ACPI_FREE(aml_buffer);
 604        ACPI_FREE(method_obj);
 605        return (status);
 606}
 607ACPI_EXPORT_SYMBOL(acpi_install_method)
 608