467 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: nsnames - Name manipulation and search5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "amlcode.h"11#include "acnamesp.h"12 13#define _COMPONENT ACPI_NAMESPACE14ACPI_MODULE_NAME("nsnames")15 16/*******************************************************************************17 *18 * FUNCTION: acpi_ns_get_external_pathname19 *20 * PARAMETERS: node - Namespace node whose pathname is needed21 *22 * RETURN: Pointer to storage containing the fully qualified name of23 * the node, In external format (name segments separated by path24 * separators.)25 *26 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually27 * 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_length43 *44 * PARAMETERS: node - Namespace node45 *46 * RETURN: Length of path, including prefix47 *48 * DESCRIPTION: Get the length of the pathname string for this node49 *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_name72 *73 * PARAMETERS: target_handle - Handle of named object whose name is74 * to be found75 * buffer - Where the name is returned76 *77 * RETURN: Status, Buffer is filled with name if status is AE_OK78 *79 * DESCRIPTION: Build and return a full namespace name80 *81 ******************************************************************************/82 83acpi_status84acpi_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_pathname117 *118 * PARAMETERS: target_handle - Handle of named object whose name is119 * to be found120 * buffer - Where the pathname is returned121 * no_trailing - Remove trailing '_' for each name122 * segment123 *124 * RETURN: Status, Buffer is filled with pathname if status is AE_OK125 *126 * DESCRIPTION: Build and return a full namespace pathname127 *128 ******************************************************************************/129 130acpi_status131acpi_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_path173 *174 * PARAMETERS: node - Namespace node175 * full_path - Where the path name is returned176 * path_size - Size of returned path name buffer177 * no_trailing - Remove trailing '_' from each name segment178 *179 * RETURN: Return 1 if the AML path is empty, otherwise returning (length180 * of pathname + 1) which means the 'FullPath' contains a trailing181 * null.182 *183 * DESCRIPTION: Build and return a full namespace pathname.184 * Note that if the size of 'FullPath' isn't large enough to185 * contain the namespace node's path name, the actual required186 * buffer length is returned, and it should be greater than187 * 'PathSize'. So callers are able to check the returning value188 * to determine the buffer size of 'FullPath'.189 *190 ******************************************************************************/191 192u32193acpi_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 to215 * 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_PUT8268 269 return_UINT32(length);270}271 272/*******************************************************************************273 *274 * FUNCTION: acpi_ns_get_normalized_pathname275 *276 * PARAMETERS: node - Namespace node whose pathname is needed277 * no_trailing - Remove trailing '_' from each name segment278 *279 * RETURN: Pointer to storage containing the fully qualified name of280 * the node, In external format (name segments separated by path281 * separators.)282 *283 * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually284 * for error and debug statements. All trailing '_' will be285 * 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_pathname326 *327 * PARAMETERS: prefix_scope - Scope/Path that prefixes the internal path328 * internal_path - Name or path of the namespace node329 *330 * RETURN: None331 *332 * DESCRIPTION: Construct a fully qualified pathname from a concatenation of:333 * 1) Path associated with the prefix_scope namespace node334 * 2) External path representation of the Internal path335 *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_pathname399 *400 * PARAMETERS: original_path - Path to be normalized, in External format401 *402 * RETURN: The original path is processed in-place403 *404 * DESCRIPTION: Remove trailing underscores from each element of a path.405 *406 * For example: \A___.B___.C___ becomes \A.B.C407 *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