vserver 2.0 rc7
[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 - 2005, 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                         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n",
191                                 stack_desc->reference.offset, obj_desc));
192
193                         /*
194                          * Now we can delete the original Reference Object and
195                          * replace it with the resolved value
196                          */
197                         acpi_ut_remove_reference (stack_desc);
198                         *stack_ptr = 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         acpi_status                     status;
331
332
333         ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple");
334
335
336         /*
337          * Operand can be either a namespace node or an operand descriptor
338          */
339         switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
340         case ACPI_DESC_TYPE_OPERAND:
341                 type = obj_desc->common.type;
342                 break;
343
344         case ACPI_DESC_TYPE_NAMED:
345                 type = ((struct acpi_namespace_node *) obj_desc)->type;
346                 obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
347
348                 /* If we had an Alias node, use the attached object for type info */
349
350                 if (type == ACPI_TYPE_LOCAL_ALIAS) {
351                         type = ((struct acpi_namespace_node *) obj_desc)->type;
352                         obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
353                 }
354                 break;
355
356         default:
357                 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
358         }
359
360
361         /*
362          * If type is anything other than a reference, we are done
363          */
364         if (type != ACPI_TYPE_LOCAL_REFERENCE) {
365                 goto exit;
366         }
367
368         /*
369          * For reference objects created via the ref_of or Index operators,
370          * we need to get to the base object (as per the ACPI specification
371          * of the object_type and size_of operators). This means traversing
372          * the list of possibly many nested references.
373          */
374         while (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
375                 switch (obj_desc->reference.opcode) {
376                 case AML_REF_OF_OP:
377
378                         /* Dereference the reference pointer */
379
380                         node = obj_desc->reference.object;
381
382                         /* All "References" point to a NS node */
383
384                         if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
385                                 ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
386                                                 node, acpi_ut_get_descriptor_name (node)));
387                                 return_ACPI_STATUS (AE_AML_INTERNAL);
388                         }
389
390                         /* Get the attached object */
391
392                         obj_desc = acpi_ns_get_attached_object (node);
393                         if (!obj_desc) {
394                                 /* No object, use the NS node type */
395
396                                 type = acpi_ns_get_type (node);
397                                 goto exit;
398                         }
399
400                         /* Check for circular references */
401
402                         if (obj_desc == operand) {
403                                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
404                         }
405                         break;
406
407
408                 case AML_INDEX_OP:
409
410                         /* Get the type of this reference (index into another object) */
411
412                         type = obj_desc->reference.target_type;
413                         if (type != ACPI_TYPE_PACKAGE) {
414                                 goto exit;
415                         }
416
417                         /*
418                          * The main object is a package, we want to get the type
419                          * of the individual package element that is referenced by
420                          * the index.
421                          *
422                          * This could of course in turn be another reference object.
423                          */
424                         obj_desc = *(obj_desc->reference.where);
425                         if (!obj_desc) {
426                                 /* NULL package elements are allowed */
427
428                                 type = 0; /* Uninitialized */
429                                 goto exit;
430                         }
431                         break;
432
433
434                 case AML_INT_NAMEPATH_OP:
435
436                         /* Dereference the reference pointer */
437
438                         node = obj_desc->reference.node;
439
440                         /* All "References" point to a NS node */
441
442                         if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
443                                 ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
444                                                 node, acpi_ut_get_descriptor_name (node)));
445                            return_ACPI_STATUS (AE_AML_INTERNAL);
446                         }
447
448                         /* Get the attached object */
449
450                         obj_desc = acpi_ns_get_attached_object (node);
451                         if (!obj_desc) {
452                                 /* No object, use the NS node type */
453
454                                 type = acpi_ns_get_type (node);
455                                 goto exit;
456                         }
457
458                         /* Check for circular references */
459
460                         if (obj_desc == operand) {
461                                 return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
462                         }
463                         break;
464
465
466                 case AML_LOCAL_OP:
467                 case AML_ARG_OP:
468
469                         if (return_desc) {
470                                 status = acpi_ds_method_data_get_value (obj_desc->reference.opcode,
471                                                   obj_desc->reference.offset, walk_state, &obj_desc);
472                                 if (ACPI_FAILURE (status)) {
473                                         return_ACPI_STATUS (status);
474                                 }
475                                 acpi_ut_remove_reference (obj_desc);
476                         }
477                         else {
478                                 status = acpi_ds_method_data_get_node (obj_desc->reference.opcode,
479                                                  obj_desc->reference.offset, walk_state, &node);
480                                 if (ACPI_FAILURE (status)) {
481                                         return_ACPI_STATUS (status);
482                                 }
483
484                                 obj_desc = acpi_ns_get_attached_object (node);
485                                 if (!obj_desc) {
486                                         type = ACPI_TYPE_ANY;
487                                         goto exit;
488                                 }
489                         }
490                         break;
491
492
493                 case AML_DEBUG_OP:
494
495                         /* The Debug Object is of type "debug_object" */
496
497                         type = ACPI_TYPE_DEBUG_OBJECT;
498                         goto exit;
499
500
501                 default:
502
503                         ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
504                                 obj_desc->reference.opcode));
505                         return_ACPI_STATUS (AE_AML_INTERNAL);
506                 }
507         }
508
509         /*
510          * Now we are guaranteed to have an object that has not been created
511          * via the ref_of or Index operators.
512          */
513         type = ACPI_GET_OBJECT_TYPE (obj_desc);
514
515
516 exit:
517         /* Convert internal types to external types */
518
519         switch (type) {
520         case ACPI_TYPE_LOCAL_REGION_FIELD:
521         case ACPI_TYPE_LOCAL_BANK_FIELD:
522         case ACPI_TYPE_LOCAL_INDEX_FIELD:
523
524                 type = ACPI_TYPE_FIELD_UNIT;
525                 break;
526
527         case ACPI_TYPE_LOCAL_SCOPE:
528
529                 /* Per ACPI Specification, Scope is untyped */
530
531                 type = ACPI_TYPE_ANY;
532                 break;
533
534         default:
535                 /* No change to Type required */
536                 break;
537         }
538
539         *return_type = type;
540         if (return_desc) {
541                 *return_desc = obj_desc;
542         }
543         return_ACPI_STATUS (AE_OK);
544 }
545
546