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
34 #define _COMPONENT ACPI_NAMESPACE
35 MODULE_NAME ("nsutils")
38 /****************************************************************************
40 * FUNCTION: Acpi_ns_valid_root_prefix
42 * PARAMETERS: Prefix - Character to be checked
44 * RETURN: TRUE if a valid prefix
46 * DESCRIPTION: Check if a character is a valid ACPI Root prefix
48 ***************************************************************************/
51 acpi_ns_valid_root_prefix (
55 return ((u8) (prefix == '\\'));
59 /****************************************************************************
61 * FUNCTION: Acpi_ns_valid_path_separator
63 * PARAMETERS: Sep - Character to be checked
65 * RETURN: TRUE if a valid path separator
67 * DESCRIPTION: Check if a character is a valid ACPI path separator
69 ***************************************************************************/
72 acpi_ns_valid_path_separator (
76 return ((u8) (sep == '.'));
80 /****************************************************************************
82 * FUNCTION: Acpi_ns_get_type
84 * PARAMETERS: Handle - Parent Node to be examined
86 * RETURN: Type field from Node whose handle is passed
88 ***************************************************************************/
96 REPORT_WARNING (("Ns_get_type: Null handle\n"));
97 return (ACPI_TYPE_ANY);
100 return (((ACPI_NAMESPACE_NODE *) handle)->type);
104 /****************************************************************************
106 * FUNCTION: Acpi_ns_local
108 * PARAMETERS: Type - A namespace object type
110 * RETURN: LOCAL if names must be found locally in objects of the
111 * passed type, 0 if enclosing scopes should be searched
113 ***************************************************************************/
117 OBJECT_TYPE_INTERNAL type)
120 if (!acpi_cm_valid_object_type (type)) {
121 /* Type code out of range */
123 REPORT_WARNING (("Ns_local: Invalid Object Type\n"));
127 return ((u32) acpi_gbl_ns_properties[type] & NSP_LOCAL);
131 /****************************************************************************
133 * FUNCTION: Acpi_ns_internalize_name
135 * PARAMETERS: *External_name - External representation of name
136 * **Converted Name - Where to return the resulting
137 * internal represention of the name
141 * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
142 * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
144 ****************************************************************************/
147 acpi_ns_internalize_name (
148 NATIVE_CHAR *external_name,
149 NATIVE_CHAR **converted_name)
151 NATIVE_CHAR *result = NULL;
152 NATIVE_CHAR *internal_name;
153 u32 num_segments = 0;
154 u8 fully_qualified = FALSE;
159 if ((!external_name) ||
160 (*external_name == 0) ||
162 return (AE_BAD_PARAMETER);
167 * For the internal name, the required length is 4 bytes
168 * per segment, plus 1 each for Root_prefix, Multi_name_prefix_op,
169 * segment count, trailing null (which is not really needed,
170 * but no there's harm in putting it there)
172 * strlen() + 1 covers the first Name_seg, which has no
176 if (acpi_ns_valid_root_prefix (external_name[0])) {
177 fully_qualified = TRUE;
183 * Handle Carat prefixes
186 while (*external_name == '^') {
193 * Determine the number of ACPI name "segments" by counting
194 * the number of path separators within the string. Start
195 * with one segment since the segment count is (# separators)
196 * + 1, and zero separators is ok.
199 if (*external_name) {
201 for (i = 0; external_name[i]; i++) {
202 if (acpi_ns_valid_path_separator (external_name[i])) {
209 /* We need a segment to store the internal version of the name */
211 internal_name = acpi_cm_callocate ((ACPI_NAME_SIZE * num_segments) + 4 + num_carats);
212 if (!internal_name) {
213 return (AE_NO_MEMORY);
217 /* Setup the correct prefixes, counts, and pointers */
219 if (fully_qualified) {
220 internal_name[0] = '\\';
222 if (num_segments <= 1) {
223 result = &internal_name[1];
225 else if (num_segments == 2) {
226 internal_name[1] = AML_DUAL_NAME_PREFIX;
227 result = &internal_name[2];
230 internal_name[1] = AML_MULTI_NAME_PREFIX_OP;
231 internal_name[2] = (char) num_segments;
232 result = &internal_name[3];
239 * Not fully qualified.
240 * Handle Carats first, then append the name segments
245 for (i = 0; i < num_carats; i++) {
246 internal_name[i] = '^';
250 if (num_segments == 1) {
251 result = &internal_name[i];
254 else if (num_segments == 2) {
255 internal_name[i] = AML_DUAL_NAME_PREFIX;
256 result = &internal_name[i+1];
260 internal_name[i] = AML_MULTI_NAME_PREFIX_OP;
261 internal_name[i+1] = (char) num_segments;
262 result = &internal_name[i+2];
267 /* Build the name (minus path separators) */
269 for (; num_segments; num_segments--) {
270 for (i = 0; i < ACPI_NAME_SIZE; i++) {
271 if (acpi_ns_valid_path_separator (*external_name) ||
272 (*external_name == 0)) {
274 * Pad the segment with underscore(s) if
282 /* Convert s8 to uppercase and save it */
284 result[i] = (char) TOUPPER (*external_name);
290 /* Now we must have a path separator, or the pathname is bad */
292 if (!acpi_ns_valid_path_separator (*external_name) &&
293 (*external_name != 0)) {
294 acpi_cm_free (internal_name);
295 return (AE_BAD_PARAMETER);
298 /* Move on the next segment */
301 result += ACPI_NAME_SIZE;
305 /* Return the completed name */
307 /* Terminate the string! */
309 *converted_name = internal_name;
317 /****************************************************************************
319 * FUNCTION: Acpi_ns_externalize_name
321 * PARAMETERS: *Internal_name - Internal representation of name
322 * **Converted_name - Where to return the resulting
323 * external representation of name
327 * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
328 * to its external form (e.g. "\_PR_.CPU0")
330 ****************************************************************************/
333 acpi_ns_externalize_name (
334 u32 internal_name_length,
336 u32 *converted_name_length,
337 char **converted_name)
339 u32 prefix_length = 0;
346 if (!internal_name_length ||
348 !converted_name_length ||
350 return (AE_BAD_PARAMETER);
355 * Check for a prefix (one '\' | one or more '^').
357 switch (internal_name[0]) {
363 for (i = 0; i < internal_name_length; i++) {
364 if (internal_name[i] != '^') {
365 prefix_length = i + 1;
369 if (i == internal_name_length) {
377 * Check for object names. Note that there could be 0-255 of these
380 if (prefix_length < internal_name_length) {
381 switch (internal_name[prefix_length]) {
383 /* <count> 4-byte names */
385 case AML_MULTI_NAME_PREFIX_OP:
386 names_index = prefix_length + 2;
387 names_count = (u32) internal_name[prefix_length + 1];
391 /* two 4-byte names */
393 case AML_DUAL_NAME_PREFIX:
394 names_index = prefix_length + 1;
407 /* one 4-byte name */
410 names_index = prefix_length;
417 * Calculate the length of Converted_name, which equals the length
418 * of the prefix, length of all object names, length of any required
419 * punctuation ('.') between object names, plus the NULL terminator.
421 *converted_name_length = prefix_length + (4 * names_count) +
422 ((names_count > 0) ? (names_count - 1) : 0) + 1;
425 * Check to see if we're still in bounds. If not, there's a problem
426 * with Internal_name (invalid format).
428 if (*converted_name_length > internal_name_length) {
429 REPORT_ERROR (("Ns_externalize_name: Invalid internal name\n"));
430 return (AE_BAD_PATHNAME);
434 * Build Converted_name...
437 (*converted_name) = acpi_cm_callocate (*converted_name_length);
438 if (!(*converted_name)) {
439 return (AE_NO_MEMORY);
444 for (i = 0; i < prefix_length; i++) {
445 (*converted_name)[j++] = internal_name[i];
448 if (names_count > 0) {
449 for (i = 0; i < names_count; i++) {
451 (*converted_name)[j++] = '.';
454 (*converted_name)[j++] = internal_name[names_index++];
455 (*converted_name)[j++] = internal_name[names_index++];
456 (*converted_name)[j++] = internal_name[names_index++];
457 (*converted_name)[j++] = internal_name[names_index++];
465 /****************************************************************************
467 * FUNCTION: Acpi_ns_convert_handle_to_entry
469 * PARAMETERS: Handle - Handle to be converted to an Node
471 * RETURN: A Name table entry pointer
473 * DESCRIPTION: Convert a namespace handle to a real Node
475 ****************************************************************************/
477 ACPI_NAMESPACE_NODE *
478 acpi_ns_convert_handle_to_entry (
483 * Simple implementation for now;
484 * TBD: [Future] Real integer handles allow for more verification
485 * and keep all pointers within this subsystem!
492 if (handle == ACPI_ROOT_OBJECT) {
493 return (acpi_gbl_root_node);
497 /* We can at least attempt to verify the handle */
499 if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) {
503 return ((ACPI_NAMESPACE_NODE *) handle);
507 /****************************************************************************
509 * FUNCTION: Acpi_ns_convert_entry_to_handle
511 * PARAMETERS: Node - Node to be converted to a Handle
513 * RETURN: An USER ACPI_HANDLE
515 * DESCRIPTION: Convert a real Node to a namespace handle
517 ****************************************************************************/
520 acpi_ns_convert_entry_to_handle (
521 ACPI_NAMESPACE_NODE *node)
526 * Simple implementation for now;
527 * TBD: [Future] Real integer handles allow for more verification
528 * and keep all pointers within this subsystem!
531 return ((ACPI_HANDLE) node);
534 /* ---------------------------------------------------
541 if (Node == Acpi_gbl_Root_node)
543 return (ACPI_ROOT_OBJECT);
547 return ((ACPI_HANDLE) Node);
548 ------------------------------------------------------*/
552 /******************************************************************************
554 * FUNCTION: Acpi_ns_terminate
560 * DESCRIPTION: free memory allocated for table storage.
562 ******************************************************************************/
565 acpi_ns_terminate (void)
567 ACPI_OPERAND_OBJECT *obj_desc;
568 ACPI_NAMESPACE_NODE *this_node;
571 this_node = acpi_gbl_root_node;
574 * 1) Free the entire namespace -- all objects, tables, and stacks
577 * Delete all objects linked to the root
578 * (additional table descriptors)
581 acpi_ns_delete_namespace_subtree (this_node);
583 /* Detach any object(s) attached to the root */
585 obj_desc = acpi_ns_get_attached_object (this_node);
587 acpi_ns_detach_object (this_node);
588 acpi_cm_remove_reference (obj_desc);
591 acpi_ns_delete_children (this_node);
595 * 2) Now we can delete the ACPI tables
598 acpi_tb_delete_acpi_tables ();
604 /****************************************************************************
606 * FUNCTION: Acpi_ns_opens_scope
608 * PARAMETERS: Type - A valid namespace type
610 * RETURN: NEWSCOPE if the passed type "opens a name scope" according
611 * to the ACPI specification, else 0
613 ***************************************************************************/
616 acpi_ns_opens_scope (
617 OBJECT_TYPE_INTERNAL type)
620 if (!acpi_cm_valid_object_type (type)) {
621 /* type code out of range */
623 REPORT_WARNING (("Ns_opens_scope: Invalid Object Type\n"));
627 return (((u32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE);
631 /****************************************************************************
633 * FUNCTION: Acpi_ns_get_node
635 * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The
636 * \ (backslash) and ^ (carat) prefixes, and the
637 * . (period) to separate segments are supported.
638 * Start_node - Root of subtree to be searched, or NS_ALL for the
639 * root of the name space. If Name is fully
640 * qualified (first s8 is '\'), the passed value
641 * of Scope will not be accessed.
642 * Return_node - Where the Node is returned
644 * DESCRIPTION: Look up a name relative to a given scope and return the
645 * corresponding Node. NOTE: Scope can be null.
647 * MUTEX: Locks namespace
649 ***************************************************************************/
653 NATIVE_CHAR *pathname,
654 ACPI_NAMESPACE_NODE *start_node,
655 ACPI_NAMESPACE_NODE **return_node)
657 ACPI_GENERIC_STATE scope_info;
659 NATIVE_CHAR *internal_path = NULL;
662 /* Ensure that the namespace has been initialized */
664 if (!acpi_gbl_root_node) {
665 return (AE_NO_NAMESPACE);
669 return (AE_BAD_PARAMETER);
673 /* Convert path to internal representation */
675 status = acpi_ns_internalize_name (pathname, &internal_path);
676 if (ACPI_FAILURE (status)) {
681 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
683 /* Setup lookup scope (search starting point) */
685 scope_info.scope.node = start_node;
687 /* Lookup the name in the namespace */
689 status = acpi_ns_lookup (&scope_info, internal_path,
690 ACPI_TYPE_ANY, IMODE_EXECUTE,
691 NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
696 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
700 acpi_cm_free (internal_path);
706 /****************************************************************************
708 * FUNCTION: Acpi_ns_find_parent_name
710 * PARAMETERS: *Child_node - Named Obj whose name is to be found
712 * RETURN: The ACPI name
714 * DESCRIPTION: Search for the given obj in its parent scope and return the
715 * name segment, or "????" if the parent name can't be found
716 * (which "should not happen").
718 ***************************************************************************/
721 acpi_ns_find_parent_name (
722 ACPI_NAMESPACE_NODE *child_node)
724 ACPI_NAMESPACE_NODE *parent_node;
728 /* Valid entry. Get the parent Node */
730 parent_node = acpi_ns_get_parent_object (child_node);
732 if (parent_node->name) {
733 return (parent_node->name);
740 return (ACPI_UNKNOWN_NAME);
744 /****************************************************************************
746 * FUNCTION: Acpi_ns_get_parent_object
748 * PARAMETERS: Node - Current table entry
750 * RETURN: Parent entry of the given entry
752 * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
754 ***************************************************************************/
757 ACPI_NAMESPACE_NODE *
758 acpi_ns_get_parent_object (
759 ACPI_NAMESPACE_NODE *node)
768 * Walk to the end of this peer list.
769 * The last entry is marked with a flag and the peer
770 * pointer is really a pointer back to the parent.
771 * This saves putting a parent back pointer in each and
772 * every named object!
775 while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
784 /****************************************************************************
786 * FUNCTION: Acpi_ns_get_next_valid_object
788 * PARAMETERS: Node - Current table entry
790 * RETURN: Next valid object in the table. NULL if no more valid
793 * DESCRIPTION: Find the next valid object within a name table.
794 * Useful for implementing NULL-end-of-list loops.
796 ***************************************************************************/
799 ACPI_NAMESPACE_NODE *
800 acpi_ns_get_next_valid_object (
801 ACPI_NAMESPACE_NODE *node)
804 /* If we are at the end of this peer list, return NULL */
806 if (node->flags & ANOBJ_END_OF_PEER_LIST) {
810 /* Otherwise just return the next peer */