diff options
Diffstat (limited to 'drivers/acpi/acpica/exresolv.c')
-rw-r--r-- | drivers/acpi/acpica/exresolv.c | 551 |
1 files changed, 551 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c new file mode 100644 index 000000000000..42adde01bc93 --- /dev/null +++ b/drivers/acpi/acpica/exresolv.c | |||
@@ -0,0 +1,551 @@ | |||
1 | |||
2 | /****************************************************************************** | ||
3 | * | ||
4 | * Module Name: exresolv - AML Interpreter object resolution | ||
5 | * | ||
6 | *****************************************************************************/ | ||
7 | |||
8 | /* | ||
9 | * Copyright (C) 2000 - 2008, 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 | #include <acpi/acpi.h> | ||
46 | #include <acpi/accommon.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | #include <acpi/acnamesp.h> | ||
51 | |||
52 | #define _COMPONENT ACPI_EXECUTER | ||
53 | ACPI_MODULE_NAME("exresolv") | ||
54 | |||
55 | /* Local prototypes */ | ||
56 | static acpi_status | ||
57 | acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, | ||
58 | struct acpi_walk_state *walk_state); | ||
59 | |||
60 | /******************************************************************************* | ||
61 | * | ||
62 | * FUNCTION: acpi_ex_resolve_to_value | ||
63 | * | ||
64 | * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can | ||
65 | * be either an (union acpi_operand_object *) | ||
66 | * or an acpi_handle. | ||
67 | * walk_state - Current method state | ||
68 | * | ||
69 | * RETURN: Status | ||
70 | * | ||
71 | * DESCRIPTION: Convert Reference objects to values | ||
72 | * | ||
73 | ******************************************************************************/ | ||
74 | |||
75 | acpi_status | ||
76 | acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, | ||
77 | struct acpi_walk_state *walk_state) | ||
78 | { | ||
79 | acpi_status status; | ||
80 | |||
81 | ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr); | ||
82 | |||
83 | if (!stack_ptr || !*stack_ptr) { | ||
84 | ACPI_ERROR((AE_INFO, "Internal - null pointer")); | ||
85 | return_ACPI_STATUS(AE_AML_NO_OPERAND); | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * The entity pointed to by the stack_ptr can be either | ||
90 | * 1) A valid union acpi_operand_object, or | ||
91 | * 2) A struct acpi_namespace_node (named_obj) | ||
92 | */ | ||
93 | if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_OPERAND) { | ||
94 | status = acpi_ex_resolve_object_to_value(stack_ptr, walk_state); | ||
95 | if (ACPI_FAILURE(status)) { | ||
96 | return_ACPI_STATUS(status); | ||
97 | } | ||
98 | |||
99 | if (!*stack_ptr) { | ||
100 | ACPI_ERROR((AE_INFO, "Internal - null pointer")); | ||
101 | return_ACPI_STATUS(AE_AML_NO_OPERAND); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Object on the stack may have changed if acpi_ex_resolve_object_to_value() | ||
107 | * was called (i.e., we can't use an _else_ here.) | ||
108 | */ | ||
109 | if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_NAMED) { | ||
110 | status = | ||
111 | acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR | ||
112 | (struct acpi_namespace_node, | ||
113 | stack_ptr), walk_state); | ||
114 | if (ACPI_FAILURE(status)) { | ||
115 | return_ACPI_STATUS(status); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr)); | ||
120 | return_ACPI_STATUS(AE_OK); | ||
121 | } | ||
122 | |||
123 | /******************************************************************************* | ||
124 | * | ||
125 | * FUNCTION: acpi_ex_resolve_object_to_value | ||
126 | * | ||
127 | * PARAMETERS: stack_ptr - Pointer to an internal object | ||
128 | * walk_state - Current method state | ||
129 | * | ||
130 | * RETURN: Status | ||
131 | * | ||
132 | * DESCRIPTION: Retrieve the value from an internal object. The Reference type | ||
133 | * uses the associated AML opcode to determine the value. | ||
134 | * | ||
135 | ******************************************************************************/ | ||
136 | |||
137 | static acpi_status | ||
138 | acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, | ||
139 | struct acpi_walk_state *walk_state) | ||
140 | { | ||
141 | acpi_status status = AE_OK; | ||
142 | union acpi_operand_object *stack_desc; | ||
143 | union acpi_operand_object *obj_desc = NULL; | ||
144 | u8 ref_type; | ||
145 | |||
146 | ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); | ||
147 | |||
148 | stack_desc = *stack_ptr; | ||
149 | |||
150 | /* This is an union acpi_operand_object */ | ||
151 | |||
152 | switch (ACPI_GET_OBJECT_TYPE(stack_desc)) { | ||
153 | case ACPI_TYPE_LOCAL_REFERENCE: | ||
154 | |||
155 | ref_type = stack_desc->reference.class; | ||
156 | |||
157 | switch (ref_type) { | ||
158 | case ACPI_REFCLASS_LOCAL: | ||
159 | case ACPI_REFCLASS_ARG: | ||
160 | |||
161 | /* | ||
162 | * Get the local from the method's state info | ||
163 | * Note: this increments the local's object reference count | ||
164 | */ | ||
165 | status = acpi_ds_method_data_get_value(ref_type, | ||
166 | stack_desc-> | ||
167 | reference.value, | ||
168 | walk_state, | ||
169 | &obj_desc); | ||
170 | if (ACPI_FAILURE(status)) { | ||
171 | return_ACPI_STATUS(status); | ||
172 | } | ||
173 | |||
174 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | ||
175 | "[Arg/Local %X] ValueObj is %p\n", | ||
176 | stack_desc->reference.value, | ||
177 | obj_desc)); | ||
178 | |||
179 | /* | ||
180 | * Now we can delete the original Reference Object and | ||
181 | * replace it with the resolved value | ||
182 | */ | ||
183 | acpi_ut_remove_reference(stack_desc); | ||
184 | *stack_ptr = obj_desc; | ||
185 | break; | ||
186 | |||
187 | case ACPI_REFCLASS_INDEX: | ||
188 | |||
189 | switch (stack_desc->reference.target_type) { | ||
190 | case ACPI_TYPE_BUFFER_FIELD: | ||
191 | |||
192 | /* Just return - do not dereference */ | ||
193 | break; | ||
194 | |||
195 | case ACPI_TYPE_PACKAGE: | ||
196 | |||
197 | /* If method call or copy_object - do not dereference */ | ||
198 | |||
199 | if ((walk_state->opcode == | ||
200 | AML_INT_METHODCALL_OP) | ||
201 | || (walk_state->opcode == AML_COPY_OP)) { | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | /* Otherwise, dereference the package_index to a package element */ | ||
206 | |||
207 | obj_desc = *stack_desc->reference.where; | ||
208 | if (obj_desc) { | ||
209 | /* | ||
210 | * Valid object descriptor, copy pointer to return value | ||
211 | * (i.e., dereference the package index) | ||
212 | * Delete the ref object, increment the returned object | ||
213 | */ | ||
214 | acpi_ut_remove_reference(stack_desc); | ||
215 | acpi_ut_add_reference(obj_desc); | ||
216 | *stack_ptr = obj_desc; | ||
217 | } else { | ||
218 | /* | ||
219 | * A NULL object descriptor means an uninitialized element of | ||
220 | * the package, can't dereference it | ||
221 | */ | ||
222 | ACPI_ERROR((AE_INFO, | ||
223 | "Attempt to dereference an Index to NULL package element Idx=%p", | ||
224 | stack_desc)); | ||
225 | status = AE_AML_UNINITIALIZED_ELEMENT; | ||
226 | } | ||
227 | break; | ||
228 | |||
229 | default: | ||
230 | |||
231 | /* Invalid reference object */ | ||
232 | |||
233 | ACPI_ERROR((AE_INFO, | ||
234 | "Unknown TargetType %X in Index/Reference object %p", | ||
235 | stack_desc->reference.target_type, | ||
236 | stack_desc)); | ||
237 | status = AE_AML_INTERNAL; | ||
238 | break; | ||
239 | } | ||
240 | break; | ||
241 | |||
242 | case ACPI_REFCLASS_REFOF: | ||
243 | case ACPI_REFCLASS_DEBUG: | ||
244 | case ACPI_REFCLASS_TABLE: | ||
245 | |||
246 | /* Just leave the object as-is, do not dereference */ | ||
247 | |||
248 | break; | ||
249 | |||
250 | case ACPI_REFCLASS_NAME: /* Reference to a named object */ | ||
251 | |||
252 | /* Dereference the name */ | ||
253 | |||
254 | if ((stack_desc->reference.node->type == | ||
255 | ACPI_TYPE_DEVICE) | ||
256 | || (stack_desc->reference.node->type == | ||
257 | ACPI_TYPE_THERMAL)) { | ||
258 | |||
259 | /* These node types do not have 'real' subobjects */ | ||
260 | |||
261 | *stack_ptr = (void *)stack_desc->reference.node; | ||
262 | } else { | ||
263 | /* Get the object pointed to by the namespace node */ | ||
264 | |||
265 | *stack_ptr = | ||
266 | (stack_desc->reference.node)->object; | ||
267 | acpi_ut_add_reference(*stack_ptr); | ||
268 | } | ||
269 | |||
270 | acpi_ut_remove_reference(stack_desc); | ||
271 | break; | ||
272 | |||
273 | default: | ||
274 | |||
275 | ACPI_ERROR((AE_INFO, | ||
276 | "Unknown Reference type %X in %p", ref_type, | ||
277 | stack_desc)); | ||
278 | status = AE_AML_INTERNAL; | ||
279 | break; | ||
280 | } | ||
281 | break; | ||
282 | |||
283 | case ACPI_TYPE_BUFFER: | ||
284 | |||
285 | status = acpi_ds_get_buffer_arguments(stack_desc); | ||
286 | break; | ||
287 | |||
288 | case ACPI_TYPE_PACKAGE: | ||
289 | |||
290 | status = acpi_ds_get_package_arguments(stack_desc); | ||
291 | break; | ||
292 | |||
293 | case ACPI_TYPE_BUFFER_FIELD: | ||
294 | case ACPI_TYPE_LOCAL_REGION_FIELD: | ||
295 | case ACPI_TYPE_LOCAL_BANK_FIELD: | ||
296 | case ACPI_TYPE_LOCAL_INDEX_FIELD: | ||
297 | |||
298 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | ||
299 | "FieldRead SourceDesc=%p Type=%X\n", | ||
300 | stack_desc, | ||
301 | ACPI_GET_OBJECT_TYPE(stack_desc))); | ||
302 | |||
303 | status = | ||
304 | acpi_ex_read_data_from_field(walk_state, stack_desc, | ||
305 | &obj_desc); | ||
306 | |||
307 | /* Remove a reference to the original operand, then override */ | ||
308 | |||
309 | acpi_ut_remove_reference(*stack_ptr); | ||
310 | *stack_ptr = (void *)obj_desc; | ||
311 | break; | ||
312 | |||
313 | default: | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | return_ACPI_STATUS(status); | ||
318 | } | ||
319 | |||
320 | /******************************************************************************* | ||
321 | * | ||
322 | * FUNCTION: acpi_ex_resolve_multiple | ||
323 | * | ||
324 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
325 | * Operand - Starting point for resolution | ||
326 | * return_type - Where the object type is returned | ||
327 | * return_desc - Where the resolved object is returned | ||
328 | * | ||
329 | * RETURN: Status | ||
330 | * | ||
331 | * DESCRIPTION: Return the base object and type. Traverse a reference list if | ||
332 | * necessary to get to the base object. | ||
333 | * | ||
334 | ******************************************************************************/ | ||
335 | |||
336 | acpi_status | ||
337 | acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, | ||
338 | union acpi_operand_object *operand, | ||
339 | acpi_object_type * return_type, | ||
340 | union acpi_operand_object **return_desc) | ||
341 | { | ||
342 | union acpi_operand_object *obj_desc = (void *)operand; | ||
343 | struct acpi_namespace_node *node; | ||
344 | acpi_object_type type; | ||
345 | acpi_status status; | ||
346 | |||
347 | ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple); | ||
348 | |||
349 | /* Operand can be either a namespace node or an operand descriptor */ | ||
350 | |||
351 | switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { | ||
352 | case ACPI_DESC_TYPE_OPERAND: | ||
353 | type = obj_desc->common.type; | ||
354 | break; | ||
355 | |||
356 | case ACPI_DESC_TYPE_NAMED: | ||
357 | type = ((struct acpi_namespace_node *)obj_desc)->type; | ||
358 | obj_desc = | ||
359 | acpi_ns_get_attached_object((struct acpi_namespace_node *) | ||
360 | obj_desc); | ||
361 | |||
362 | /* If we had an Alias node, use the attached object for type info */ | ||
363 | |||
364 | if (type == ACPI_TYPE_LOCAL_ALIAS) { | ||
365 | type = ((struct acpi_namespace_node *)obj_desc)->type; | ||
366 | obj_desc = | ||
367 | acpi_ns_get_attached_object((struct | ||
368 | acpi_namespace_node *) | ||
369 | obj_desc); | ||
370 | } | ||
371 | break; | ||
372 | |||
373 | default: | ||
374 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | ||
375 | } | ||
376 | |||
377 | /* If type is anything other than a reference, we are done */ | ||
378 | |||
379 | if (type != ACPI_TYPE_LOCAL_REFERENCE) { | ||
380 | goto exit; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * For reference objects created via the ref_of, Index, or Load/load_table | ||
385 | * operators, we need to get to the base object (as per the ACPI | ||
386 | * specification of the object_type and size_of operators). This means | ||
387 | * traversing the list of possibly many nested references. | ||
388 | */ | ||
389 | while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) { | ||
390 | switch (obj_desc->reference.class) { | ||
391 | case ACPI_REFCLASS_REFOF: | ||
392 | case ACPI_REFCLASS_NAME: | ||
393 | |||
394 | /* Dereference the reference pointer */ | ||
395 | |||
396 | if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) { | ||
397 | node = obj_desc->reference.object; | ||
398 | } else { /* AML_INT_NAMEPATH_OP */ | ||
399 | |||
400 | node = obj_desc->reference.node; | ||
401 | } | ||
402 | |||
403 | /* All "References" point to a NS node */ | ||
404 | |||
405 | if (ACPI_GET_DESCRIPTOR_TYPE(node) != | ||
406 | ACPI_DESC_TYPE_NAMED) { | ||
407 | ACPI_ERROR((AE_INFO, "Not a NS node %p [%s]", | ||
408 | node, | ||
409 | acpi_ut_get_descriptor_name(node))); | ||
410 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
411 | } | ||
412 | |||
413 | /* Get the attached object */ | ||
414 | |||
415 | obj_desc = acpi_ns_get_attached_object(node); | ||
416 | if (!obj_desc) { | ||
417 | |||
418 | /* No object, use the NS node type */ | ||
419 | |||
420 | type = acpi_ns_get_type(node); | ||
421 | goto exit; | ||
422 | } | ||
423 | |||
424 | /* Check for circular references */ | ||
425 | |||
426 | if (obj_desc == operand) { | ||
427 | return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE); | ||
428 | } | ||
429 | break; | ||
430 | |||
431 | case ACPI_REFCLASS_INDEX: | ||
432 | |||
433 | /* Get the type of this reference (index into another object) */ | ||
434 | |||
435 | type = obj_desc->reference.target_type; | ||
436 | if (type != ACPI_TYPE_PACKAGE) { | ||
437 | goto exit; | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * The main object is a package, we want to get the type | ||
442 | * of the individual package element that is referenced by | ||
443 | * the index. | ||
444 | * | ||
445 | * This could of course in turn be another reference object. | ||
446 | */ | ||
447 | obj_desc = *(obj_desc->reference.where); | ||
448 | if (!obj_desc) { | ||
449 | |||
450 | /* NULL package elements are allowed */ | ||
451 | |||
452 | type = 0; /* Uninitialized */ | ||
453 | goto exit; | ||
454 | } | ||
455 | break; | ||
456 | |||
457 | case ACPI_REFCLASS_TABLE: | ||
458 | |||
459 | type = ACPI_TYPE_DDB_HANDLE; | ||
460 | goto exit; | ||
461 | |||
462 | case ACPI_REFCLASS_LOCAL: | ||
463 | case ACPI_REFCLASS_ARG: | ||
464 | |||
465 | if (return_desc) { | ||
466 | status = | ||
467 | acpi_ds_method_data_get_value(obj_desc-> | ||
468 | reference. | ||
469 | class, | ||
470 | obj_desc-> | ||
471 | reference. | ||
472 | value, | ||
473 | walk_state, | ||
474 | &obj_desc); | ||
475 | if (ACPI_FAILURE(status)) { | ||
476 | return_ACPI_STATUS(status); | ||
477 | } | ||
478 | acpi_ut_remove_reference(obj_desc); | ||
479 | } else { | ||
480 | status = | ||
481 | acpi_ds_method_data_get_node(obj_desc-> | ||
482 | reference. | ||
483 | class, | ||
484 | obj_desc-> | ||
485 | reference. | ||
486 | value, | ||
487 | walk_state, | ||
488 | &node); | ||
489 | if (ACPI_FAILURE(status)) { | ||
490 | return_ACPI_STATUS(status); | ||
491 | } | ||
492 | |||
493 | obj_desc = acpi_ns_get_attached_object(node); | ||
494 | if (!obj_desc) { | ||
495 | type = ACPI_TYPE_ANY; | ||
496 | goto exit; | ||
497 | } | ||
498 | } | ||
499 | break; | ||
500 | |||
501 | case ACPI_REFCLASS_DEBUG: | ||
502 | |||
503 | /* The Debug Object is of type "DebugObject" */ | ||
504 | |||
505 | type = ACPI_TYPE_DEBUG_OBJECT; | ||
506 | goto exit; | ||
507 | |||
508 | default: | ||
509 | |||
510 | ACPI_ERROR((AE_INFO, | ||
511 | "Unknown Reference Class %2.2X", | ||
512 | obj_desc->reference.class)); | ||
513 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Now we are guaranteed to have an object that has not been created | ||
519 | * via the ref_of or Index operators. | ||
520 | */ | ||
521 | type = ACPI_GET_OBJECT_TYPE(obj_desc); | ||
522 | |||
523 | exit: | ||
524 | /* Convert internal types to external types */ | ||
525 | |||
526 | switch (type) { | ||
527 | case ACPI_TYPE_LOCAL_REGION_FIELD: | ||
528 | case ACPI_TYPE_LOCAL_BANK_FIELD: | ||
529 | case ACPI_TYPE_LOCAL_INDEX_FIELD: | ||
530 | |||
531 | type = ACPI_TYPE_FIELD_UNIT; | ||
532 | break; | ||
533 | |||
534 | case ACPI_TYPE_LOCAL_SCOPE: | ||
535 | |||
536 | /* Per ACPI Specification, Scope is untyped */ | ||
537 | |||
538 | type = ACPI_TYPE_ANY; | ||
539 | break; | ||
540 | |||
541 | default: | ||
542 | /* No change to Type required */ | ||
543 | break; | ||
544 | } | ||
545 | |||
546 | *return_type = type; | ||
547 | if (return_desc) { | ||
548 | *return_desc = obj_desc; | ||
549 | } | ||
550 | return_ACPI_STATUS(AE_OK); | ||
551 | } | ||