linux/drivers/acpi/acpica/nsnames.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/*******************************************************************************
   3 *
   4 * Module Name: nsnames - Name manipulation and search
   5 *
   6 ******************************************************************************/
   7
   8#include <acpi/acpi.h>
   9#include "accommon.h"
  10#include "amlcode.h"
  11#include "acnamesp.h"
  12
  13#define _COMPONENT          ACPI_NAMESPACE
  14ACPI_MODULE_NAME("nsnames")
  15
  16/*******************************************************************************
  17 *
  18 * FUNCTION:    acpi_ns_get_external_pathname
  19 *
  20 * PARAMETERS:  node            - Namespace node whose pathname is needed
  21 *
  22 * RETURN:      Pointer to storage containing the fully qualified name of
  23 *              the node, In external format (name segments separated by path
  24 *              separators.)
  25 *
  26 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
  27 *              for error and debug statements.
  28 *
  29 ******************************************************************************/
  30char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
  31{
  32        char *name_buffer;
  33
  34        ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node);
  35
  36        name_buffer = acpi_ns_get_normalized_pathname(node, FALSE);
  37        return_PTR(name_buffer);
  38}
  39
  40/*******************************************************************************
  41 *
  42 * FUNCTION:    acpi_ns_get_pathname_length
  43 *
  44 * PARAMETERS:  node        - Namespace node
  45 *
  46 * RETURN:      Length of path, including prefix
  47 *
  48 * DESCRIPTION: Get the length of the pathname string for this node
  49 *
  50 ******************************************************************************/
  51
  52acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
  53{
  54        acpi_size size;
  55
  56        /* Validate the Node */
  57
  58        if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
  59                ACPI_ERROR((AE_INFO,
  60                            "Invalid/cached reference target node: %p, descriptor type %d",
  61                            node, ACPI_GET_DESCRIPTOR_TYPE(node)));
  62                return (0);
  63        }
  64
  65        size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE);
  66        return (size);
  67}
  68
  69/*******************************************************************************
  70 *
  71 * FUNCTION:    acpi_ns_handle_to_name
  72 *
  73 * PARAMETERS:  target_handle           - Handle of named object whose name is
  74 *                                        to be found
  75 *              buffer                  - Where the name is returned
  76 *
  77 * RETURN:      Status, Buffer is filled with name if status is AE_OK
  78 *
  79 * DESCRIPTION: Build and return a full namespace name
  80 *
  81 ******************************************************************************/
  82
  83acpi_status
  84acpi_ns_handle_to_name(acpi_handle target_handle, struct acpi_buffer *buffer)
  85{
  86        acpi_status status;
  87        struct acpi_namespace_node *node;
  88        const char *node_name;
  89
  90        ACPI_FUNCTION_TRACE_PTR(ns_handle_to_name, target_handle);
  91
  92        node = acpi_ns_validate_handle(target_handle);
  93        if (!node) {
  94                return_ACPI_STATUS(AE_BAD_PARAMETER);
  95        }
  96
  97        /* Validate/Allocate/Clear caller buffer */
  98
  99        status = acpi_ut_initialize_buffer(buffer, ACPI_PATH_SEGMENT_LENGTH);
 100        if (ACPI_FAILURE(status)) {
 101                return_ACPI_STATUS(status);
 102        }
 103
 104        /* Just copy the ACPI name from the Node and zero terminate it */
 105
 106        node_name = acpi_ut_get_node_name(node);
 107        ACPI_COPY_NAMESEG(buffer->pointer, node_name);
 108        ((char *)buffer->pointer)[ACPI_NAMESEG_SIZE] = 0;
 109
 110        ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%4.4s\n", (char *)buffer->pointer));
 111        return_ACPI_STATUS(AE_OK);
 112}
 113
 114/*******************************************************************************
 115 *
 116 * FUNCTION:    acpi_ns_handle_to_pathname
 117 *
 118 * PARAMETERS:  target_handle           - Handle of named object whose name is
 119 *                                        to be found
 120 *              buffer                  - Where the pathname is returned
 121 *              no_trailing             - Remove trailing '_' for each name
 122 *                                        segment
 123 *
 124 * RETURN:      Status, Buffer is filled with pathname if status is AE_OK
 125 *
 126 * DESCRIPTION: Build and return a full namespace pathname
 127 *
 128 ******************************************************************************/
 129
 130acpi_status
 131acpi_ns_handle_to_pathname(acpi_handle target_handle,
 132                           struct acpi_buffer *buffer, u8 no_trailing)
 133{
 134        acpi_status status;
 135        struct acpi_namespace_node *node;
 136        acpi_size required_size;
 137
 138        ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle);
 139
 140        node = acpi_ns_validate_handle(target_handle);
 141        if (!node) {
 142                return_ACPI_STATUS(AE_BAD_PARAMETER);
 143        }
 144
 145        /* Determine size required for the caller buffer */
 146
 147        required_size =
 148            acpi_ns_build_normalized_path(node, NULL, 0, no_trailing);
 149        if (!required_size) {
 150                return_ACPI_STATUS(AE_BAD_PARAMETER);
 151        }
 152
 153        /* Validate/Allocate/Clear caller buffer */
 154
 155        status = acpi_ut_initialize_buffer(buffer, required_size);
 156        if (ACPI_FAILURE(status)) {
 157                return_ACPI_STATUS(status);
 158        }
 159
 160        /* Build the path in the caller buffer */
 161
 162        (void)acpi_ns_build_normalized_path(node, buffer->pointer,
 163                                            (u32)required_size, no_trailing);
 164
 165        ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n",
 166                          (char *)buffer->pointer, (u32) required_size));
 167        return_ACPI_STATUS(AE_OK);
 168}
 169
 170/*******************************************************************************
 171 *
 172 * FUNCTION:    acpi_ns_build_normalized_path
 173 *
 174 * PARAMETERS:  node        - Namespace node
 175 *              full_path   - Where the path name is returned
 176 *              path_size   - Size of returned path name buffer
 177 *              no_trailing - Remove trailing '_' from each name segment
 178 *
 179 * RETURN:      Return 1 if the AML path is empty, otherwise returning (length
 180 *              of pathname + 1) which means the 'FullPath' contains a trailing
 181 *              null.
 182 *
 183 * DESCRIPTION: Build and return a full namespace pathname.
 184 *              Note that if the size of 'FullPath' isn't large enough to
 185 *              contain the namespace node's path name, the actual required
 186 *              buffer length is returned, and it should be greater than
 187 *              'PathSize'. So callers are able to check the returning value
 188 *              to determine the buffer size of 'FullPath'.
 189 *
 190 ******************************************************************************/
 191
 192u32
 193acpi_ns_build_normalized_path(struct acpi_namespace_node *node,
 194                              char *full_path, u32 path_size, u8 no_trailing)
 195{
 196        u32 length = 0, i;
 197        char name[ACPI_NAMESEG_SIZE];
 198        u8 do_no_trailing;
 199        char c, *left, *right;
 200        struct acpi_namespace_node *next_node;
 201
 202        ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node);
 203
 204#define ACPI_PATH_PUT8(path, size, byte, length)    \
 205        do {                                            \
 206                if ((length) < (size))                      \
 207                {                                           \
 208                        (path)[(length)] = (byte);              \
 209                }                                           \
 210                (length)++;                                 \
 211        } while (0)
 212
 213        /*
 214         * Make sure the path_size is correct, so that we don't need to
 215         * validate both full_path and path_size.
 216         */
 217        if (!full_path) {
 218                path_size = 0;
 219        }
 220
 221        if (!node) {
 222                goto build_trailing_null;
 223        }
 224
 225        next_node = node;
 226        while (next_node && next_node != acpi_gbl_root_node) {
 227                if (next_node != node) {
 228                        ACPI_PATH_PUT8(full_path, path_size,
 229                                       AML_DUAL_NAME_PREFIX, length);
 230                }
 231
 232                ACPI_MOVE_32_TO_32(name, &next_node->name);
 233                do_no_trailing = no_trailing;
 234                for (i = 0; i < 4; i++) {
 235                        c = name[4 - i - 1];
 236                        if (do_no_trailing && c != '_') {
 237                                do_no_trailing = FALSE;
 238                        }
 239                        if (!do_no_trailing) {
 240                                ACPI_PATH_PUT8(full_path, path_size, c, length);
 241                        }
 242                }
 243
 244                next_node = next_node->parent;
 245        }
 246
 247        ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length);
 248
 249        /* Reverse the path string */
 250
 251        if (length <= path_size) {
 252                left = full_path;
 253                right = full_path + length - 1;
 254
 255                while (left < right) {
 256                        c = *left;
 257                        *left++ = *right;
 258                        *right-- = c;
 259                }
 260        }
 261
 262        /* Append the trailing null */
 263
 264build_trailing_null:
 265        ACPI_PATH_PUT8(full_path, path_size, '\0', length);
 266
 267#undef ACPI_PATH_PUT8
 268
 269        return_UINT32(length);
 270}
 271
 272/*******************************************************************************
 273 *
 274 * FUNCTION:    acpi_ns_get_normalized_pathname
 275 *
 276 * PARAMETERS:  node            - Namespace node whose pathname is needed
 277 *              no_trailing     - Remove trailing '_' from each name segment
 278 *
 279 * RETURN:      Pointer to storage containing the fully qualified name of
 280 *              the node, In external format (name segments separated by path
 281 *              separators.)
 282 *
 283 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually
 284 *              for error and debug statements. All trailing '_' will be
 285 *              removed from the full pathname if 'NoTrailing' is specified..
 286 *
 287 ******************************************************************************/
 288
 289char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node,
 290                                      u8 no_trailing)
 291{
 292        char *name_buffer;
 293        acpi_size size;
 294
 295        ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node);
 296
 297        /* Calculate required buffer size based on depth below root */
 298
 299        size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing);
 300        if (!size) {
 301                return_PTR(NULL);
 302        }
 303
 304        /* Allocate a buffer to be returned to caller */
 305
 306        name_buffer = ACPI_ALLOCATE_ZEROED(size);
 307        if (!name_buffer) {
 308                ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size));
 309                return_PTR(NULL);
 310        }
 311
 312        /* Build the path in the allocated buffer */
 313
 314        (void)acpi_ns_build_normalized_path(node, name_buffer, (u32)size,
 315                                            no_trailing);
 316
 317        ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, "%s: Path \"%s\"\n",
 318                              ACPI_GET_FUNCTION_NAME, name_buffer));
 319
 320        return_PTR(name_buffer);
 321}
 322
 323/*******************************************************************************
 324 *
 325 * FUNCTION:    acpi_ns_build_prefixed_pathname
 326 *
 327 * PARAMETERS:  prefix_scope        - Scope/Path that prefixes the internal path
 328 *              internal_path       - Name or path of the namespace node
 329 *
 330 * RETURN:      None
 331 *
 332 * DESCRIPTION: Construct a fully qualified pathname from a concatenation of:
 333 *              1) Path associated with the prefix_scope namespace node
 334 *              2) External path representation of the Internal path
 335 *
 336 ******************************************************************************/
 337
 338char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope,
 339                                      const char *internal_path)
 340{
 341        acpi_status status;
 342        char *full_path = NULL;
 343        char *external_path = NULL;
 344        char *prefix_path = NULL;
 345        acpi_size prefix_path_length = 0;
 346
 347        /* If there is a prefix, get the pathname to it */
 348
 349        if (prefix_scope && prefix_scope->scope.node) {
 350                prefix_path =
 351                    acpi_ns_get_normalized_pathname(prefix_scope->scope.node,
 352                                                    TRUE);
 353                if (prefix_path) {
 354                        prefix_path_length = strlen(prefix_path);
 355                }
 356        }
 357
 358        status = acpi_ns_externalize_name(ACPI_UINT32_MAX, internal_path,
 359                                          NULL, &external_path);
 360        if (ACPI_FAILURE(status)) {
 361                goto cleanup;
 362        }
 363
 364        /* Merge the prefix path and the path. 2 is for one dot and trailing null */
 365
 366        full_path =
 367            ACPI_ALLOCATE_ZEROED(prefix_path_length + strlen(external_path) +
 368                                 2);
 369        if (!full_path) {
 370                goto cleanup;
 371        }
 372
 373        /* Don't merge if the External path is already fully qualified */
 374
 375        if (prefix_path && (*external_path != '\\') && (*external_path != '^')) {
 376                strcat(full_path, prefix_path);
 377                if (prefix_path[1]) {
 378                        strcat(full_path, ".");
 379                }
 380        }
 381
 382        acpi_ns_normalize_pathname(external_path);
 383        strcat(full_path, external_path);
 384
 385cleanup:
 386        if (prefix_path) {
 387                ACPI_FREE(prefix_path);
 388        }
 389        if (external_path) {
 390                ACPI_FREE(external_path);
 391        }
 392
 393        return (full_path);
 394}
 395
 396/*******************************************************************************
 397 *
 398 * FUNCTION:    acpi_ns_normalize_pathname
 399 *
 400 * PARAMETERS:  original_path       - Path to be normalized, in External format
 401 *
 402 * RETURN:      The original path is processed in-place
 403 *
 404 * DESCRIPTION: Remove trailing underscores from each element of a path.
 405 *
 406 *              For example:  \A___.B___.C___ becomes \A.B.C
 407 *
 408 ******************************************************************************/
 409
 410void acpi_ns_normalize_pathname(char *original_path)
 411{
 412        char *input_path = original_path;
 413        char *new_path_buffer;
 414        char *new_path;
 415        u32 i;
 416
 417        /* Allocate a temp buffer in which to construct the new path */
 418
 419        new_path_buffer = ACPI_ALLOCATE_ZEROED(strlen(input_path) + 1);
 420        new_path = new_path_buffer;
 421        if (!new_path_buffer) {
 422                return;
 423        }
 424
 425        /* Special characters may appear at the beginning of the path */
 426
 427        if (*input_path == '\\') {
 428                *new_path = *input_path;
 429                new_path++;
 430                input_path++;
 431        }
 432
 433        while (*input_path == '^') {
 434                *new_path = *input_path;
 435                new_path++;
 436                input_path++;
 437        }
 438
 439        /* Remainder of the path */
 440
 441        while (*input_path) {
 442
 443                /* Do one nameseg at a time */
 444
 445                for (i = 0; (i < ACPI_NAMESEG_SIZE) && *input_path; i++) {
 446                        if ((i == 0) || (*input_path != '_')) { /* First char is allowed to be underscore */
 447                                *new_path = *input_path;
 448                                new_path++;
 449                        }
 450
 451                        input_path++;
 452                }
 453
 454                /* Dot means that there are more namesegs to come */
 455
 456                if (*input_path == '.') {
 457                        *new_path = *input_path;
 458                        new_path++;
 459                        input_path++;
 460                }
 461        }
 462
 463        *new_path = 0;
 464        strcpy(original_path, new_path_buffer);
 465        ACPI_FREE(new_path_buffer);
 466}
 467