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