xref: /freebsd/sys/contrib/dev/acpica/components/namespace/nsutils.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /******************************************************************************
2  *
3  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
4  *                        parents and siblings and Scope manipulation
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2015, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acnamesp.h>
48 #include <contrib/dev/acpica/include/amlcode.h>
49 
50 #define _COMPONENT          ACPI_NAMESPACE
51         ACPI_MODULE_NAME    ("nsutils")
52 
53 /* Local prototypes */
54 
55 #ifdef ACPI_OBSOLETE_FUNCTIONS
56 ACPI_NAME
57 AcpiNsFindParentName (
58     ACPI_NAMESPACE_NODE     *NodeToSearch);
59 #endif
60 
61 
62 /*******************************************************************************
63  *
64  * FUNCTION:    AcpiNsPrintNodePathname
65  *
66  * PARAMETERS:  Node            - Object
67  *              Message         - Prefix message
68  *
69  * DESCRIPTION: Print an object's full namespace pathname
70  *              Manages allocation/freeing of a pathname buffer
71  *
72  ******************************************************************************/
73 
74 void
75 AcpiNsPrintNodePathname (
76     ACPI_NAMESPACE_NODE     *Node,
77     const char              *Message)
78 {
79     ACPI_BUFFER             Buffer;
80     ACPI_STATUS             Status;
81 
82 
83     if (!Node)
84     {
85         AcpiOsPrintf ("[NULL NAME]");
86         return;
87     }
88 
89     /* Convert handle to full pathname and print it (with supplied message) */
90 
91     Buffer.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
92 
93     Status = AcpiNsHandleToPathname (Node, &Buffer, TRUE);
94     if (ACPI_SUCCESS (Status))
95     {
96         if (Message)
97         {
98             AcpiOsPrintf ("%s ", Message);
99         }
100 
101         AcpiOsPrintf ("[%s] (Node %p)", (char *) Buffer.Pointer, Node);
102         ACPI_FREE (Buffer.Pointer);
103     }
104 }
105 
106 
107 /*******************************************************************************
108  *
109  * FUNCTION:    AcpiNsGetType
110  *
111  * PARAMETERS:  Node        - Parent Node to be examined
112  *
113  * RETURN:      Type field from Node whose handle is passed
114  *
115  * DESCRIPTION: Return the type of a Namespace node
116  *
117  ******************************************************************************/
118 
119 ACPI_OBJECT_TYPE
120 AcpiNsGetType (
121     ACPI_NAMESPACE_NODE     *Node)
122 {
123     ACPI_FUNCTION_TRACE (NsGetType);
124 
125 
126     if (!Node)
127     {
128         ACPI_WARNING ((AE_INFO, "Null Node parameter"));
129         return_UINT8 (ACPI_TYPE_ANY);
130     }
131 
132     return_UINT8 (Node->Type);
133 }
134 
135 
136 /*******************************************************************************
137  *
138  * FUNCTION:    AcpiNsLocal
139  *
140  * PARAMETERS:  Type        - A namespace object type
141  *
142  * RETURN:      LOCAL if names must be found locally in objects of the
143  *              passed type, 0 if enclosing scopes should be searched
144  *
145  * DESCRIPTION: Returns scope rule for the given object type.
146  *
147  ******************************************************************************/
148 
149 UINT32
150 AcpiNsLocal (
151     ACPI_OBJECT_TYPE        Type)
152 {
153     ACPI_FUNCTION_TRACE (NsLocal);
154 
155 
156     if (!AcpiUtValidObjectType (Type))
157     {
158         /* Type code out of range  */
159 
160         ACPI_WARNING ((AE_INFO, "Invalid Object Type 0x%X", Type));
161         return_UINT32 (ACPI_NS_NORMAL);
162     }
163 
164     return_UINT32 (AcpiGbl_NsProperties[Type] & ACPI_NS_LOCAL);
165 }
166 
167 
168 /*******************************************************************************
169  *
170  * FUNCTION:    AcpiNsGetInternalNameLength
171  *
172  * PARAMETERS:  Info            - Info struct initialized with the
173  *                                external name pointer.
174  *
175  * RETURN:      None
176  *
177  * DESCRIPTION: Calculate the length of the internal (AML) namestring
178  *              corresponding to the external (ASL) namestring.
179  *
180  ******************************************************************************/
181 
182 void
183 AcpiNsGetInternalNameLength (
184     ACPI_NAMESTRING_INFO    *Info)
185 {
186     const char              *NextExternalChar;
187     UINT32                  i;
188 
189 
190     ACPI_FUNCTION_ENTRY ();
191 
192 
193     NextExternalChar = Info->ExternalName;
194     Info->NumCarats = 0;
195     Info->NumSegments = 0;
196     Info->FullyQualified = FALSE;
197 
198     /*
199      * For the internal name, the required length is 4 bytes per segment, plus
200      * 1 each for RootPrefix, MultiNamePrefixOp, segment count, trailing null
201      * (which is not really needed, but no there's harm in putting it there)
202      *
203      * strlen() + 1 covers the first NameSeg, which has no path separator
204      */
205     if (ACPI_IS_ROOT_PREFIX (*NextExternalChar))
206     {
207         Info->FullyQualified = TRUE;
208         NextExternalChar++;
209 
210         /* Skip redundant RootPrefix, like \\_SB.PCI0.SBRG.EC0 */
211 
212         while (ACPI_IS_ROOT_PREFIX (*NextExternalChar))
213         {
214             NextExternalChar++;
215         }
216     }
217     else
218     {
219         /* Handle Carat prefixes */
220 
221         while (ACPI_IS_PARENT_PREFIX (*NextExternalChar))
222         {
223             Info->NumCarats++;
224             NextExternalChar++;
225         }
226     }
227 
228     /*
229      * Determine the number of ACPI name "segments" by counting the number of
230      * path separators within the string. Start with one segment since the
231      * segment count is [(# separators) + 1], and zero separators is ok.
232      */
233     if (*NextExternalChar)
234     {
235         Info->NumSegments = 1;
236         for (i = 0; NextExternalChar[i]; i++)
237         {
238             if (ACPI_IS_PATH_SEPARATOR (NextExternalChar[i]))
239             {
240                 Info->NumSegments++;
241             }
242         }
243     }
244 
245     Info->Length = (ACPI_NAME_SIZE * Info->NumSegments) +
246                     4 + Info->NumCarats;
247 
248     Info->NextExternalChar = NextExternalChar;
249 }
250 
251 
252 /*******************************************************************************
253  *
254  * FUNCTION:    AcpiNsBuildInternalName
255  *
256  * PARAMETERS:  Info            - Info struct fully initialized
257  *
258  * RETURN:      Status
259  *
260  * DESCRIPTION: Construct the internal (AML) namestring
261  *              corresponding to the external (ASL) namestring.
262  *
263  ******************************************************************************/
264 
265 ACPI_STATUS
266 AcpiNsBuildInternalName (
267     ACPI_NAMESTRING_INFO    *Info)
268 {
269     UINT32                  NumSegments = Info->NumSegments;
270     char                    *InternalName = Info->InternalName;
271     const char              *ExternalName = Info->NextExternalChar;
272     char                    *Result = NULL;
273     UINT32                  i;
274 
275 
276     ACPI_FUNCTION_TRACE (NsBuildInternalName);
277 
278 
279     /* Setup the correct prefixes, counts, and pointers */
280 
281     if (Info->FullyQualified)
282     {
283         InternalName[0] = AML_ROOT_PREFIX;
284 
285         if (NumSegments <= 1)
286         {
287             Result = &InternalName[1];
288         }
289         else if (NumSegments == 2)
290         {
291             InternalName[1] = AML_DUAL_NAME_PREFIX;
292             Result = &InternalName[2];
293         }
294         else
295         {
296             InternalName[1] = AML_MULTI_NAME_PREFIX_OP;
297             InternalName[2] = (char) NumSegments;
298             Result = &InternalName[3];
299         }
300     }
301     else
302     {
303         /*
304          * Not fully qualified.
305          * Handle Carats first, then append the name segments
306          */
307         i = 0;
308         if (Info->NumCarats)
309         {
310             for (i = 0; i < Info->NumCarats; i++)
311             {
312                 InternalName[i] = AML_PARENT_PREFIX;
313             }
314         }
315 
316         if (NumSegments <= 1)
317         {
318             Result = &InternalName[i];
319         }
320         else if (NumSegments == 2)
321         {
322             InternalName[i] = AML_DUAL_NAME_PREFIX;
323             Result = &InternalName[(ACPI_SIZE) i+1];
324         }
325         else
326         {
327             InternalName[i] = AML_MULTI_NAME_PREFIX_OP;
328             InternalName[(ACPI_SIZE) i+1] = (char) NumSegments;
329             Result = &InternalName[(ACPI_SIZE) i+2];
330         }
331     }
332 
333     /* Build the name (minus path separators) */
334 
335     for (; NumSegments; NumSegments--)
336     {
337         for (i = 0; i < ACPI_NAME_SIZE; i++)
338         {
339             if (ACPI_IS_PATH_SEPARATOR (*ExternalName) ||
340                (*ExternalName == 0))
341             {
342                 /* Pad the segment with underscore(s) if segment is short */
343 
344                 Result[i] = '_';
345             }
346             else
347             {
348                 /* Convert the character to uppercase and save it */
349 
350                 Result[i] = (char) toupper ((int) *ExternalName);
351                 ExternalName++;
352             }
353         }
354 
355         /* Now we must have a path separator, or the pathname is bad */
356 
357         if (!ACPI_IS_PATH_SEPARATOR (*ExternalName) &&
358             (*ExternalName != 0))
359         {
360             return_ACPI_STATUS (AE_BAD_PATHNAME);
361         }
362 
363         /* Move on the next segment */
364 
365         ExternalName++;
366         Result += ACPI_NAME_SIZE;
367     }
368 
369     /* Terminate the string */
370 
371     *Result = 0;
372 
373     if (Info->FullyQualified)
374     {
375         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (abs) \"\\%s\"\n",
376             InternalName, InternalName));
377     }
378     else
379     {
380         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n",
381             InternalName, InternalName));
382     }
383 
384     return_ACPI_STATUS (AE_OK);
385 }
386 
387 
388 /*******************************************************************************
389  *
390  * FUNCTION:    AcpiNsInternalizeName
391  *
392  * PARAMETERS:  *ExternalName           - External representation of name
393  *              **Converted Name        - Where to return the resulting
394  *                                        internal represention of the name
395  *
396  * RETURN:      Status
397  *
398  * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
399  *              to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
400  *
401  *******************************************************************************/
402 
403 ACPI_STATUS
404 AcpiNsInternalizeName (
405     const char              *ExternalName,
406     char                    **ConvertedName)
407 {
408     char                    *InternalName;
409     ACPI_NAMESTRING_INFO    Info;
410     ACPI_STATUS             Status;
411 
412 
413     ACPI_FUNCTION_TRACE (NsInternalizeName);
414 
415 
416     if ((!ExternalName)      ||
417         (*ExternalName == 0) ||
418         (!ConvertedName))
419     {
420         return_ACPI_STATUS (AE_BAD_PARAMETER);
421     }
422 
423     /* Get the length of the new internal name */
424 
425     Info.ExternalName = ExternalName;
426     AcpiNsGetInternalNameLength (&Info);
427 
428     /* We need a segment to store the internal  name */
429 
430     InternalName = ACPI_ALLOCATE_ZEROED (Info.Length);
431     if (!InternalName)
432     {
433         return_ACPI_STATUS (AE_NO_MEMORY);
434     }
435 
436     /* Build the name */
437 
438     Info.InternalName = InternalName;
439     Status = AcpiNsBuildInternalName (&Info);
440     if (ACPI_FAILURE (Status))
441     {
442         ACPI_FREE (InternalName);
443         return_ACPI_STATUS (Status);
444     }
445 
446     *ConvertedName = InternalName;
447     return_ACPI_STATUS (AE_OK);
448 }
449 
450 
451 /*******************************************************************************
452  *
453  * FUNCTION:    AcpiNsExternalizeName
454  *
455  * PARAMETERS:  InternalNameLength  - Lenth of the internal name below
456  *              InternalName        - Internal representation of name
457  *              ConvertedNameLength - Where the length is returned
458  *              ConvertedName       - Where the resulting external name
459  *                                    is returned
460  *
461  * RETURN:      Status
462  *
463  * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
464  *              to its external (printable) form (e.g. "\_PR_.CPU0")
465  *
466  ******************************************************************************/
467 
468 ACPI_STATUS
469 AcpiNsExternalizeName (
470     UINT32                  InternalNameLength,
471     const char              *InternalName,
472     UINT32                  *ConvertedNameLength,
473     char                    **ConvertedName)
474 {
475     UINT32                  NamesIndex = 0;
476     UINT32                  NumSegments = 0;
477     UINT32                  RequiredLength;
478     UINT32                  PrefixLength = 0;
479     UINT32                  i = 0;
480     UINT32                  j = 0;
481 
482 
483     ACPI_FUNCTION_TRACE (NsExternalizeName);
484 
485 
486     if (!InternalNameLength     ||
487         !InternalName           ||
488         !ConvertedName)
489     {
490         return_ACPI_STATUS (AE_BAD_PARAMETER);
491     }
492 
493     /* Check for a prefix (one '\' | one or more '^') */
494 
495     switch (InternalName[0])
496     {
497     case AML_ROOT_PREFIX:
498 
499         PrefixLength = 1;
500         break;
501 
502     case AML_PARENT_PREFIX:
503 
504         for (i = 0; i < InternalNameLength; i++)
505         {
506             if (ACPI_IS_PARENT_PREFIX (InternalName[i]))
507             {
508                 PrefixLength = i + 1;
509             }
510             else
511             {
512                 break;
513             }
514         }
515 
516         if (i == InternalNameLength)
517         {
518             PrefixLength = i;
519         }
520 
521         break;
522 
523     default:
524 
525         break;
526     }
527 
528     /*
529      * Check for object names. Note that there could be 0-255 of these
530      * 4-byte elements.
531      */
532     if (PrefixLength < InternalNameLength)
533     {
534         switch (InternalName[PrefixLength])
535         {
536         case AML_MULTI_NAME_PREFIX_OP:
537 
538             /* <count> 4-byte names */
539 
540             NamesIndex = PrefixLength + 2;
541             NumSegments = (UINT8)
542                 InternalName[(ACPI_SIZE) PrefixLength + 1];
543             break;
544 
545         case AML_DUAL_NAME_PREFIX:
546 
547             /* Two 4-byte names */
548 
549             NamesIndex = PrefixLength + 1;
550             NumSegments = 2;
551             break;
552 
553         case 0:
554 
555             /* NullName */
556 
557             NamesIndex = 0;
558             NumSegments = 0;
559             break;
560 
561         default:
562 
563             /* one 4-byte name */
564 
565             NamesIndex = PrefixLength;
566             NumSegments = 1;
567             break;
568         }
569     }
570 
571     /*
572      * Calculate the length of ConvertedName, which equals the length
573      * of the prefix, length of all object names, length of any required
574      * punctuation ('.') between object names, plus the NULL terminator.
575      */
576     RequiredLength = PrefixLength + (4 * NumSegments) +
577                         ((NumSegments > 0) ? (NumSegments - 1) : 0) + 1;
578 
579     /*
580      * Check to see if we're still in bounds. If not, there's a problem
581      * with InternalName (invalid format).
582      */
583     if (RequiredLength > InternalNameLength)
584     {
585         ACPI_ERROR ((AE_INFO, "Invalid internal name"));
586         return_ACPI_STATUS (AE_BAD_PATHNAME);
587     }
588 
589     /* Build the ConvertedName */
590 
591     *ConvertedName = ACPI_ALLOCATE_ZEROED (RequiredLength);
592     if (!(*ConvertedName))
593     {
594         return_ACPI_STATUS (AE_NO_MEMORY);
595     }
596 
597     j = 0;
598 
599     for (i = 0; i < PrefixLength; i++)
600     {
601         (*ConvertedName)[j++] = InternalName[i];
602     }
603 
604     if (NumSegments > 0)
605     {
606         for (i = 0; i < NumSegments; i++)
607         {
608             if (i > 0)
609             {
610                 (*ConvertedName)[j++] = '.';
611             }
612 
613             /* Copy and validate the 4-char name segment */
614 
615             ACPI_MOVE_NAME (&(*ConvertedName)[j], &InternalName[NamesIndex]);
616             AcpiUtRepairName (&(*ConvertedName)[j]);
617 
618             j += ACPI_NAME_SIZE;
619             NamesIndex += ACPI_NAME_SIZE;
620         }
621     }
622 
623     if (ConvertedNameLength)
624     {
625         *ConvertedNameLength = (UINT32) RequiredLength;
626     }
627 
628     return_ACPI_STATUS (AE_OK);
629 }
630 
631 
632 /*******************************************************************************
633  *
634  * FUNCTION:    AcpiNsValidateHandle
635  *
636  * PARAMETERS:  Handle          - Handle to be validated and typecast to a
637  *                                namespace node.
638  *
639  * RETURN:      A pointer to a namespace node
640  *
641  * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special
642  *              cases for the root node.
643  *
644  * NOTE: Real integer handles would allow for more verification
645  *       and keep all pointers within this subsystem - however this introduces
646  *       more overhead and has not been necessary to this point. Drivers
647  *       holding handles are typically notified before a node becomes invalid
648  *       due to a table unload.
649  *
650  ******************************************************************************/
651 
652 ACPI_NAMESPACE_NODE *
653 AcpiNsValidateHandle (
654     ACPI_HANDLE             Handle)
655 {
656 
657     ACPI_FUNCTION_ENTRY ();
658 
659 
660     /* Parameter validation */
661 
662     if ((!Handle) || (Handle == ACPI_ROOT_OBJECT))
663     {
664         return (AcpiGbl_RootNode);
665     }
666 
667     /* We can at least attempt to verify the handle */
668 
669     if (ACPI_GET_DESCRIPTOR_TYPE (Handle) != ACPI_DESC_TYPE_NAMED)
670     {
671         return (NULL);
672     }
673 
674     return (ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Handle));
675 }
676 
677 
678 /*******************************************************************************
679  *
680  * FUNCTION:    AcpiNsTerminate
681  *
682  * PARAMETERS:  none
683  *
684  * RETURN:      none
685  *
686  * DESCRIPTION: free memory allocated for namespace and ACPI table storage.
687  *
688  ******************************************************************************/
689 
690 void
691 AcpiNsTerminate (
692     void)
693 {
694     ACPI_STATUS             Status;
695 
696 
697     ACPI_FUNCTION_TRACE (NsTerminate);
698 
699 
700 #ifdef ACPI_EXEC_APP
701     {
702         ACPI_OPERAND_OBJECT     *Prev;
703         ACPI_OPERAND_OBJECT     *Next;
704 
705         /* Delete any module-level code blocks */
706 
707         Next = AcpiGbl_ModuleCodeList;
708         while (Next)
709         {
710             Prev = Next;
711             Next = Next->Method.Mutex;
712             Prev->Method.Mutex = NULL; /* Clear the Mutex (cheated) field */
713             AcpiUtRemoveReference (Prev);
714         }
715     }
716 #endif
717 
718     /*
719      * Free the entire namespace -- all nodes and all objects
720      * attached to the nodes
721      */
722     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
723 
724     /* Delete any objects attached to the root node */
725 
726     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
727     if (ACPI_FAILURE (Status))
728     {
729         return_VOID;
730     }
731 
732     AcpiNsDeleteNode (AcpiGbl_RootNode);
733     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
734 
735     ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Namespace freed\n"));
736     return_VOID;
737 }
738 
739 
740 /*******************************************************************************
741  *
742  * FUNCTION:    AcpiNsOpensScope
743  *
744  * PARAMETERS:  Type        - A valid namespace type
745  *
746  * RETURN:      NEWSCOPE if the passed type "opens a name scope" according
747  *              to the ACPI specification, else 0
748  *
749  ******************************************************************************/
750 
751 UINT32
752 AcpiNsOpensScope (
753     ACPI_OBJECT_TYPE        Type)
754 {
755     ACPI_FUNCTION_ENTRY ();
756 
757 
758     if (Type > ACPI_TYPE_LOCAL_MAX)
759     {
760         /* type code out of range  */
761 
762         ACPI_WARNING ((AE_INFO, "Invalid Object Type 0x%X", Type));
763         return (ACPI_NS_NORMAL);
764     }
765 
766     return (((UINT32) AcpiGbl_NsProperties[Type]) & ACPI_NS_NEWSCOPE);
767 }
768 
769 
770 /*******************************************************************************
771  *
772  * FUNCTION:    AcpiNsGetNode
773  *
774  * PARAMETERS:  *Pathname   - Name to be found, in external (ASL) format. The
775  *                            \ (backslash) and ^ (carat) prefixes, and the
776  *                            . (period) to separate segments are supported.
777  *              PrefixNode   - Root of subtree to be searched, or NS_ALL for the
778  *                            root of the name space. If Name is fully
779  *                            qualified (first INT8 is '\'), the passed value
780  *                            of Scope will not be accessed.
781  *              Flags       - Used to indicate whether to perform upsearch or
782  *                            not.
783  *              ReturnNode  - Where the Node is returned
784  *
785  * DESCRIPTION: Look up a name relative to a given scope and return the
786  *              corresponding Node. NOTE: Scope can be null.
787  *
788  * MUTEX:       Locks namespace
789  *
790  ******************************************************************************/
791 
792 ACPI_STATUS
793 AcpiNsGetNode (
794     ACPI_NAMESPACE_NODE     *PrefixNode,
795     const char              *Pathname,
796     UINT32                  Flags,
797     ACPI_NAMESPACE_NODE     **ReturnNode)
798 {
799     ACPI_GENERIC_STATE      ScopeInfo;
800     ACPI_STATUS             Status;
801     char                    *InternalPath;
802 
803 
804     ACPI_FUNCTION_TRACE_PTR (NsGetNode, ACPI_CAST_PTR (char, Pathname));
805 
806 
807     /* Simplest case is a null pathname */
808 
809     if (!Pathname)
810     {
811         *ReturnNode = PrefixNode;
812         if (!PrefixNode)
813         {
814             *ReturnNode = AcpiGbl_RootNode;
815         }
816         return_ACPI_STATUS (AE_OK);
817     }
818 
819     /* Quick check for a reference to the root */
820 
821     if (ACPI_IS_ROOT_PREFIX (Pathname[0]) && (!Pathname[1]))
822     {
823         *ReturnNode = AcpiGbl_RootNode;
824         return_ACPI_STATUS (AE_OK);
825     }
826 
827     /* Convert path to internal representation */
828 
829     Status = AcpiNsInternalizeName (Pathname, &InternalPath);
830     if (ACPI_FAILURE (Status))
831     {
832         return_ACPI_STATUS (Status);
833     }
834 
835     /* Must lock namespace during lookup */
836 
837     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
838     if (ACPI_FAILURE (Status))
839     {
840         goto Cleanup;
841     }
842 
843     /* Setup lookup scope (search starting point) */
844 
845     ScopeInfo.Scope.Node = PrefixNode;
846 
847     /* Lookup the name in the namespace */
848 
849     Status = AcpiNsLookup (&ScopeInfo, InternalPath, ACPI_TYPE_ANY,
850                 ACPI_IMODE_EXECUTE, (Flags | ACPI_NS_DONT_OPEN_SCOPE),
851                 NULL, ReturnNode);
852     if (ACPI_FAILURE (Status))
853     {
854         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s, %s\n",
855                 Pathname, AcpiFormatException (Status)));
856     }
857 
858     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
859 
860 Cleanup:
861     ACPI_FREE (InternalPath);
862     return_ACPI_STATUS (Status);
863 }
864