nswalk.c revision 231844
138032Speter/****************************************************************************** 298125Sgshapiro * 364565Sgshapiro * Module Name: nswalk - Functions for walking the ACPI namespace 438032Speter * 538032Speter *****************************************************************************/ 638032Speter 738032Speter/* 838032Speter * Copyright (C) 2000 - 2012, Intel Corp. 938032Speter * All rights reserved. 1038032Speter * 1138032Speter * Redistribution and use in source and binary forms, with or without 12102533Sgshapiro * modification, are permitted provided that the following conditions 13102533Sgshapiro * are met: 1438032Speter * 1. Redistributions of source code must retain the above copyright 1538032Speter * notice, this list of conditions, and the following disclaimer, 1690795Sgshapiro * without modification. 1790795Sgshapiro * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1890795Sgshapiro * substantially similar to the "NO WARRANTY" disclaimer below 1973191Sgshapiro * ("Disclaimer") and any redistribution must be conditioned upon 2064565Sgshapiro * including a substantially similar Disclaimer requirement for further 2164565Sgshapiro * binary redistribution. 2264565Sgshapiro * 3. Neither the names of the above-listed copyright holders nor the names 2390795Sgshapiro * of any contributors may be used to endorse or promote products derived 2438032Speter * from this software without specific prior written permission. 2598125Sgshapiro * 2664565Sgshapiro * Alternatively, this software may be distributed under the terms of the 2738032Speter * GNU General Public License ("GPL") version 2 as published by the Free 2838032Speter * Software Foundation. 2938032Speter * 3038032Speter * NO WARRANTY 3138032Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3238032Speter * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3338032Speter * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3438032Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3538032Speter * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3638032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3738032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3838032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3938032Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4038032Speter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4138032Speter * POSSIBILITY OF SUCH DAMAGES. 4238081Speter */ 4338032Speter 4438032Speter 4564565Sgshapiro#define __NSWALK_C__ 4664565Sgshapiro 4764565Sgshapiro#include <contrib/dev/acpica/include/acpi.h> 4838032Speter#include <contrib/dev/acpica/include/accommon.h> 4938032Speter#include <contrib/dev/acpica/include/acnamesp.h> 5064565Sgshapiro 5138032Speter 5238032Speter#define _COMPONENT ACPI_NAMESPACE 5338032Speter ACPI_MODULE_NAME ("nswalk") 5438032Speter 5538032Speter 5638032Speter/******************************************************************************* 5738032Speter * 5890795Sgshapiro * FUNCTION: AcpiNsGetNextNode 5998125Sgshapiro * 6090795Sgshapiro * PARAMETERS: ParentNode - Parent node whose children we are 6138032Speter * getting 62105016Sgshapiro * ChildNode - Previous child that was found. 63105016Sgshapiro * The NEXT child will be returned 6438032Speter * 6538032Speter * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if 6664565Sgshapiro * none is found. 6738032Speter * 6838032Speter * DESCRIPTION: Return the next peer node within the namespace. If Handle 6964565Sgshapiro * is valid, Scope is ignored. Otherwise, the first node 7038032Speter * within Scope is returned. 7138032Speter * 7238032Speter ******************************************************************************/ 7338032Speter 7490795SgshapiroACPI_NAMESPACE_NODE * 7590795SgshapiroAcpiNsGetNextNode ( 7664565Sgshapiro ACPI_NAMESPACE_NODE *ParentNode, 7738032Speter ACPI_NAMESPACE_NODE *ChildNode) 7838032Speter{ 7990795Sgshapiro ACPI_FUNCTION_ENTRY (); 8090795Sgshapiro 8190795Sgshapiro 8290795Sgshapiro if (!ChildNode) 8390795Sgshapiro { 8464565Sgshapiro /* It's really the parent's _scope_ that we want */ 8538032Speter 8638032Speter return (ParentNode->Child); 8738032Speter } 8838032Speter 8938032Speter /* Otherwise just return the next peer */ 9038032Speter 9190795Sgshapiro return (ChildNode->Peer); 9290795Sgshapiro} 9390795Sgshapiro 9490795Sgshapiro 9590795Sgshapiro/******************************************************************************* 9664565Sgshapiro * 9738032Speter * FUNCTION: AcpiNsGetNextNodeTyped 9864565Sgshapiro * 9964565Sgshapiro * PARAMETERS: Type - Type of node to be searched for 10064565Sgshapiro * ParentNode - Parent node whose children we are 10164565Sgshapiro * getting 10264565Sgshapiro * ChildNode - Previous child that was found. 10364565Sgshapiro * The NEXT child will be returned 10464565Sgshapiro * 10564565Sgshapiro * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if 10664565Sgshapiro * none is found. 10764565Sgshapiro * 10864565Sgshapiro * DESCRIPTION: Return the next peer node within the namespace. If Handle 10964565Sgshapiro * is valid, Scope is ignored. Otherwise, the first node 11064565Sgshapiro * within Scope is returned. 11164565Sgshapiro * 11264565Sgshapiro ******************************************************************************/ 11364565Sgshapiro 11464565SgshapiroACPI_NAMESPACE_NODE * 11564565SgshapiroAcpiNsGetNextNodeTyped ( 11664565Sgshapiro ACPI_OBJECT_TYPE Type, 11790795Sgshapiro ACPI_NAMESPACE_NODE *ParentNode, 11890795Sgshapiro ACPI_NAMESPACE_NODE *ChildNode) 11964565Sgshapiro{ 12064565Sgshapiro ACPI_NAMESPACE_NODE *NextNode = NULL; 12164565Sgshapiro 12264565Sgshapiro 12364565Sgshapiro ACPI_FUNCTION_ENTRY (); 12464565Sgshapiro 12564565Sgshapiro 12690795Sgshapiro NextNode = AcpiNsGetNextNode (ParentNode, ChildNode); 12790795Sgshapiro 12864565Sgshapiro /* If any type is OK, we are done */ 12964565Sgshapiro 13064565Sgshapiro if (Type == ACPI_TYPE_ANY) 13164565Sgshapiro { 13264565Sgshapiro /* NextNode is NULL if we are at the end-of-list */ 13364565Sgshapiro 13498125Sgshapiro return (NextNode); 13590795Sgshapiro } 13664565Sgshapiro 13764565Sgshapiro /* Must search for the node -- but within this scope only */ 13838032Speter 13938032Speter while (NextNode) 14038032Speter { 14138032Speter /* If type matches, we are done */ 14238032Speter 14338032Speter if (NextNode->Type == Type) 14438032Speter { 14564565Sgshapiro return (NextNode); 14638032Speter } 14764565Sgshapiro 14864565Sgshapiro /* Otherwise, move on to the next peer node */ 14938032Speter 15038032Speter NextNode = NextNode->Peer; 15164565Sgshapiro } 152105016Sgshapiro 15338032Speter /* Not found */ 15464565Sgshapiro 15564565Sgshapiro return (NULL); 15638032Speter} 15764565Sgshapiro 15838032Speter 15964565Sgshapiro/******************************************************************************* 16064565Sgshapiro * 16138032Speter * FUNCTION: AcpiNsWalkNamespace 16298125Sgshapiro * 16338032Speter * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for 16438032Speter * StartNode - Handle in namespace where search begins 16538032Speter * MaxDepth - Depth to which search is to reach 16638032Speter * Flags - Whether to unlock the NS before invoking 16738032Speter * the callback routine 16838032Speter * PreOrderVisit - Called during tree pre-order visit 16938032Speter * when an object of "Type" is found 17064565Sgshapiro * PostOrderVisit - Called during tree post-order visit 17164565Sgshapiro * when an object of "Type" is found 17238032Speter * Context - Passed to user function(s) above 17338032Speter * ReturnValue - from the UserFunction if terminated 17490795Sgshapiro * early. Otherwise, returns NULL. 17590795Sgshapiro * RETURNS: Status 17664565Sgshapiro * 17738032Speter * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 17864565Sgshapiro * starting (and ending) at the node specified by StartHandle. 17938032Speter * The callback function is called whenever a node that matches 18038032Speter * the type parameter is found. If the callback function returns 18138032Speter * a non-zero value, the search is terminated immediately and 18277352Sgshapiro * this value is returned to the caller. 18377352Sgshapiro * 18438032Speter * The point of this procedure is to provide a generic namespace 18538032Speter * walk routine that can be called from multiple places to 18638032Speter * provide multiple services; the callback function(s) can be 18738032Speter * tailored to each task, whether it is a print function, 18838032Speter * a compare function, etc. 18938032Speter * 19038032Speter ******************************************************************************/ 19164565Sgshapiro 19238032SpeterACPI_STATUS 19364565SgshapiroAcpiNsWalkNamespace ( 19464565Sgshapiro ACPI_OBJECT_TYPE Type, 19564565Sgshapiro ACPI_HANDLE StartNode, 19638032Speter UINT32 MaxDepth, 19738032Speter UINT32 Flags, 19890795Sgshapiro ACPI_WALK_CALLBACK PreOrderVisit, 19964565Sgshapiro ACPI_WALK_CALLBACK PostOrderVisit, 20064565Sgshapiro void *Context, 20190795Sgshapiro void **ReturnValue) 20238032Speter{ 20338032Speter ACPI_STATUS Status; 20438032Speter ACPI_STATUS MutexStatus; 20538032Speter ACPI_NAMESPACE_NODE *ChildNode; 20638032Speter ACPI_NAMESPACE_NODE *ParentNode; 20790795Sgshapiro ACPI_OBJECT_TYPE ChildType; 20838032Speter UINT32 Level; 20990795Sgshapiro BOOLEAN NodePreviouslyVisited = FALSE; 21090795Sgshapiro 21164565Sgshapiro 21264565Sgshapiro ACPI_FUNCTION_TRACE (NsWalkNamespace); 21364565Sgshapiro 21438032Speter 21538032Speter /* Special case for the namespace Root Node */ 21638032Speter 21764565Sgshapiro if (StartNode == ACPI_ROOT_OBJECT) 21864565Sgshapiro { 21990795Sgshapiro StartNode = AcpiGbl_RootNode; 22038032Speter } 22198125Sgshapiro 22238032Speter /* Null child means "get first node" */ 22364565Sgshapiro 22464565Sgshapiro ParentNode = StartNode; 22564565Sgshapiro ChildNode = AcpiNsGetNextNode (ParentNode, NULL); 22664565Sgshapiro ChildType = ACPI_TYPE_ANY; 22738032Speter Level = 1; 22864565Sgshapiro 22964565Sgshapiro /* 23064565Sgshapiro * Traverse the tree of nodes until we bubble back up to where we 23164565Sgshapiro * started. When Level is zero, the loop is done because we have 23238032Speter * bubbled up to (and passed) the original parent handle (StartEntry) 23364565Sgshapiro */ 23464565Sgshapiro while (Level > 0 && ChildNode) 23590795Sgshapiro { 23690795Sgshapiro Status = AE_OK; 23790795Sgshapiro 23864565Sgshapiro /* Found next child, get the type if we are not searching for ANY */ 23990795Sgshapiro 24064565Sgshapiro if (Type != ACPI_TYPE_ANY) 24164565Sgshapiro { 24264565Sgshapiro ChildType = ChildNode->Type; 24338032Speter } 24438032Speter 24538032Speter /* 24664565Sgshapiro * Ignore all temporary namespace nodes (created during control 24764565Sgshapiro * method execution) unless told otherwise. These temporary nodes 24864565Sgshapiro * can cause a race condition because they can be deleted during 24964565Sgshapiro * the execution of the user function (if the namespace is 25064565Sgshapiro * unlocked before invocation of the user function.) Only the 25164565Sgshapiro * debugger namespace dump will examine the temporary nodes. 25264565Sgshapiro */ 25364565Sgshapiro if ((ChildNode->Flags & ANOBJ_TEMPORARY) && 25464565Sgshapiro !(Flags & ACPI_NS_WALK_TEMP_NODES)) 25564565Sgshapiro { 25664565Sgshapiro Status = AE_CTRL_DEPTH; 25764565Sgshapiro } 25864565Sgshapiro 25964565Sgshapiro /* Type must match requested type */ 26064565Sgshapiro 26164565Sgshapiro else if (ChildType == Type) 26264565Sgshapiro { 26364565Sgshapiro /* 26464565Sgshapiro * Found a matching node, invoke the user callback function. 26538032Speter * Unlock the namespace if flag is set. 26664565Sgshapiro */ 26764565Sgshapiro if (Flags & ACPI_NS_WALK_UNLOCK) 26864565Sgshapiro { 26990795Sgshapiro MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 27098125Sgshapiro if (ACPI_FAILURE (MutexStatus)) 27164565Sgshapiro { 27264565Sgshapiro return_ACPI_STATUS (MutexStatus); 27390795Sgshapiro } 27464565Sgshapiro } 27564565Sgshapiro 27664565Sgshapiro /* 27764565Sgshapiro * Invoke the user function, either pre-order or post-order 27890795Sgshapiro * or both. 27998125Sgshapiro */ 28064565Sgshapiro if (!NodePreviouslyVisited) 28164565Sgshapiro { 28264565Sgshapiro if (PreOrderVisit) 28364565Sgshapiro { 28498125Sgshapiro Status = PreOrderVisit (ChildNode, Level, 28598125Sgshapiro Context, ReturnValue); 28664565Sgshapiro } 28764565Sgshapiro } 28864565Sgshapiro else 28998125Sgshapiro { 29098125Sgshapiro if (PostOrderVisit) 29198125Sgshapiro { 29298125Sgshapiro Status = PostOrderVisit (ChildNode, Level, 29398125Sgshapiro Context, ReturnValue); 29498125Sgshapiro } 29598125Sgshapiro } 29698125Sgshapiro 29798125Sgshapiro if (Flags & ACPI_NS_WALK_UNLOCK) 29898125Sgshapiro { 29998125Sgshapiro MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 30098125Sgshapiro if (ACPI_FAILURE (MutexStatus)) 30198125Sgshapiro { 30298125Sgshapiro return_ACPI_STATUS (MutexStatus); 30398125Sgshapiro } 30498125Sgshapiro } 30598125Sgshapiro 30664565Sgshapiro switch (Status) 30790795Sgshapiro { 30890795Sgshapiro case AE_OK: 30964565Sgshapiro case AE_CTRL_DEPTH: 310105016Sgshapiro 311105016Sgshapiro /* Just keep going */ 312105016Sgshapiro break; 313105016Sgshapiro 314105016Sgshapiro case AE_CTRL_TERMINATE: 315105016Sgshapiro 316105016Sgshapiro /* Exit now, with OK status */ 317105016Sgshapiro 318105016Sgshapiro return_ACPI_STATUS (AE_OK); 319105016Sgshapiro 320105016Sgshapiro default: 321105016Sgshapiro 322105016Sgshapiro /* All others are valid exceptions */ 323105016Sgshapiro 324105016Sgshapiro return_ACPI_STATUS (Status); 325105016Sgshapiro } 326105016Sgshapiro } 327105016Sgshapiro 328105016Sgshapiro /* 329105016Sgshapiro * Depth first search: Attempt to go down another level in the 330105016Sgshapiro * namespace if we are allowed to. Don't go any further if we have 331105016Sgshapiro * reached the caller specified maximum depth or if the user 332105016Sgshapiro * function has specified that the maximum depth has been reached. 333105016Sgshapiro */ 334105016Sgshapiro if (!NodePreviouslyVisited && 335105016Sgshapiro (Level < MaxDepth) && 336105016Sgshapiro (Status != AE_CTRL_DEPTH)) 337105016Sgshapiro { 338105016Sgshapiro if (ChildNode->Child) 339105016Sgshapiro { 340105016Sgshapiro /* There is at least one child of this node, visit it */ 341105016Sgshapiro 34264565Sgshapiro Level++; 34364565Sgshapiro ParentNode = ChildNode; 34464565Sgshapiro ChildNode = AcpiNsGetNextNode (ParentNode, NULL); 34590795Sgshapiro continue; 34690795Sgshapiro } 34790795Sgshapiro } 34864565Sgshapiro 34964565Sgshapiro /* No more children, re-visit this node */ 35064565Sgshapiro 35164565Sgshapiro if (!NodePreviouslyVisited) 35290795Sgshapiro { 35364565Sgshapiro NodePreviouslyVisited = TRUE; 35464565Sgshapiro continue; 35564565Sgshapiro } 35638032Speter 35764565Sgshapiro /* No more children, visit peers */ 35864565Sgshapiro 35964565Sgshapiro ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); 36064565Sgshapiro if (ChildNode) 36190795Sgshapiro { 36264565Sgshapiro NodePreviouslyVisited = FALSE; 36390795Sgshapiro } 36464565Sgshapiro 36538032Speter /* No peers, re-visit parent */ 36638032Speter 36764565Sgshapiro else 36864565Sgshapiro { 36964565Sgshapiro /* 37064565Sgshapiro * No more children of this node (AcpiNsGetNextNode failed), go 37190795Sgshapiro * back upwards in the namespace tree to the node's parent. 37290795Sgshapiro */ 37390795Sgshapiro Level--; 37464565Sgshapiro ChildNode = ParentNode; 37564565Sgshapiro ParentNode = ParentNode->Parent; 37664565Sgshapiro 37790795Sgshapiro NodePreviouslyVisited = TRUE; 37890795Sgshapiro } 37990795Sgshapiro } 38064565Sgshapiro 38164565Sgshapiro /* Complete walk, not terminated by user function */ 38264565Sgshapiro 38364565Sgshapiro return_ACPI_STATUS (AE_OK); 38464565Sgshapiro} 38564565Sgshapiro 38664565Sgshapiro 38790795Sgshapiro