167754Smsmith/****************************************************************************** 267754Smsmith * 382367Smsmith * Module Name: nswalk - Functions for walking the ACPI namespace 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 7217365Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 970243Smsmith * All rights reserved. 1067754Smsmith * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 2567754Smsmith * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 2967754Smsmith * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 4367754Smsmith 44193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 45193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 46193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h> 4767754Smsmith 4867754Smsmith 4977424Smsmith#define _COMPONENT ACPI_NAMESPACE 5091116Smsmith ACPI_MODULE_NAME ("nswalk") 5167754Smsmith 5267754Smsmith 5385756Smsmith/******************************************************************************* 5467754Smsmith * 5585756Smsmith * FUNCTION: AcpiNsGetNextNode 5667754Smsmith * 57193267Sjkim * PARAMETERS: ParentNode - Parent node whose children we are 58151937Sjkim * getting 5985756Smsmith * ChildNode - Previous child that was found. 6067754Smsmith * The NEXT child will be returned 6167754Smsmith * 6267754Smsmith * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if 6385756Smsmith * none is found. 6467754Smsmith * 65241973Sjkim * DESCRIPTION: Return the next peer node within the namespace. If Handle 66241973Sjkim * is valid, Scope is ignored. Otherwise, the first node 6767754Smsmith * within Scope is returned. 6867754Smsmith * 6985756Smsmith ******************************************************************************/ 7067754Smsmith 7167754SmsmithACPI_NAMESPACE_NODE * 7285756SmsmithAcpiNsGetNextNode ( 7367754Smsmith ACPI_NAMESPACE_NODE *ParentNode, 7467754Smsmith ACPI_NAMESPACE_NODE *ChildNode) 7567754Smsmith{ 7691116Smsmith ACPI_FUNCTION_ENTRY (); 7783174Smsmith 7883174Smsmith 7967754Smsmith if (!ChildNode) 8067754Smsmith { 8167754Smsmith /* It's really the parent's _scope_ that we want */ 8267754Smsmith 83193267Sjkim return (ParentNode->Child); 8467754Smsmith } 8567754Smsmith 86193267Sjkim /* Otherwise just return the next peer */ 87193267Sjkim 88193267Sjkim return (ChildNode->Peer); 89193267Sjkim} 90193267Sjkim 91193267Sjkim 92193267Sjkim/******************************************************************************* 93193267Sjkim * 94193267Sjkim * FUNCTION: AcpiNsGetNextNodeTyped 95193267Sjkim * 96193267Sjkim * PARAMETERS: Type - Type of node to be searched for 97193267Sjkim * ParentNode - Parent node whose children we are 98193267Sjkim * getting 99193267Sjkim * ChildNode - Previous child that was found. 100193267Sjkim * The NEXT child will be returned 101193267Sjkim * 102193267Sjkim * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if 103193267Sjkim * none is found. 104193267Sjkim * 105241973Sjkim * DESCRIPTION: Return the next peer node within the namespace. If Handle 106241973Sjkim * is valid, Scope is ignored. Otherwise, the first node 107193267Sjkim * within Scope is returned. 108193267Sjkim * 109193267Sjkim ******************************************************************************/ 110193267Sjkim 111193267SjkimACPI_NAMESPACE_NODE * 112193267SjkimAcpiNsGetNextNodeTyped ( 113193267Sjkim ACPI_OBJECT_TYPE Type, 114193267Sjkim ACPI_NAMESPACE_NODE *ParentNode, 115193267Sjkim ACPI_NAMESPACE_NODE *ChildNode) 116193267Sjkim{ 117193267Sjkim ACPI_NAMESPACE_NODE *NextNode = NULL; 118193267Sjkim 119193267Sjkim 120193267Sjkim ACPI_FUNCTION_ENTRY (); 121193267Sjkim 122193267Sjkim 123193267Sjkim NextNode = AcpiNsGetNextNode (ParentNode, ChildNode); 124193267Sjkim 12567754Smsmith /* If any type is OK, we are done */ 12667754Smsmith 12767754Smsmith if (Type == ACPI_TYPE_ANY) 12867754Smsmith { 12967754Smsmith /* NextNode is NULL if we are at the end-of-list */ 13067754Smsmith 13167754Smsmith return (NextNode); 13267754Smsmith } 13367754Smsmith 13485756Smsmith /* Must search for the node -- but within this scope only */ 13567754Smsmith 13667754Smsmith while (NextNode) 13767754Smsmith { 13867754Smsmith /* If type matches, we are done */ 13967754Smsmith 14067754Smsmith if (NextNode->Type == Type) 14167754Smsmith { 14267754Smsmith return (NextNode); 14367754Smsmith } 14467754Smsmith 145209746Sjkim /* Otherwise, move on to the next peer node */ 14667754Smsmith 147209746Sjkim NextNode = NextNode->Peer; 14867754Smsmith } 14967754Smsmith 15067754Smsmith /* Not found */ 15167754Smsmith 15267754Smsmith return (NULL); 15367754Smsmith} 15467754Smsmith 15567754Smsmith 15685756Smsmith/******************************************************************************* 15767754Smsmith * 15867754Smsmith * FUNCTION: AcpiNsWalkNamespace 15967754Smsmith * 16067754Smsmith * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for 16167754Smsmith * StartNode - Handle in namespace where search begins 16267754Smsmith * MaxDepth - Depth to which search is to reach 163167802Sjkim * Flags - Whether to unlock the NS before invoking 16467754Smsmith * the callback routine 165253690Sjkim * DescendingCallback - Called during tree descent 166199337Sjkim * when an object of "Type" is found 167253690Sjkim * AscendingCallback - Called during tree ascent 168199337Sjkim * when an object of "Type" is found 169199337Sjkim * Context - Passed to user function(s) above 170199337Sjkim * ReturnValue - from the UserFunction if terminated 171199337Sjkim * early. Otherwise, returns NULL. 17285756Smsmith * RETURNS: Status 17367754Smsmith * 17467754Smsmith * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 17585756Smsmith * starting (and ending) at the node specified by StartHandle. 176199337Sjkim * The callback function is called whenever a node that matches 177199337Sjkim * the type parameter is found. If the callback function returns 178193267Sjkim * a non-zero value, the search is terminated immediately and 179193267Sjkim * this value is returned to the caller. 18067754Smsmith * 18167754Smsmith * The point of this procedure is to provide a generic namespace 18267754Smsmith * walk routine that can be called from multiple places to 183199337Sjkim * provide multiple services; the callback function(s) can be 184199337Sjkim * tailored to each task, whether it is a print function, 185199337Sjkim * a compare function, etc. 18667754Smsmith * 18767754Smsmith ******************************************************************************/ 18867754Smsmith 18967754SmsmithACPI_STATUS 19067754SmsmithAcpiNsWalkNamespace ( 19191116Smsmith ACPI_OBJECT_TYPE Type, 19267754Smsmith ACPI_HANDLE StartNode, 19367754Smsmith UINT32 MaxDepth, 194167802Sjkim UINT32 Flags, 195253690Sjkim ACPI_WALK_CALLBACK DescendingCallback, 196253690Sjkim ACPI_WALK_CALLBACK AscendingCallback, 19767754Smsmith void *Context, 19867754Smsmith void **ReturnValue) 19967754Smsmith{ 20067754Smsmith ACPI_STATUS Status; 201117521Snjl ACPI_STATUS MutexStatus; 20267754Smsmith ACPI_NAMESPACE_NODE *ChildNode; 20367754Smsmith ACPI_NAMESPACE_NODE *ParentNode; 20491116Smsmith ACPI_OBJECT_TYPE ChildType; 20567754Smsmith UINT32 Level; 206199337Sjkim BOOLEAN NodePreviouslyVisited = FALSE; 20767754Smsmith 20867754Smsmith 209167802Sjkim ACPI_FUNCTION_TRACE (NsWalkNamespace); 21067754Smsmith 21183174Smsmith 21267754Smsmith /* Special case for the namespace Root Node */ 21367754Smsmith 21467754Smsmith if (StartNode == ACPI_ROOT_OBJECT) 21567754Smsmith { 21667754Smsmith StartNode = AcpiGbl_RootNode; 21767754Smsmith } 21867754Smsmith 21985756Smsmith /* Null child means "get first node" */ 22067754Smsmith 221306536Sjkim ParentNode = StartNode; 222306536Sjkim ChildNode = AcpiNsGetNextNode (ParentNode, NULL); 223306536Sjkim ChildType = ACPI_TYPE_ANY; 224306536Sjkim Level = 1; 22567754Smsmith 22667754Smsmith /* 22785756Smsmith * Traverse the tree of nodes until we bubble back up to where we 22867754Smsmith * started. When Level is zero, the loop is done because we have 22967754Smsmith * bubbled up to (and passed) the original parent handle (StartEntry) 23067754Smsmith */ 231199337Sjkim while (Level > 0 && ChildNode) 23267754Smsmith { 233199337Sjkim Status = AE_OK; 23485756Smsmith 235199337Sjkim /* Found next child, get the type if we are not searching for ANY */ 236199337Sjkim 237199337Sjkim if (Type != ACPI_TYPE_ANY) 23867754Smsmith { 239199337Sjkim ChildType = ChildNode->Type; 240199337Sjkim } 241167802Sjkim 242199337Sjkim /* 243199337Sjkim * Ignore all temporary namespace nodes (created during control 244199337Sjkim * method execution) unless told otherwise. These temporary nodes 245199337Sjkim * can cause a race condition because they can be deleted during 246199337Sjkim * the execution of the user function (if the namespace is 247199337Sjkim * unlocked before invocation of the user function.) Only the 248199337Sjkim * debugger namespace dump will examine the temporary nodes. 249199337Sjkim */ 250199337Sjkim if ((ChildNode->Flags & ANOBJ_TEMPORARY) && 251199337Sjkim !(Flags & ACPI_NS_WALK_TEMP_NODES)) 252199337Sjkim { 253199337Sjkim Status = AE_CTRL_DEPTH; 254199337Sjkim } 255199337Sjkim 256199337Sjkim /* Type must match requested type */ 257199337Sjkim 258199337Sjkim else if (ChildType == Type) 259199337Sjkim { 260199337Sjkim /* 261199337Sjkim * Found a matching node, invoke the user callback function. 262199337Sjkim * Unlock the namespace if flag is set. 263199337Sjkim */ 264199337Sjkim if (Flags & ACPI_NS_WALK_UNLOCK) 26567754Smsmith { 266199337Sjkim MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 267199337Sjkim if (ACPI_FAILURE (MutexStatus)) 268199337Sjkim { 269199337Sjkim return_ACPI_STATUS (MutexStatus); 270199337Sjkim } 27167754Smsmith } 27267754Smsmith 273167802Sjkim /* 274253690Sjkim * Invoke the user function, either descending, ascending, 275199337Sjkim * or both. 276167802Sjkim */ 277199337Sjkim if (!NodePreviouslyVisited) 27867754Smsmith { 279253690Sjkim if (DescendingCallback) 280199337Sjkim { 281253690Sjkim Status = DescendingCallback (ChildNode, Level, 282306536Sjkim Context, ReturnValue); 283199337Sjkim } 284167802Sjkim } 285199337Sjkim else 286167802Sjkim { 287253690Sjkim if (AscendingCallback) 28867754Smsmith { 289253690Sjkim Status = AscendingCallback (ChildNode, Level, 290306536Sjkim Context, ReturnValue); 29167754Smsmith } 292199337Sjkim } 29367754Smsmith 294199337Sjkim if (Flags & ACPI_NS_WALK_UNLOCK) 295199337Sjkim { 296199337Sjkim MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 297199337Sjkim if (ACPI_FAILURE (MutexStatus)) 29867754Smsmith { 299199337Sjkim return_ACPI_STATUS (MutexStatus); 30067754Smsmith } 301199337Sjkim } 30267754Smsmith 303199337Sjkim switch (Status) 304199337Sjkim { 305199337Sjkim case AE_OK: 306199337Sjkim case AE_CTRL_DEPTH: 30783174Smsmith 308199337Sjkim /* Just keep going */ 309199337Sjkim break; 31067754Smsmith 311199337Sjkim case AE_CTRL_TERMINATE: 31283174Smsmith 313199337Sjkim /* Exit now, with OK status */ 31483174Smsmith 315199337Sjkim return_ACPI_STATUS (AE_OK); 31667754Smsmith 317199337Sjkim default: 31883174Smsmith 319199337Sjkim /* All others are valid exceptions */ 32083174Smsmith 321199337Sjkim return_ACPI_STATUS (Status); 32267754Smsmith } 323199337Sjkim } 32467754Smsmith 325199337Sjkim /* 326199337Sjkim * Depth first search: Attempt to go down another level in the 327241973Sjkim * namespace if we are allowed to. Don't go any further if we have 328199337Sjkim * reached the caller specified maximum depth or if the user 329199337Sjkim * function has specified that the maximum depth has been reached. 330199337Sjkim */ 331199337Sjkim if (!NodePreviouslyVisited && 332199337Sjkim (Level < MaxDepth) && 333199337Sjkim (Status != AE_CTRL_DEPTH)) 334199337Sjkim { 335199337Sjkim if (ChildNode->Child) 33667754Smsmith { 337199337Sjkim /* There is at least one child of this node, visit it */ 338167802Sjkim 339199337Sjkim Level++; 340199337Sjkim ParentNode = ChildNode; 341199337Sjkim ChildNode = AcpiNsGetNextNode (ParentNode, NULL); 342199337Sjkim continue; 34367754Smsmith } 34467754Smsmith } 345199337Sjkim 346199337Sjkim /* No more children, re-visit this node */ 347199337Sjkim 348199337Sjkim if (!NodePreviouslyVisited) 349199337Sjkim { 350199337Sjkim NodePreviouslyVisited = TRUE; 351199337Sjkim continue; 352199337Sjkim } 353199337Sjkim 354199337Sjkim /* No more children, visit peers */ 355199337Sjkim 356199337Sjkim ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode); 357199337Sjkim if (ChildNode) 358199337Sjkim { 359199337Sjkim NodePreviouslyVisited = FALSE; 360199337Sjkim } 361199337Sjkim 362199337Sjkim /* No peers, re-visit parent */ 363199337Sjkim 36467754Smsmith else 36567754Smsmith { 36667754Smsmith /* 367167802Sjkim * No more children of this node (AcpiNsGetNextNode failed), go 368167802Sjkim * back upwards in the namespace tree to the node's parent. 36967754Smsmith */ 37067754Smsmith Level--; 37167754Smsmith ChildNode = ParentNode; 372209746Sjkim ParentNode = ParentNode->Parent; 373199337Sjkim 374199337Sjkim NodePreviouslyVisited = TRUE; 37567754Smsmith } 37667754Smsmith } 37767754Smsmith 37867754Smsmith /* Complete walk, not terminated by user function */ 37983174Smsmith 38067754Smsmith return_ACPI_STATUS (AE_OK); 38167754Smsmith} 382