xref: /freebsd/sys/contrib/dev/acpica/components/namespace/nsxfeval.c (revision 7453645f2a9411a3f9d982b768bcc323f41cf906)
1 /*******************************************************************************
2  *
3  * Module Name: nsxfeval - Public interfaces to the ACPI subsystem
4  *                         ACPI Object evaluation interfaces
5  *
6  ******************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2016, 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 #define EXPORT_ACPI_INTERFACES
46 
47 #include <contrib/dev/acpica/include/acpi.h>
48 #include <contrib/dev/acpica/include/accommon.h>
49 #include <contrib/dev/acpica/include/acnamesp.h>
50 #include <contrib/dev/acpica/include/acinterp.h>
51 
52 
53 #define _COMPONENT          ACPI_NAMESPACE
54         ACPI_MODULE_NAME    ("nsxfeval")
55 
56 /* Local prototypes */
57 
58 static void
59 AcpiNsResolveReferences (
60     ACPI_EVALUATE_INFO      *Info);
61 
62 
63 /*******************************************************************************
64  *
65  * FUNCTION:    AcpiEvaluateObjectTyped
66  *
67  * PARAMETERS:  Handle              - Object handle (optional)
68  *              Pathname            - Object pathname (optional)
69  *              ExternalParams      - List of parameters to pass to method,
70  *                                    terminated by NULL. May be NULL
71  *                                    if no parameters are being passed.
72  *              ReturnBuffer        - Where to put method's return value (if
73  *                                    any). If NULL, no value is returned.
74  *              ReturnType          - Expected type of return object
75  *
76  * RETURN:      Status
77  *
78  * DESCRIPTION: Find and evaluate the given object, passing the given
79  *              parameters if necessary. One of "Handle" or "Pathname" must
80  *              be valid (non-null)
81  *
82  ******************************************************************************/
83 
84 ACPI_STATUS
85 AcpiEvaluateObjectTyped (
86     ACPI_HANDLE             Handle,
87     ACPI_STRING             Pathname,
88     ACPI_OBJECT_LIST        *ExternalParams,
89     ACPI_BUFFER             *ReturnBuffer,
90     ACPI_OBJECT_TYPE        ReturnType)
91 {
92     ACPI_STATUS             Status;
93     BOOLEAN                 FreeBufferOnError = FALSE;
94 
95 
96     ACPI_FUNCTION_TRACE (AcpiEvaluateObjectTyped);
97 
98 
99     /* Return buffer must be valid */
100 
101     if (!ReturnBuffer)
102     {
103         return_ACPI_STATUS (AE_BAD_PARAMETER);
104     }
105 
106     if (ReturnBuffer->Length == ACPI_ALLOCATE_BUFFER)
107     {
108         FreeBufferOnError = TRUE;
109     }
110 
111     /* Evaluate the object */
112 
113     Status = AcpiEvaluateObject (Handle, Pathname,
114         ExternalParams, ReturnBuffer);
115     if (ACPI_FAILURE (Status))
116     {
117         return_ACPI_STATUS (Status);
118     }
119 
120     /* Type ANY means "don't care" */
121 
122     if (ReturnType == ACPI_TYPE_ANY)
123     {
124         return_ACPI_STATUS (AE_OK);
125     }
126 
127     if (ReturnBuffer->Length == 0)
128     {
129         /* Error because caller specifically asked for a return value */
130 
131         ACPI_ERROR ((AE_INFO, "No return value"));
132         return_ACPI_STATUS (AE_NULL_OBJECT);
133     }
134 
135     /* Examine the object type returned from EvaluateObject */
136 
137     if (((ACPI_OBJECT *) ReturnBuffer->Pointer)->Type == ReturnType)
138     {
139         return_ACPI_STATUS (AE_OK);
140     }
141 
142     /* Return object type does not match requested type */
143 
144     ACPI_ERROR ((AE_INFO,
145         "Incorrect return type [%s] requested [%s]",
146         AcpiUtGetTypeName (((ACPI_OBJECT *) ReturnBuffer->Pointer)->Type),
147         AcpiUtGetTypeName (ReturnType)));
148 
149     if (FreeBufferOnError)
150     {
151         /*
152          * Free a buffer created via ACPI_ALLOCATE_BUFFER.
153          * Note: We use AcpiOsFree here because AcpiOsAllocate was used
154          * to allocate the buffer. This purposefully bypasses the
155          * (optionally enabled) allocation tracking mechanism since we
156          * only want to track internal allocations.
157          */
158         AcpiOsFree (ReturnBuffer->Pointer);
159         ReturnBuffer->Pointer = NULL;
160     }
161 
162     ReturnBuffer->Length = 0;
163     return_ACPI_STATUS (AE_TYPE);
164 }
165 
166 ACPI_EXPORT_SYMBOL (AcpiEvaluateObjectTyped)
167 
168 
169 /*******************************************************************************
170  *
171  * FUNCTION:    AcpiEvaluateObject
172  *
173  * PARAMETERS:  Handle              - Object handle (optional)
174  *              Pathname            - Object pathname (optional)
175  *              ExternalParams      - List of parameters to pass to method,
176  *                                    terminated by NULL. May be NULL
177  *                                    if no parameters are being passed.
178  *              ReturnBuffer        - Where to put method's return value (if
179  *                                    any). If NULL, no value is returned.
180  *
181  * RETURN:      Status
182  *
183  * DESCRIPTION: Find and evaluate the given object, passing the given
184  *              parameters if necessary. One of "Handle" or "Pathname" must
185  *              be valid (non-null)
186  *
187  ******************************************************************************/
188 
189 ACPI_STATUS
190 AcpiEvaluateObject (
191     ACPI_HANDLE             Handle,
192     ACPI_STRING             Pathname,
193     ACPI_OBJECT_LIST        *ExternalParams,
194     ACPI_BUFFER             *ReturnBuffer)
195 {
196     ACPI_STATUS             Status;
197     ACPI_EVALUATE_INFO      *Info;
198     ACPI_SIZE               BufferSpaceNeeded;
199     UINT32                  i;
200 
201 
202     ACPI_FUNCTION_TRACE (AcpiEvaluateObject);
203 
204 
205     /* Allocate and initialize the evaluation information block */
206 
207     Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO));
208     if (!Info)
209     {
210         return_ACPI_STATUS (AE_NO_MEMORY);
211     }
212 
213     /* Convert and validate the device handle */
214 
215     Info->PrefixNode = AcpiNsValidateHandle (Handle);
216     if (!Info->PrefixNode)
217     {
218         Status = AE_BAD_PARAMETER;
219         goto Cleanup;
220     }
221 
222     /*
223      * Get the actual namespace node for the target object.
224      * Handles these cases:
225      *
226      * 1) Null node, valid pathname from root (absolute path)
227      * 2) Node and valid pathname (path relative to Node)
228      * 3) Node, Null pathname
229      */
230     if ((Pathname) &&
231         (ACPI_IS_ROOT_PREFIX (Pathname[0])))
232     {
233         /* The path is fully qualified, just evaluate by name */
234 
235         Info->PrefixNode = NULL;
236     }
237     else if (!Handle)
238     {
239         /*
240          * A handle is optional iff a fully qualified pathname is specified.
241          * Since we've already handled fully qualified names above, this is
242          * an error.
243          */
244         if (!Pathname)
245         {
246             ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
247                 "Both Handle and Pathname are NULL"));
248         }
249         else
250         {
251             ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
252                 "Null Handle with relative pathname [%s]", Pathname));
253         }
254 
255         Status = AE_BAD_PARAMETER;
256         goto Cleanup;
257     }
258 
259     Info->RelativePathname = Pathname;
260 
261     /*
262      * Convert all external objects passed as arguments to the
263      * internal version(s).
264      */
265     if (ExternalParams && ExternalParams->Count)
266     {
267         Info->ParamCount = (UINT16) ExternalParams->Count;
268 
269         /* Warn on impossible argument count */
270 
271         if (Info->ParamCount > ACPI_METHOD_NUM_ARGS)
272         {
273             ACPI_WARN_PREDEFINED ((AE_INFO, Pathname, ACPI_WARN_ALWAYS,
274                 "Excess arguments (%u) - using only %u",
275                 Info->ParamCount, ACPI_METHOD_NUM_ARGS));
276 
277             Info->ParamCount = ACPI_METHOD_NUM_ARGS;
278         }
279 
280         /*
281          * Allocate a new parameter block for the internal objects
282          * Add 1 to count to allow for null terminated internal list
283          */
284         Info->Parameters = ACPI_ALLOCATE_ZEROED (
285             ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *));
286         if (!Info->Parameters)
287         {
288             Status = AE_NO_MEMORY;
289             goto Cleanup;
290         }
291 
292         /* Convert each external object in the list to an internal object */
293 
294         for (i = 0; i < Info->ParamCount; i++)
295         {
296             Status = AcpiUtCopyEobjectToIobject (
297                 &ExternalParams->Pointer[i], &Info->Parameters[i]);
298             if (ACPI_FAILURE (Status))
299             {
300                 goto Cleanup;
301             }
302         }
303 
304         Info->Parameters[Info->ParamCount] = NULL;
305     }
306 
307 
308 #ifdef _FUTURE_FEATURE
309 
310     /*
311      * Begin incoming argument count analysis. Check for too few args
312      * and too many args.
313      */
314     switch (AcpiNsGetType (Info->Node))
315     {
316     case ACPI_TYPE_METHOD:
317 
318         /* Check incoming argument count against the method definition */
319 
320         if (Info->ObjDesc->Method.ParamCount > Info->ParamCount)
321         {
322             ACPI_ERROR ((AE_INFO,
323                 "Insufficient arguments (%u) - %u are required",
324                 Info->ParamCount,
325                 Info->ObjDesc->Method.ParamCount));
326 
327             Status = AE_MISSING_ARGUMENTS;
328             goto Cleanup;
329         }
330 
331         else if (Info->ObjDesc->Method.ParamCount < Info->ParamCount)
332         {
333             ACPI_WARNING ((AE_INFO,
334                 "Excess arguments (%u) - only %u are required",
335                 Info->ParamCount,
336                 Info->ObjDesc->Method.ParamCount));
337 
338             /* Just pass the required number of arguments */
339 
340             Info->ParamCount = Info->ObjDesc->Method.ParamCount;
341         }
342 
343         /*
344          * Any incoming external objects to be passed as arguments to the
345          * method must be converted to internal objects
346          */
347         if (Info->ParamCount)
348         {
349             /*
350              * Allocate a new parameter block for the internal objects
351              * Add 1 to count to allow for null terminated internal list
352              */
353             Info->Parameters = ACPI_ALLOCATE_ZEROED (
354                 ((ACPI_SIZE) Info->ParamCount + 1) * sizeof (void *));
355             if (!Info->Parameters)
356             {
357                 Status = AE_NO_MEMORY;
358                 goto Cleanup;
359             }
360 
361             /* Convert each external object in the list to an internal object */
362 
363             for (i = 0; i < Info->ParamCount; i++)
364             {
365                 Status = AcpiUtCopyEobjectToIobject (
366                     &ExternalParams->Pointer[i], &Info->Parameters[i]);
367                 if (ACPI_FAILURE (Status))
368                 {
369                     goto Cleanup;
370                 }
371             }
372 
373             Info->Parameters[Info->ParamCount] = NULL;
374         }
375         break;
376 
377     default:
378 
379         /* Warn if arguments passed to an object that is not a method */
380 
381         if (Info->ParamCount)
382         {
383             ACPI_WARNING ((AE_INFO,
384                 "%u arguments were passed to a non-method ACPI object",
385                 Info->ParamCount));
386         }
387         break;
388     }
389 
390 #endif
391 
392 
393     /* Now we can evaluate the object */
394 
395     Status = AcpiNsEvaluate (Info);
396 
397     /*
398      * If we are expecting a return value, and all went well above,
399      * copy the return value to an external object.
400      */
401     if (!ReturnBuffer)
402     {
403         goto CleanupReturnObject;
404     }
405 
406     if (!Info->ReturnObject)
407     {
408         ReturnBuffer->Length = 0;
409         goto Cleanup;
410     }
411 
412     if (ACPI_GET_DESCRIPTOR_TYPE (Info->ReturnObject) ==
413         ACPI_DESC_TYPE_NAMED)
414     {
415         /*
416          * If we received a NS Node as a return object, this means that
417          * the object we are evaluating has nothing interesting to
418          * return (such as a mutex, etc.)  We return an error because
419          * these types are essentially unsupported by this interface.
420          * We don't check up front because this makes it easier to add
421          * support for various types at a later date if necessary.
422          */
423         Status = AE_TYPE;
424         Info->ReturnObject = NULL;   /* No need to delete a NS Node */
425         ReturnBuffer->Length = 0;
426     }
427 
428     if (ACPI_FAILURE (Status))
429     {
430         goto CleanupReturnObject;
431     }
432 
433     /* Dereference Index and RefOf references */
434 
435     AcpiNsResolveReferences (Info);
436 
437     /* Get the size of the returned object */
438 
439     Status = AcpiUtGetObjectSize (Info->ReturnObject,
440         &BufferSpaceNeeded);
441     if (ACPI_SUCCESS (Status))
442     {
443         /* Validate/Allocate/Clear caller buffer */
444 
445         Status = AcpiUtInitializeBuffer (ReturnBuffer,
446             BufferSpaceNeeded);
447         if (ACPI_FAILURE (Status))
448         {
449             /*
450              * Caller's buffer is too small or a new one can't
451              * be allocated
452              */
453             ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
454                 "Needed buffer size %X, %s\n",
455                 (UINT32) BufferSpaceNeeded,
456                 AcpiFormatException (Status)));
457         }
458         else
459         {
460             /* We have enough space for the object, build it */
461 
462             Status = AcpiUtCopyIobjectToEobject (
463                 Info->ReturnObject, ReturnBuffer);
464         }
465     }
466 
467 CleanupReturnObject:
468 
469     if (Info->ReturnObject)
470     {
471         /*
472          * Delete the internal return object. NOTE: Interpreter must be
473          * locked to avoid race condition.
474          */
475         AcpiExEnterInterpreter ();
476 
477         /* Remove one reference on the return object (should delete it) */
478 
479         AcpiUtRemoveReference (Info->ReturnObject);
480         AcpiExExitInterpreter ();
481     }
482 
483 
484 Cleanup:
485 
486     /* Free the input parameter list (if we created one) */
487 
488     if (Info->Parameters)
489     {
490         /* Free the allocated parameter block */
491 
492         AcpiUtDeleteInternalObjectList (Info->Parameters);
493     }
494 
495     ACPI_FREE (Info);
496     return_ACPI_STATUS (Status);
497 }
498 
499 ACPI_EXPORT_SYMBOL (AcpiEvaluateObject)
500 
501 
502 /*******************************************************************************
503  *
504  * FUNCTION:    AcpiNsResolveReferences
505  *
506  * PARAMETERS:  Info                    - Evaluation info block
507  *
508  * RETURN:      Info->ReturnObject is replaced with the dereferenced object
509  *
510  * DESCRIPTION: Dereference certain reference objects. Called before an
511  *              internal return object is converted to an external ACPI_OBJECT.
512  *
513  * Performs an automatic dereference of Index and RefOf reference objects.
514  * These reference objects are not supported by the ACPI_OBJECT, so this is a
515  * last resort effort to return something useful. Also, provides compatibility
516  * with other ACPI implementations.
517  *
518  * NOTE: does not handle references within returned package objects or nested
519  * references, but this support could be added later if found to be necessary.
520  *
521  ******************************************************************************/
522 
523 static void
524 AcpiNsResolveReferences (
525     ACPI_EVALUATE_INFO      *Info)
526 {
527     ACPI_OPERAND_OBJECT     *ObjDesc = NULL;
528     ACPI_NAMESPACE_NODE     *Node;
529 
530 
531     /* We are interested in reference objects only */
532 
533     if ((Info->ReturnObject)->Common.Type != ACPI_TYPE_LOCAL_REFERENCE)
534     {
535         return;
536     }
537 
538     /*
539      * Two types of references are supported - those created by Index and
540      * RefOf operators. A name reference (AML_NAMEPATH_OP) can be converted
541      * to an ACPI_OBJECT, so it is not dereferenced here. A DdbHandle
542      * (AML_LOAD_OP) cannot be dereferenced, nor can it be converted to
543      * an ACPI_OBJECT.
544      */
545     switch (Info->ReturnObject->Reference.Class)
546     {
547     case ACPI_REFCLASS_INDEX:
548 
549         ObjDesc = *(Info->ReturnObject->Reference.Where);
550         break;
551 
552     case ACPI_REFCLASS_REFOF:
553 
554         Node = Info->ReturnObject->Reference.Object;
555         if (Node)
556         {
557             ObjDesc = Node->Object;
558         }
559         break;
560 
561     default:
562 
563         return;
564     }
565 
566     /* Replace the existing reference object */
567 
568     if (ObjDesc)
569     {
570         AcpiUtAddReference (ObjDesc);
571         AcpiUtRemoveReference (Info->ReturnObject);
572         Info->ReturnObject = ObjDesc;
573     }
574 
575     return;
576 }
577 
578 
579 /*******************************************************************************
580  *
581  * FUNCTION:    AcpiWalkNamespace
582  *
583  * PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
584  *              StartObject         - Handle in namespace where search begins
585  *              MaxDepth            - Depth to which search is to reach
586  *              DescendingCallback  - Called during tree descent
587  *                                    when an object of "Type" is found
588  *              AscendingCallback   - Called during tree ascent
589  *                                    when an object of "Type" is found
590  *              Context             - Passed to user function(s) above
591  *              ReturnValue         - Location where return value of
592  *                                    UserFunction is put if terminated early
593  *
594  * RETURNS      Return value from the UserFunction if terminated early.
595  *              Otherwise, returns NULL.
596  *
597  * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
598  *              starting (and ending) at the object specified by StartHandle.
599  *              The callback function is called whenever an object that matches
600  *              the type parameter is found. If the callback function returns
601  *              a non-zero value, the search is terminated immediately and this
602  *              value is returned to the caller.
603  *
604  *              The point of this procedure is to provide a generic namespace
605  *              walk routine that can be called from multiple places to
606  *              provide multiple services; the callback function(s) can be
607  *              tailored to each task, whether it is a print function,
608  *              a compare function, etc.
609  *
610  ******************************************************************************/
611 
612 ACPI_STATUS
613 AcpiWalkNamespace (
614     ACPI_OBJECT_TYPE        Type,
615     ACPI_HANDLE             StartObject,
616     UINT32                  MaxDepth,
617     ACPI_WALK_CALLBACK      DescendingCallback,
618     ACPI_WALK_CALLBACK      AscendingCallback,
619     void                    *Context,
620     void                    **ReturnValue)
621 {
622     ACPI_STATUS             Status;
623 
624 
625     ACPI_FUNCTION_TRACE (AcpiWalkNamespace);
626 
627 
628     /* Parameter validation */
629 
630     if ((Type > ACPI_TYPE_LOCAL_MAX) ||
631         (!MaxDepth)                  ||
632         (!DescendingCallback && !AscendingCallback))
633     {
634         return_ACPI_STATUS (AE_BAD_PARAMETER);
635     }
636 
637     /*
638      * Need to acquire the namespace reader lock to prevent interference
639      * with any concurrent table unloads (which causes the deletion of
640      * namespace objects). We cannot allow the deletion of a namespace node
641      * while the user function is using it. The exception to this are the
642      * nodes created and deleted during control method execution -- these
643      * nodes are marked as temporary nodes and are ignored by the namespace
644      * walk. Thus, control methods can be executed while holding the
645      * namespace deletion lock (and the user function can execute control
646      * methods.)
647      */
648     Status = AcpiUtAcquireReadLock (&AcpiGbl_NamespaceRwLock);
649     if (ACPI_FAILURE (Status))
650     {
651         return_ACPI_STATUS (Status);
652     }
653 
654     /*
655      * Lock the namespace around the walk. The namespace will be
656      * unlocked/locked around each call to the user function - since the user
657      * function must be allowed to make ACPICA calls itself (for example, it
658      * will typically execute control methods during device enumeration.)
659      */
660     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
661     if (ACPI_FAILURE (Status))
662     {
663         goto UnlockAndExit;
664     }
665 
666     /* Now we can validate the starting node */
667 
668     if (!AcpiNsValidateHandle (StartObject))
669     {
670         Status = AE_BAD_PARAMETER;
671         goto UnlockAndExit2;
672     }
673 
674     Status = AcpiNsWalkNamespace (Type, StartObject, MaxDepth,
675         ACPI_NS_WALK_UNLOCK, DescendingCallback,
676         AscendingCallback, Context, ReturnValue);
677 
678 UnlockAndExit2:
679     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
680 
681 UnlockAndExit:
682     (void) AcpiUtReleaseReadLock (&AcpiGbl_NamespaceRwLock);
683     return_ACPI_STATUS (Status);
684 }
685 
686 ACPI_EXPORT_SYMBOL (AcpiWalkNamespace)
687 
688 
689 /*******************************************************************************
690  *
691  * FUNCTION:    AcpiNsGetDeviceCallback
692  *
693  * PARAMETERS:  Callback from AcpiGetDevice
694  *
695  * RETURN:      Status
696  *
697  * DESCRIPTION: Takes callbacks from WalkNamespace and filters out all non-
698  *              present devices, or if they specified a HID, it filters based
699  *              on that.
700  *
701  ******************************************************************************/
702 
703 static ACPI_STATUS
704 AcpiNsGetDeviceCallback (
705     ACPI_HANDLE             ObjHandle,
706     UINT32                  NestingLevel,
707     void                    *Context,
708     void                    **ReturnValue)
709 {
710     ACPI_GET_DEVICES_INFO   *Info = Context;
711     ACPI_STATUS             Status;
712     ACPI_NAMESPACE_NODE     *Node;
713     UINT32                  Flags;
714     ACPI_PNP_DEVICE_ID      *Hid;
715     ACPI_PNP_DEVICE_ID_LIST *Cid;
716     UINT32                  i;
717     BOOLEAN                 Found;
718     int                     NoMatch;
719 
720 
721     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
722     if (ACPI_FAILURE (Status))
723     {
724         return (Status);
725     }
726 
727     Node = AcpiNsValidateHandle (ObjHandle);
728     Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
729     if (ACPI_FAILURE (Status))
730     {
731         return (Status);
732     }
733 
734     if (!Node)
735     {
736         return (AE_BAD_PARAMETER);
737     }
738 
739     /*
740      * First, filter based on the device HID and CID.
741      *
742      * 01/2010: For this case where a specific HID is requested, we don't
743      * want to run _STA until we have an actual HID match. Thus, we will
744      * not unnecessarily execute _STA on devices for which the caller
745      * doesn't care about. Previously, _STA was executed unconditionally
746      * on all devices found here.
747      *
748      * A side-effect of this change is that now we will continue to search
749      * for a matching HID even under device trees where the parent device
750      * would have returned a _STA that indicates it is not present or
751      * not functioning (thus aborting the search on that branch).
752      */
753     if (Info->Hid != NULL)
754     {
755         Status = AcpiUtExecute_HID (Node, &Hid);
756         if (Status == AE_NOT_FOUND)
757         {
758             return (AE_OK);
759         }
760         else if (ACPI_FAILURE (Status))
761         {
762             return (AE_CTRL_DEPTH);
763         }
764 
765         NoMatch = strcmp (Hid->String, Info->Hid);
766         ACPI_FREE (Hid);
767 
768         if (NoMatch)
769         {
770             /*
771              * HID does not match, attempt match within the
772              * list of Compatible IDs (CIDs)
773              */
774             Status = AcpiUtExecute_CID (Node, &Cid);
775             if (Status == AE_NOT_FOUND)
776             {
777                 return (AE_OK);
778             }
779             else if (ACPI_FAILURE (Status))
780             {
781                 return (AE_CTRL_DEPTH);
782             }
783 
784             /* Walk the CID list */
785 
786             Found = FALSE;
787             for (i = 0; i < Cid->Count; i++)
788             {
789                 if (strcmp (Cid->Ids[i].String, Info->Hid) == 0)
790                 {
791                     /* Found a matching CID */
792 
793                     Found = TRUE;
794                     break;
795                 }
796             }
797 
798             ACPI_FREE (Cid);
799             if (!Found)
800             {
801                 return (AE_OK);
802             }
803         }
804     }
805 
806     /* Run _STA to determine if device is present */
807 
808     Status = AcpiUtExecute_STA (Node, &Flags);
809     if (ACPI_FAILURE (Status))
810     {
811         return (AE_CTRL_DEPTH);
812     }
813 
814     if (!(Flags & ACPI_STA_DEVICE_PRESENT) &&
815         !(Flags & ACPI_STA_DEVICE_FUNCTIONING))
816     {
817         /*
818          * Don't examine the children of the device only when the
819          * device is neither present nor functional. See ACPI spec,
820          * description of _STA for more information.
821          */
822         return (AE_CTRL_DEPTH);
823     }
824 
825     /* We have a valid device, invoke the user function */
826 
827     Status = Info->UserFunction (ObjHandle, NestingLevel,
828         Info->Context, ReturnValue);
829     return (Status);
830 }
831 
832 
833 /*******************************************************************************
834  *
835  * FUNCTION:    AcpiGetDevices
836  *
837  * PARAMETERS:  HID                 - HID to search for. Can be NULL.
838  *              UserFunction        - Called when a matching object is found
839  *              Context             - Passed to user function
840  *              ReturnValue         - Location where return value of
841  *                                    UserFunction is put if terminated early
842  *
843  * RETURNS      Return value from the UserFunction if terminated early.
844  *              Otherwise, returns NULL.
845  *
846  * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
847  *              starting (and ending) at the object specified by StartHandle.
848  *              The UserFunction is called whenever an object of type
849  *              Device is found. If the user function returns
850  *              a non-zero value, the search is terminated immediately and this
851  *              value is returned to the caller.
852  *
853  *              This is a wrapper for WalkNamespace, but the callback performs
854  *              additional filtering. Please see AcpiNsGetDeviceCallback.
855  *
856  ******************************************************************************/
857 
858 ACPI_STATUS
859 AcpiGetDevices (
860     char                    *HID,
861     ACPI_WALK_CALLBACK      UserFunction,
862     void                    *Context,
863     void                    **ReturnValue)
864 {
865     ACPI_STATUS             Status;
866     ACPI_GET_DEVICES_INFO   Info;
867 
868 
869     ACPI_FUNCTION_TRACE (AcpiGetDevices);
870 
871 
872     /* Parameter validation */
873 
874     if (!UserFunction)
875     {
876         return_ACPI_STATUS (AE_BAD_PARAMETER);
877     }
878 
879     /*
880      * We're going to call their callback from OUR callback, so we need
881      * to know what it is, and their context parameter.
882      */
883     Info.Hid = HID;
884     Info.Context = Context;
885     Info.UserFunction = UserFunction;
886 
887     /*
888      * Lock the namespace around the walk.
889      * The namespace will be unlocked/locked around each call
890      * to the user function - since this function
891      * must be allowed to make Acpi calls itself.
892      */
893     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
894     if (ACPI_FAILURE (Status))
895     {
896         return_ACPI_STATUS (Status);
897     }
898 
899     Status = AcpiNsWalkNamespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
900         ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK,
901         AcpiNsGetDeviceCallback, NULL, &Info, ReturnValue);
902 
903     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
904     return_ACPI_STATUS (Status);
905 }
906 
907 ACPI_EXPORT_SYMBOL (AcpiGetDevices)
908 
909 
910 /*******************************************************************************
911  *
912  * FUNCTION:    AcpiAttachData
913  *
914  * PARAMETERS:  ObjHandle           - Namespace node
915  *              Handler             - Handler for this attachment
916  *              Data                - Pointer to data to be attached
917  *
918  * RETURN:      Status
919  *
920  * DESCRIPTION: Attach arbitrary data and handler to a namespace node.
921  *
922  ******************************************************************************/
923 
924 ACPI_STATUS
925 AcpiAttachData (
926     ACPI_HANDLE             ObjHandle,
927     ACPI_OBJECT_HANDLER     Handler,
928     void                    *Data)
929 {
930     ACPI_NAMESPACE_NODE     *Node;
931     ACPI_STATUS             Status;
932 
933 
934     /* Parameter validation */
935 
936     if (!ObjHandle  ||
937         !Handler    ||
938         !Data)
939     {
940         return (AE_BAD_PARAMETER);
941     }
942 
943     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
944     if (ACPI_FAILURE (Status))
945     {
946         return (Status);
947     }
948 
949     /* Convert and validate the handle */
950 
951     Node = AcpiNsValidateHandle (ObjHandle);
952     if (!Node)
953     {
954         Status = AE_BAD_PARAMETER;
955         goto UnlockAndExit;
956     }
957 
958     Status = AcpiNsAttachData (Node, Handler, Data);
959 
960 UnlockAndExit:
961     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
962     return (Status);
963 }
964 
965 ACPI_EXPORT_SYMBOL (AcpiAttachData)
966 
967 
968 /*******************************************************************************
969  *
970  * FUNCTION:    AcpiDetachData
971  *
972  * PARAMETERS:  ObjHandle           - Namespace node handle
973  *              Handler             - Handler used in call to AcpiAttachData
974  *
975  * RETURN:      Status
976  *
977  * DESCRIPTION: Remove data that was previously attached to a node.
978  *
979  ******************************************************************************/
980 
981 ACPI_STATUS
982 AcpiDetachData (
983     ACPI_HANDLE             ObjHandle,
984     ACPI_OBJECT_HANDLER     Handler)
985 {
986     ACPI_NAMESPACE_NODE     *Node;
987     ACPI_STATUS             Status;
988 
989 
990     /* Parameter validation */
991 
992     if (!ObjHandle  ||
993         !Handler)
994     {
995         return (AE_BAD_PARAMETER);
996     }
997 
998     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
999     if (ACPI_FAILURE (Status))
1000     {
1001         return (Status);
1002     }
1003 
1004     /* Convert and validate the handle */
1005 
1006     Node = AcpiNsValidateHandle (ObjHandle);
1007     if (!Node)
1008     {
1009         Status = AE_BAD_PARAMETER;
1010         goto UnlockAndExit;
1011     }
1012 
1013     Status = AcpiNsDetachData (Node, Handler);
1014 
1015 UnlockAndExit:
1016     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
1017     return (Status);
1018 }
1019 
1020 ACPI_EXPORT_SYMBOL (AcpiDetachData)
1021 
1022 
1023 /*******************************************************************************
1024  *
1025  * FUNCTION:    AcpiGetData
1026  *
1027  * PARAMETERS:  ObjHandle           - Namespace node
1028  *              Handler             - Handler used in call to AttachData
1029  *              Data                - Where the data is returned
1030  *
1031  * RETURN:      Status
1032  *
1033  * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
1034  *
1035  ******************************************************************************/
1036 
1037 ACPI_STATUS
1038 AcpiGetData (
1039     ACPI_HANDLE             ObjHandle,
1040     ACPI_OBJECT_HANDLER     Handler,
1041     void                    **Data)
1042 {
1043     ACPI_NAMESPACE_NODE     *Node;
1044     ACPI_STATUS             Status;
1045 
1046 
1047     /* Parameter validation */
1048 
1049     if (!ObjHandle  ||
1050         !Handler    ||
1051         !Data)
1052     {
1053         return (AE_BAD_PARAMETER);
1054     }
1055 
1056     Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
1057     if (ACPI_FAILURE (Status))
1058     {
1059         return (Status);
1060     }
1061 
1062     /* Convert and validate the handle */
1063 
1064     Node = AcpiNsValidateHandle (ObjHandle);
1065     if (!Node)
1066     {
1067         Status = AE_BAD_PARAMETER;
1068         goto UnlockAndExit;
1069     }
1070 
1071     Status = AcpiNsGetAttachedData (Node, Handler, Data);
1072 
1073 UnlockAndExit:
1074     (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
1075     return (Status);
1076 }
1077 
1078 ACPI_EXPORT_SYMBOL (AcpiGetData)
1079