ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / acpi / executer / exresolv.c
1
2 /******************************************************************************
3  *
4  * Module Name: exresolv - AML Interpreter object resolution
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2004, R. Byron Moore
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
46 #include <acpi/acpi.h>
47 #include <acpi/amlcode.h>
48 #include <acpi/acdispat.h>
49 #include <acpi/acinterp.h>
50 #include <acpi/acnamesp.h>
51 #include <acpi/acparser.h>
52
53
54 #define _COMPONENT          ACPI_EXECUTER
55          ACPI_MODULE_NAME    ("exresolv")
56
57
58 /*******************************************************************************
59  *
60  * FUNCTION:    acpi_ex_resolve_to_value
61  *
62  * PARAMETERS:  **stack_ptr         - Points to entry on obj_stack, which can
63  *                                    be either an (union acpi_operand_object *)
64  *                                    or an acpi_handle.
65  *              walk_state          - Current method state
66  *
67  * RETURN:      Status
68  *
69  * DESCRIPTION: Convert Reference objects to values
70  *
71  ******************************************************************************/
72
73 acpi_status
74 acpi_ex_resolve_to_value (
75         union acpi_operand_object       **stack_ptr,
76         struct acpi_walk_state          *walk_state)
77 {
78         acpi_status                     status;
79
80
81         ACPI_FUNCTION_TRACE_PTR ("ex_resolve_to_value", stack_ptr);
82
83
84         if (!stack_ptr || !*stack_ptr) {
85                 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n"));
86                 return_ACPI_STATUS (AE_AML_NO_OPERAND);
87         }
88
89         /*
90          * The entity pointed to by the stack_ptr can be either
91          * 1) A valid union acpi_operand_object, or
92          * 2) A struct acpi_namespace_node (named_obj)
93          */
94         if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_OPERAND) {
95                 status = acpi_ex_resolve_object_to_value (stack_ptr, walk_state);
96                 if (ACPI_FAILURE (status)) {
97                         return_ACPI_STATUS (status);
98                 }
99         }
100
101         /*
102          * Object on the stack may have changed if acpi_ex_resolve_object_to_value()
103          * was called (i.e., we can't use an _else_ here.)
104          */
105         if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_NAMED) {
106                 status = acpi_ex_resolve_node_to_value (
107                                   ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, stack_ptr),
108                                   walk_state);
109                 if (ACPI_FAILURE (status)) {
110                         return_ACPI_STATUS (status);
111                 }
112         }
113
114         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr));
115         return_ACPI_STATUS (AE_OK);
116 }
117
118
119 /*******************************************************************************
120  *
121  * FUNCTION:    acpi_ex_resolve_object_to_value
122  *
123  * PARAMETERS:  stack_ptr       - Pointer to a stack location that contains a
124  *                                ptr to an internal object.
125  *              walk_state      - Current method state
126  *
127  * RETURN:      Status
128  *
129  * DESCRIPTION: Retrieve the value from an internal object.  The Reference type
130  *              uses the associated AML opcode to determine the value.
131  *
132  ******************************************************************************/
133
134 acpi_status
135 acpi_ex_resolve_object_to_value (
136         union acpi_operand_object       **stack_ptr,
137         struct acpi_walk_state          *walk_state)
138 {
139         acpi_status                     status = AE_OK;
140         union acpi_operand_object       *stack_desc;
141         void                            *temp_node;
142         union acpi_operand_object       *obj_desc;
143         u16                             opcode;
144
145
146         ACPI_FUNCTION_TRACE ("ex_resolve_object_to_value");
147
148
149         stack_desc = *stack_ptr;
150
151         /* This is an union acpi_operand_object    */
152
153         switch (ACPI_GET_OBJECT_TYPE (stack_desc)) {
154         case ACPI_TYPE_LOCAL_REFERENCE:
155
156                 opcode = stack_desc->reference.opcode;
157
158                 switch (opcode) {
159                 case AML_NAME_OP:
160
161                         /*
162                          * Convert indirect name ptr to a direct name ptr.
163                          * Then, acpi_ex_resolve_node_to_value can be used to get the value
164                          */
165                         temp_node = stack_desc->reference.object;
166
167                         /* Delete the Reference Object */
168
169                         acpi_ut_remove_reference (stack_desc);
170
171                         /* Put direct name pointer onto stack and exit */
172
173                         (*stack_ptr) = temp_node;
174                         break;
175
176
177                 case AML_LOCAL_OP:
178                 case AML_ARG_OP:
179
180                         /*
181                          * Get the local from the method's state info
182                          * Note: this increments the local's object reference count
183                          */
184                         status = acpi_ds_method_data_get_value (opcode,
185                                           stack_desc->reference.offset, walk_state, &obj_desc);
186                         if (ACPI_FAILURE (status)) {
187                                 return_ACPI_STATUS (status);
188                         }
189
190                         /*
191                          * Now we can delete the original Reference Object and
192                          * replace it with the resolve value
193                          */
194                         acpi_ut_remove_reference (stack_desc);
195                         *stack_ptr = obj_desc;
196
197                         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %d] value_obj is %p\n",
198                                 stack_desc->reference.offset, obj_desc));
199                         break;
200
201
202                 case AML_INDEX_OP:
203
204                         switch (stack_desc->reference.target_type) {
205                         case ACPI_TYPE_BUFFER_FIELD:
206
207                                 /* Just return - leave the Reference on the stack */
208                                 break;
209
210
211                         case ACPI_TYPE_PACKAGE:
212
213                                 obj_desc = *stack_desc->reference.where;
214                                 if (obj_desc) {
215                                         /*
216                                          * Valid obj descriptor, copy pointer to return value
217                                          * (i.e., dereference the package index)
218                                          * Delete the ref object, increment the returned object
219                                          */
220                                         acpi_ut_remove_reference (stack_desc);
221                                         acpi_ut_add_reference (obj_desc);
222                                         *stack_ptr = obj_desc;
223                                 }
224                                 else {
225                                         /*
226                                          * A NULL object descriptor means an unitialized element of
227                                          * the package, can't dereference it
228                                          */
229                                         ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
230                                                 "Attempt to deref an Index to NULL pkg element Idx=%p\n",
231                                                 stack_desc));
232                                         status = AE_AML_UNINITIALIZED_ELEMENT;
233                                 }
234                                 break;
235
236
237                         default:
238
239                                 /* Invalid reference object */
240
241                                 ACPI_REPORT_ERROR ((
242                                         "During resolve, Unknown target_type %X in Index/Reference obj %p\n",
243                                         stack_desc->reference.target_type, stack_desc));
244                                 status = AE_AML_INTERNAL;
245                                 break;
246                         }
247                         break;
248
249
250                 case AML_REF_OF_OP:
251                 case AML_DEBUG_OP:
252                 case AML_LOAD_OP:
253
254                         /* Just leave the object as-is */
255
256                         break;
257
258
259                 default:
260
261                         ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n",
262                                 opcode, acpi_ps_get_opcode_name (opcode), stack_desc));
263                         status = AE_AML_INTERNAL;
264                         break;
265                 }
266                 break;
267
268
269         case ACPI_TYPE_BUFFER:
270
271                 status = acpi_ds_get_buffer_arguments (stack_desc);
272                 break;
273
274
275         case ACPI_TYPE_PACKAGE:
276
277                 status = acpi_ds_get_package_arguments (stack_desc);
278                 break;
279
280
281         /*
282          * These cases may never happen here, but just in case..
283          */
284         case ACPI_TYPE_BUFFER_FIELD:
285         case ACPI_TYPE_LOCAL_REGION_FIELD:
286         case ACPI_TYPE_LOCAL_BANK_FIELD:
287         case ACPI_TYPE_LOCAL_INDEX_FIELD:
288
289                 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read source_desc=%p Type=%X\n",
290                         stack_desc, ACPI_GET_OBJECT_TYPE (stack_desc)));
291
292                 status = acpi_ex_read_data_from_field (walk_state, stack_desc, &obj_desc);
293                 *stack_ptr = (void *) obj_desc;
294                 break;
295
296         default:
297                 break;
298         }
299
300         return_ACPI_STATUS (status);
301 }
302
303
304 /*******************************************************************************
305  *
306  * FUNCTION:    acpi_ex_resolve_multiple
307  *
308  * PARAMETERS:  walk_state          - Current state (contains AML opcode)
309  *              Operand             - Starting point for resolution
310  *              return_type         - Where the object type is returned
311  *              return_desc         - Where the resolved object is returned
312  *
313  * RETURN:      Status
314  *
315  * DESCRIPTION: Return the base object and type.  Traverse a reference list if
316  *              necessary to get to the base object.
317  *
318  ******************************************************************************/
319
320 acpi_status
321 acpi_ex_resolve_multiple (
322         struct acpi_walk_state          *walk_state,
323         union acpi_operand_object       *operand,
324         acpi_object_type                *return_type,
325         union acpi_operand_object       **return_desc)
326 {
327         union acpi_operand_object       *obj_desc = (void *) operand;
328         struct acpi_namespace_node      *node;
329         acpi_object_type                type;
330
331
332         ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple");
333
334
335         /*
336          * For reference objects created via the ref_of or Index operators,
337          * we need to get to the base object (as per the ACPI specification
338          * of the object_type and size_of operators). This means traversing
339          * the list of possibly many nested references.
340          */
341         while (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
342                 switch (obj_desc->reference.opcode) {
343                 case AML_REF_OF_OP:
344
345                         /* Dereference the reference pointer */
346
347                         node = obj_desc->reference.object;
348
349                         /* All "References" point to a NS node */
350
351                         if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
352                                 ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
353                                                 node, acpi_ut_get_descriptor_name (node)));
354                                 return_ACPI_STATUS (AE_AML_INTERNAL);
355                         }
356
357                         /* Get the attached object */
358
359                         obj_desc = acpi_ns_get_attached_object (node);
360                         if (!obj_desc) {
361                                 /* No object, use the NS node type */
362
363                                 type = acpi_ns_get_type (node);
364                                 goto exit;
365                         }
366
367                         /* Check for circular references */
368
369                         if (obj_desc == operand) {
370                                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
371                         }
372                         break;
373
374
375                 case AML_INDEX_OP:
376
377                         /* Get the type of this reference (index into another object) */
378
379                         type = obj_desc->reference.target_type;
380                         if (type != ACPI_TYPE_PACKAGE) {
381                                 goto exit;
382                         }
383
384                         /*
385                          * The main object is a package, we want to get the type
386                          * of the individual package element that is referenced by
387                          * the index.
388                          *
389                          * This could of course in turn be another reference object.
390                          */
391                         obj_desc = *(obj_desc->reference.where);
392                         break;
393
394
395                 case AML_INT_NAMEPATH_OP:
396
397                         /* Dereference the reference pointer */
398
399                         node = obj_desc->reference.node;
400
401                         /* All "References" point to a NS node */
402
403                         if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
404                                 ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
405                                                 node, acpi_ut_get_descriptor_name (node)));
406                            return_ACPI_STATUS (AE_AML_INTERNAL);
407                         }
408
409                         /* Get the attached object */
410
411                         obj_desc = acpi_ns_get_attached_object (node);
412                         if (!obj_desc) {
413                                 /* No object, use the NS node type */
414
415                                 type = acpi_ns_get_type (node);
416                                 goto exit;
417                         }
418
419                         /* Check for circular references */
420
421                         if (obj_desc == operand) {
422                                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
423                         }
424                         break;
425
426
427                 case AML_DEBUG_OP:
428
429                         /* The Debug Object is of type "debug_object" */
430
431                         type = ACPI_TYPE_DEBUG_OBJECT;
432                         goto exit;
433
434
435                 default:
436
437                         ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
438                                 obj_desc->reference.opcode));
439                         return_ACPI_STATUS (AE_AML_INTERNAL);
440                 }
441         }
442
443         /*
444          * Now we are guaranteed to have an object that has not been created
445          * via the ref_of or Index operators.
446          */
447         type = ACPI_GET_OBJECT_TYPE (obj_desc);
448
449
450 exit:
451         /* Convert internal types to external types */
452
453         switch (type) {
454         case ACPI_TYPE_LOCAL_REGION_FIELD:
455         case ACPI_TYPE_LOCAL_BANK_FIELD:
456         case ACPI_TYPE_LOCAL_INDEX_FIELD:
457
458                 type = ACPI_TYPE_FIELD_UNIT;
459                 break;
460
461         case ACPI_TYPE_LOCAL_SCOPE:
462
463                 /* Per ACPI Specification, Scope is untyped */
464
465                 type = ACPI_TYPE_ANY;
466                 break;
467
468         default:
469                 /* No change to Type required */
470                 break;
471         }
472
473         *return_type = type;
474         if (return_desc) {
475                 *return_desc = obj_desc;
476         }
477         return_ACPI_STATUS (AE_OK);
478 }
479
480