FreeBSD/sys/contrib/dev/acpica/components/namespace/nswalk.c
/*******************************************************************************
 *
 * FUNCTION:    AcpiNsWalkNamespace
 *
 * PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
 *              StartNode           - Handle in namespace where search begins
 *              MaxDepth            - Depth to which search is to reach
 *              Flags               - Whether to unlock the NS before invoking
 *                                    the callback routine
 *              DescendingCallback  - Called during tree descent
 *                                    when an object of "Type" is found
 *              AscendingCallback   - Called during tree ascent
 *                                    when an object of "Type" is found
 *              Context             - Passed to user function(s) above
 *              ReturnValue         - from the UserFunction if terminated
 *                                    early. Otherwise, returns NULL.
 * RETURNS:     Status
 *
 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
 *              starting (and ending) at the node specified by StartHandle.
 *              The callback function is called whenever a node that matches
 *              the type parameter is found. If the callback function returns
 *              a non-zero value, the search is terminated immediately and
 *              this value is returned to the caller.
 *
 *              The point of this procedure is to provide a generic namespace
 *              walk routine that can be called from multiple places to
 *              provide multiple services; the callback function(s) can be
 *              tailored to each task, whether it is a print function,
 *              a compare function, etc.
 *
 ******************************************************************************/


Performs a modified depth-first walk of the namespace tree,
starting (and ending) at the node specified by StartHandle.
The callback function is called whenever a node that matches
the type parameter is found. If the callback function returns
a non-zero value, the search is terminated immediately and
this value is returned to the caller.

The point of this procedure is to provide a generic namespace
walk routine that can be called from multiple places to
provide multiple services; the callback function(s) can be
tailored to each task, whether it is a print function,
a compare function, etc.
Performs a modified depth - first walk of the namespace tree starting ( and ending ) at the node specified by StartHandle . The callback function is called whenever a node that matches the type parameter is found . If the callback function returns a non - zero value the search is terminated immediately and this value is returned to the caller . The point of this procedure is to provide a generic namespace walk routine that can be called from multiple places to provide multiple services ; the callback function ( s ) can be tailored to each task whether it is a print function a compare function etc .
ACPI_STATUS
AcpiNsWalkNamespace (
    ACPI_OBJECT_TYPE        Type,
    ACPI_HANDLE             StartNode,
    UINT32                  MaxDepth,
    UINT32                  Flags,
    ACPI_WALK_CALLBACK      DescendingCallback,
    ACPI_WALK_CALLBACK      AscendingCallback,
    void                    *Context,
    void                    **ReturnValue)
{
    ACPI_STATUS             Status;
    ACPI_STATUS             MutexStatus;
    ACPI_NAMESPACE_NODE     *ChildNode;
    ACPI_NAMESPACE_NODE     *ParentNode;
    ACPI_OBJECT_TYPE        ChildType;
    UINT32                  Level;
    BOOLEAN                 NodePreviouslyVisited = FALSE;
    ACPI_FUNCTION_TRACE (NsWalkNamespace);
    if (StartNode == ACPI_ROOT_OBJECT)
    {
        StartNode = AcpiGbl_RootNode;
    }
    ParentNode = StartNode;
    ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
    ChildType = ACPI_TYPE_ANY;
    Level = 1;
    while (Level > 0 && ChildNode)
    {
        Status = AE_OK;
        if (Type != ACPI_TYPE_ANY)
        {
            ChildType = ChildNode->Type;
        }
        if ((ChildNode->Flags & ANOBJ_TEMPORARY) &&
            !(Flags & ACPI_NS_WALK_TEMP_NODES))
        {
            Status = AE_CTRL_DEPTH;
        }
        else if (ChildType == Type)
        {
            if (Flags & ACPI_NS_WALK_UNLOCK)
            {
                MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
                if (ACPI_FAILURE (MutexStatus))
                {
                    return_ACPI_STATUS (MutexStatus);
                }
            }
            if (!NodePreviouslyVisited)
            {
                if (DescendingCallback)
                {
                    Status = DescendingCallback (ChildNode, Level,
                        Context, ReturnValue);
                }
            }
            else
            {
                if (AscendingCallback)
                {
                    Status = AscendingCallback (ChildNode, Level,
                        Context, ReturnValue);
                }
            }
            if (Flags & ACPI_NS_WALK_UNLOCK)
            {
                MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
                if (ACPI_FAILURE (MutexStatus))
                {
                    return_ACPI_STATUS (MutexStatus);
                }
            }
            switch (Status)
            {
            case AE_OK:
            case AE_CTRL_DEPTH:
                break;
            case AE_CTRL_TERMINATE:
                return_ACPI_STATUS (AE_OK);
            default:
                return_ACPI_STATUS (Status);
            }
        }
        if (!NodePreviouslyVisited &&
            (Level < MaxDepth) &&
            (Status != AE_CTRL_DEPTH))
        {
            if (ChildNode->Child)
            {
                Level++;
                ParentNode = ChildNode;
                ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
                continue;
            }
        }
        if (!NodePreviouslyVisited)
        {
            NodePreviouslyVisited = TRUE;
            continue;
        }
        ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
        if (ChildNode)
        {
            NodePreviouslyVisited = FALSE;
        }
        else
        {
            Level--;
            ChildNode = ParentNode;
            ParentNode = ParentNode->Parent;
            NodePreviouslyVisited = TRUE;
        }
    }
    return_ACPI_STATUS (AE_OK);
}
ACPI_STATUS AcpiNsWalkNamespace ( ACPI_OBJECT_TYPE Type , ACPI_HANDLE StartNode , UINT32 MaxDepth , UINT32 Flags , ACPI_WALK_CALLBACK DescendingCallback , ACPI_WALK_CALLBACK AscendingCallback , void * Context , void * * ReturnValue ) { ACPI_STATUS Status ; ACPI_STATUS MutexStatus ; ACPI_NAMESPACE_NODE * ChildNode ; ACPI_NAMESPACE_NODE * ParentNode ; ACPI_OBJECT_TYPE ChildType ; UINT32 Level ; BOOLEAN NodePreviouslyVisited = FALSE ; ACPI_FUNCTION_TRACE ( NsWalkNamespace ) ; if ( StartNode == ACPI_ROOT_OBJECT ) { StartNode = AcpiGbl_RootNode ; } ParentNode = StartNode ; ChildNode = AcpiNsGetNextNode ( ParentNode , NULL ) ; ChildType = ACPI_TYPE_ANY ; Level = 1 ; while ( Level > 0 && ChildNode ) { Status = AE_OK ; if ( Type != ACPI_TYPE_ANY ) { ChildType = ChildNode -> Type ; } if ( ( ChildNode -> Flags & ANOBJ_TEMPORARY ) && ! ( Flags & ACPI_NS_WALK_TEMP_NODES ) ) { Status = AE_CTRL_DEPTH ; } else if ( ChildType == Type ) { if ( Flags & ACPI_NS_WALK_UNLOCK ) { MutexStatus = AcpiUtReleaseMutex ( ACPI_MTX_NAMESPACE ) ; if ( ACPI_FAILURE ( MutexStatus ) ) { return_ACPI_STATUS ( MutexStatus ) ; } } if ( ! NodePreviouslyVisited ) { if ( DescendingCallback ) { Status = DescendingCallback ( ChildNode , Level , Context , ReturnValue ) ; } } else { if ( AscendingCallback ) { Status = AscendingCallback ( ChildNode , Level , Context , ReturnValue ) ; } } if ( Flags & ACPI_NS_WALK_UNLOCK ) { MutexStatus = AcpiUtAcquireMutex ( ACPI_MTX_NAMESPACE ) ; if ( ACPI_FAILURE ( MutexStatus ) ) { return_ACPI_STATUS ( MutexStatus ) ; } } switch ( Status ) { case AE_OK : case AE_CTRL_DEPTH : break ; case AE_CTRL_TERMINATE : return_ACPI_STATUS ( AE_OK ) ; default : return_ACPI_STATUS ( Status ) ; } } if ( ! NodePreviouslyVisited && ( Level < MaxDepth ) && ( Status != AE_CTRL_DEPTH ) ) { if ( ChildNode -> Child ) { Level ++ ; ParentNode = ChildNode ; ChildNode = AcpiNsGetNextNode ( ParentNode , NULL ) ; continue ; } } if ( ! NodePreviouslyVisited ) { NodePreviouslyVisited = TRUE ; continue ; } ChildNode = AcpiNsGetNextNode ( ParentNode , ChildNode ) ; if ( ChildNode ) { NodePreviouslyVisited = FALSE ; } else { Level -- ; ChildNode = ParentNode ; ParentNode = ParentNode -> Parent ; NodePreviouslyVisited = TRUE ; } } return_ACPI_STATUS ( AE_OK ) ; }
FUNCTION:    AcpiNsWalkNamespace
 PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
              StartNode           - Handle in namespace where search begins
              MaxDepth            - Depth to which search is to reach
              Flags               - Whether to unlock the NS before invoking
                                    the callback routine
              DescendingCallback  - Called during tree descent
                                    when an object of "Type" is found
              AscendingCallback   - Called during tree ascent
                                    when an object of "Type" is found
              Context             - Passed to user function(s) above
              ReturnValue         - from the UserFunction if terminated
                                    early.
FUNCTION : AcpiNsWalkNamespace PARAMETERS : Type - ACPI_OBJECT_TYPE to search for StartNode - Handle in namespace where search begins MaxDepth - Depth to which search is to reach Flags - Whether to unlock the NS before invoking the callback routine DescendingCallback - Called during tree descent when an object of " Type " is found AscendingCallback - Called during tree ascent when an object of " Type " is found Context - Passed to user function ( s ) above ReturnValue - from the UserFunction if terminated early .
/* Special case for the namespace Root Node */ /* Null child means "get first node" */ /*
     * Traverse the tree of nodes until we bubble back up to where we
     * started. When Level is zero, the loop is done because we have
     * bubbled up to (and passed) the original parent handle (StartEntry)
     */ /* Found next child, get the type if we are not searching for ANY */ /*
         * Ignore all temporary namespace nodes (created during control
         * method execution) unless told otherwise. These temporary nodes
         * can cause a race condition because they can be deleted during
         * the execution of the user function (if the namespace is
         * unlocked before invocation of the user function.) Only the
         * debugger namespace dump will examine the temporary nodes.
         */ /* Type must match requested type */ /*
             * Found a matching node, invoke the user callback function.
             * Unlock the namespace if flag is set.
             */ /*
             * Invoke the user function, either descending, ascending,
             * or both.
             */ /* Just keep going */ /* Exit now, with OK status */ /* All others are valid exceptions */ /*
         * Depth first search: Attempt to go down another level in the
         * namespace if we are allowed to. Don't go any further if we have
         * reached the caller specified maximum depth or if the user
         * function has specified that the maximum depth has been reached.
         */ /* There is at least one child of this node, visit it */ /* No more children, re-visit this node */ /* No more children, visit peers */ /* No peers, re-visit parent */ /*
             * No more children of this node (AcpiNsGetNextNode failed), go
             * back upwards in the namespace tree to the node's parent.
             */ /* Complete walk, not terminated by user function */