Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / acpi / acpica / nsnames.c
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
14 ACPI_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  ******************************************************************************/
30 char *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
52 acpi_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
83 acpi_status
84 acpi_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
130 acpi_status
131 acpi_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                                             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
192 u32
193 acpi_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
264 build_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
289 char *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, 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
338 char *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         u32 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
385 cleanup:
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
410 void 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 }