1 /******************************************************************************
3 * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
4 * parents and siblings and Scope manipulation
7 *****************************************************************************/
10 * Copyright (C) 2000, 2001 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #define _COMPONENT ACPI_NAMESPACE
31 MODULE_NAME ("nsutils")
34 /****************************************************************************
36 * FUNCTION: Acpi_ns_valid_root_prefix
38 * PARAMETERS: Prefix - Character to be checked
40 * RETURN: TRUE if a valid prefix
42 * DESCRIPTION: Check if a character is a valid ACPI Root prefix
44 ***************************************************************************/
47 acpi_ns_valid_root_prefix (
51 return ((u8
) (prefix
== '\\'));
55 /****************************************************************************
57 * FUNCTION: Acpi_ns_valid_path_separator
59 * PARAMETERS: Sep - Character to be checked
61 * RETURN: TRUE if a valid path separator
63 * DESCRIPTION: Check if a character is a valid ACPI path separator
65 ***************************************************************************/
68 acpi_ns_valid_path_separator (
72 return ((u8
) (sep
== '.'));
76 /****************************************************************************
78 * FUNCTION: Acpi_ns_get_type
80 * PARAMETERS: Handle - Parent Node to be examined
82 * RETURN: Type field from Node whose handle is passed
84 ***************************************************************************/
92 REPORT_WARNING (("Ns_get_type: Null handle\n"));
93 return (ACPI_TYPE_ANY
);
96 return (((ACPI_NAMESPACE_NODE
*) handle
)->type
);
100 /****************************************************************************
102 * FUNCTION: Acpi_ns_local
104 * PARAMETERS: Type - A namespace object type
106 * RETURN: LOCAL if names must be found locally in objects of the
107 * passed type, 0 if enclosing scopes should be searched
109 ***************************************************************************/
113 OBJECT_TYPE_INTERNAL type
)
116 if (!acpi_cm_valid_object_type (type
)) {
117 /* Type code out of range */
119 REPORT_WARNING (("Ns_local: Invalid Object Type\n"));
123 return ((u32
) acpi_gbl_ns_properties
[type
] & NSP_LOCAL
);
127 /****************************************************************************
129 * FUNCTION: Acpi_ns_internalize_name
131 * PARAMETERS: *External_name - External representation of name
132 * **Converted Name - Where to return the resulting
133 * internal represention of the name
137 * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
138 * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
140 ****************************************************************************/
143 acpi_ns_internalize_name (
144 NATIVE_CHAR
*external_name
,
145 NATIVE_CHAR
**converted_name
)
147 NATIVE_CHAR
*result
= NULL
;
148 NATIVE_CHAR
*internal_name
;
149 u32 num_segments
= 0;
150 u8 fully_qualified
= FALSE
;
155 if ((!external_name
) ||
156 (*external_name
== 0) ||
158 return (AE_BAD_PARAMETER
);
163 * For the internal name, the required length is 4 bytes
164 * per segment, plus 1 each for Root_prefix, Multi_name_prefix_op,
165 * segment count, trailing null (which is not really needed,
166 * but no there's harm in putting it there)
168 * strlen() + 1 covers the first Name_seg, which has no
172 if (acpi_ns_valid_root_prefix (external_name
[0])) {
173 fully_qualified
= TRUE
;
179 * Handle Carat prefixes
182 while (*external_name
== '^') {
189 * Determine the number of ACPI name "segments" by counting
190 * the number of path separators within the string. Start
191 * with one segment since the segment count is (# separators)
192 * + 1, and zero separators is ok.
195 if (*external_name
) {
197 for (i
= 0; external_name
[i
]; i
++) {
198 if (acpi_ns_valid_path_separator (external_name
[i
])) {
205 /* We need a segment to store the internal version of the name */
207 internal_name
= acpi_cm_callocate ((ACPI_NAME_SIZE
* num_segments
) + 4 + num_carats
);
208 if (!internal_name
) {
209 return (AE_NO_MEMORY
);
213 /* Setup the correct prefixes, counts, and pointers */
215 if (fully_qualified
) {
216 internal_name
[0] = '\\';
218 if (num_segments
<= 1) {
219 result
= &internal_name
[1];
221 else if (num_segments
== 2) {
222 internal_name
[1] = AML_DUAL_NAME_PREFIX
;
223 result
= &internal_name
[2];
226 internal_name
[1] = AML_MULTI_NAME_PREFIX_OP
;
227 internal_name
[2] = (char) num_segments
;
228 result
= &internal_name
[3];
235 * Not fully qualified.
236 * Handle Carats first, then append the name segments
241 for (i
= 0; i
< num_carats
; i
++) {
242 internal_name
[i
] = '^';
246 if (num_segments
== 1) {
247 result
= &internal_name
[i
];
250 else if (num_segments
== 2) {
251 internal_name
[i
] = AML_DUAL_NAME_PREFIX
;
252 result
= &internal_name
[i
+1];
256 internal_name
[i
] = AML_MULTI_NAME_PREFIX_OP
;
257 internal_name
[i
+1] = (char) num_segments
;
258 result
= &internal_name
[i
+2];
263 /* Build the name (minus path separators) */
265 for (; num_segments
; num_segments
--) {
266 for (i
= 0; i
< ACPI_NAME_SIZE
; i
++) {
267 if (acpi_ns_valid_path_separator (*external_name
) ||
268 (*external_name
== 0)) {
270 * Pad the segment with underscore(s) if
278 /* Convert s8 to uppercase and save it */
280 result
[i
] = (char) TOUPPER (*external_name
);
286 /* Now we must have a path separator, or the pathname is bad */
288 if (!acpi_ns_valid_path_separator (*external_name
) &&
289 (*external_name
!= 0)) {
290 acpi_cm_free (internal_name
);
291 return (AE_BAD_PARAMETER
);
294 /* Move on the next segment */
297 result
+= ACPI_NAME_SIZE
;
301 /* Return the completed name */
303 /* Terminate the string! */
305 *converted_name
= internal_name
;
313 /****************************************************************************
315 * FUNCTION: Acpi_ns_externalize_name
317 * PARAMETERS: *Internal_name - Internal representation of name
318 * **Converted_name - Where to return the resulting
319 * external representation of name
323 * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
324 * to its external form (e.g. "\_PR_.CPU0")
326 ****************************************************************************/
329 acpi_ns_externalize_name (
330 u32 internal_name_length
,
332 u32
*converted_name_length
,
333 char **converted_name
)
335 u32 prefix_length
= 0;
342 if (!internal_name_length
||
344 !converted_name_length
||
346 return (AE_BAD_PARAMETER
);
351 * Check for a prefix (one '\' | one or more '^').
353 switch (internal_name
[0]) {
359 for (i
= 0; i
< internal_name_length
; i
++) {
360 if (internal_name
[i
] != '^') {
361 prefix_length
= i
+ 1;
365 if (i
== internal_name_length
) {
373 * Check for object names. Note that there could be 0-255 of these
376 if (prefix_length
< internal_name_length
) {
377 switch (internal_name
[prefix_length
]) {
379 /* <count> 4-byte names */
381 case AML_MULTI_NAME_PREFIX_OP
:
382 names_index
= prefix_length
+ 2;
383 names_count
= (u32
) internal_name
[prefix_length
+ 1];
387 /* two 4-byte names */
389 case AML_DUAL_NAME_PREFIX
:
390 names_index
= prefix_length
+ 1;
403 /* one 4-byte name */
406 names_index
= prefix_length
;
413 * Calculate the length of Converted_name, which equals the length
414 * of the prefix, length of all object names, length of any required
415 * punctuation ('.') between object names, plus the NULL terminator.
417 *converted_name_length
= prefix_length
+ (4 * names_count
) +
418 ((names_count
> 0) ? (names_count
- 1) : 0) + 1;
421 * Check to see if we're still in bounds. If not, there's a problem
422 * with Internal_name (invalid format).
424 if (*converted_name_length
> internal_name_length
) {
425 REPORT_ERROR (("Ns_externalize_name: Invalid internal name\n"));
426 return (AE_BAD_PATHNAME
);
430 * Build Converted_name...
433 (*converted_name
) = acpi_cm_callocate (*converted_name_length
);
434 if (!(*converted_name
)) {
435 return (AE_NO_MEMORY
);
440 for (i
= 0; i
< prefix_length
; i
++) {
441 (*converted_name
)[j
++] = internal_name
[i
];
444 if (names_count
> 0) {
445 for (i
= 0; i
< names_count
; i
++) {
447 (*converted_name
)[j
++] = '.';
450 (*converted_name
)[j
++] = internal_name
[names_index
++];
451 (*converted_name
)[j
++] = internal_name
[names_index
++];
452 (*converted_name
)[j
++] = internal_name
[names_index
++];
453 (*converted_name
)[j
++] = internal_name
[names_index
++];
461 /****************************************************************************
463 * FUNCTION: Acpi_ns_convert_handle_to_entry
465 * PARAMETERS: Handle - Handle to be converted to an Node
467 * RETURN: A Name table entry pointer
469 * DESCRIPTION: Convert a namespace handle to a real Node
471 ****************************************************************************/
473 ACPI_NAMESPACE_NODE
*
474 acpi_ns_convert_handle_to_entry (
479 * Simple implementation for now;
480 * TBD: [Future] Real integer handles allow for more verification
481 * and keep all pointers within this subsystem!
488 if (handle
== ACPI_ROOT_OBJECT
) {
489 return (acpi_gbl_root_node
);
493 /* We can at least attempt to verify the handle */
495 if (!VALID_DESCRIPTOR_TYPE (handle
, ACPI_DESC_TYPE_NAMED
)) {
499 return ((ACPI_NAMESPACE_NODE
*) handle
);
503 /****************************************************************************
505 * FUNCTION: Acpi_ns_convert_entry_to_handle
507 * PARAMETERS: Node - Node to be converted to a Handle
509 * RETURN: An USER ACPI_HANDLE
511 * DESCRIPTION: Convert a real Node to a namespace handle
513 ****************************************************************************/
516 acpi_ns_convert_entry_to_handle (
517 ACPI_NAMESPACE_NODE
*node
)
522 * Simple implementation for now;
523 * TBD: [Future] Real integer handles allow for more verification
524 * and keep all pointers within this subsystem!
527 return ((ACPI_HANDLE
) node
);
530 /* ---------------------------------------------------
537 if (Node == Acpi_gbl_Root_node)
539 return (ACPI_ROOT_OBJECT);
543 return ((ACPI_HANDLE) Node);
544 ------------------------------------------------------*/
548 /******************************************************************************
550 * FUNCTION: Acpi_ns_terminate
556 * DESCRIPTION: free memory allocated for table storage.
558 ******************************************************************************/
561 acpi_ns_terminate (void)
563 ACPI_OPERAND_OBJECT
*obj_desc
;
564 ACPI_NAMESPACE_NODE
*this_node
;
567 this_node
= acpi_gbl_root_node
;
570 * 1) Free the entire namespace -- all objects, tables, and stacks
573 * Delete all objects linked to the root
574 * (additional table descriptors)
577 acpi_ns_delete_namespace_subtree (this_node
);
579 /* Detach any object(s) attached to the root */
581 obj_desc
= acpi_ns_get_attached_object (this_node
);
583 acpi_ns_detach_object (this_node
);
584 acpi_cm_remove_reference (obj_desc
);
587 acpi_ns_delete_children (this_node
);
591 * 2) Now we can delete the ACPI tables
594 acpi_tb_delete_acpi_tables ();
600 /****************************************************************************
602 * FUNCTION: Acpi_ns_opens_scope
604 * PARAMETERS: Type - A valid namespace type
606 * RETURN: NEWSCOPE if the passed type "opens a name scope" according
607 * to the ACPI specification, else 0
609 ***************************************************************************/
612 acpi_ns_opens_scope (
613 OBJECT_TYPE_INTERNAL type
)
616 if (!acpi_cm_valid_object_type (type
)) {
617 /* type code out of range */
619 REPORT_WARNING (("Ns_opens_scope: Invalid Object Type\n"));
623 return (((u32
) acpi_gbl_ns_properties
[type
]) & NSP_NEWSCOPE
);
627 /****************************************************************************
629 * FUNCTION: Acpi_ns_get_node
631 * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The
632 * \ (backslash) and ^ (carat) prefixes, and the
633 * . (period) to separate segments are supported.
634 * Start_node - Root of subtree to be searched, or NS_ALL for the
635 * root of the name space. If Name is fully
636 * qualified (first s8 is '\'), the passed value
637 * of Scope will not be accessed.
638 * Return_node - Where the Node is returned
640 * DESCRIPTION: Look up a name relative to a given scope and return the
641 * corresponding Node. NOTE: Scope can be null.
643 * MUTEX: Locks namespace
645 ***************************************************************************/
649 NATIVE_CHAR
*pathname
,
650 ACPI_NAMESPACE_NODE
*start_node
,
651 ACPI_NAMESPACE_NODE
**return_node
)
653 ACPI_GENERIC_STATE scope_info
;
655 NATIVE_CHAR
*internal_path
= NULL
;
658 /* Ensure that the namespace has been initialized */
660 if (!acpi_gbl_root_node
) {
661 return (AE_NO_NAMESPACE
);
665 return (AE_BAD_PARAMETER
);
669 /* Convert path to internal representation */
671 status
= acpi_ns_internalize_name (pathname
, &internal_path
);
672 if (ACPI_FAILURE (status
)) {
677 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE
);
679 /* Setup lookup scope (search starting point) */
681 scope_info
.scope
.node
= start_node
;
683 /* Lookup the name in the namespace */
685 status
= acpi_ns_lookup (&scope_info
, internal_path
,
686 ACPI_TYPE_ANY
, IMODE_EXECUTE
,
687 NS_NO_UPSEARCH
| NS_DONT_OPEN_SCOPE
,
692 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE
);
696 acpi_cm_free (internal_path
);
702 /****************************************************************************
704 * FUNCTION: Acpi_ns_find_parent_name
706 * PARAMETERS: *Child_node - Named Obj whose name is to be found
708 * RETURN: The ACPI name
710 * DESCRIPTION: Search for the given obj in its parent scope and return the
711 * name segment, or "????" if the parent name can't be found
712 * (which "should not happen").
714 ***************************************************************************/
717 acpi_ns_find_parent_name (
718 ACPI_NAMESPACE_NODE
*child_node
)
720 ACPI_NAMESPACE_NODE
*parent_node
;
724 /* Valid entry. Get the parent Node */
726 parent_node
= acpi_ns_get_parent_object (child_node
);
728 if (parent_node
->name
) {
729 return (parent_node
->name
);
736 return (ACPI_UNKNOWN_NAME
);
740 /****************************************************************************
742 * FUNCTION: Acpi_ns_get_parent_object
744 * PARAMETERS: Node - Current table entry
746 * RETURN: Parent entry of the given entry
748 * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
750 ***************************************************************************/
753 ACPI_NAMESPACE_NODE
*
754 acpi_ns_get_parent_object (
755 ACPI_NAMESPACE_NODE
*node
)
764 * Walk to the end of this peer list.
765 * The last entry is marked with a flag and the peer
766 * pointer is really a pointer back to the parent.
767 * This saves putting a parent back pointer in each and
768 * every named object!
771 while (!(node
->flags
& ANOBJ_END_OF_PEER_LIST
)) {
780 /****************************************************************************
782 * FUNCTION: Acpi_ns_get_next_valid_object
784 * PARAMETERS: Node - Current table entry
786 * RETURN: Next valid object in the table. NULL if no more valid
789 * DESCRIPTION: Find the next valid object within a name table.
790 * Useful for implementing NULL-end-of-list loops.
792 ***************************************************************************/
795 ACPI_NAMESPACE_NODE
*
796 acpi_ns_get_next_valid_object (
797 ACPI_NAMESPACE_NODE
*node
)
800 /* If we are at the end of this peer list, return NULL */
802 if (node
->flags
& ANOBJ_END_OF_PEER_LIST
) {
806 /* Otherwise just return the next peer */