Merge branch 'origin'
[pandora-kernel.git] / drivers / acpi / executer / exoparg2.c
1 /******************************************************************************
2  *
3  * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2006, R. Byron Moore
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #include <acpi/acpi.h>
45 #include <acpi/acparser.h>
46 #include <acpi/acinterp.h>
47 #include <acpi/acevents.h>
48 #include <acpi/amlcode.h>
49
50 #define _COMPONENT          ACPI_EXECUTER
51 ACPI_MODULE_NAME("exoparg2")
52
53 /*!
54  * Naming convention for AML interpreter execution routines.
55  *
56  * The routines that begin execution of AML opcodes are named with a common
57  * convention based upon the number of arguments, the number of target operands,
58  * and whether or not a value is returned:
59  *
60  *      AcpiExOpcode_xA_yT_zR
61  *
62  * Where:
63  *
64  * xA - ARGUMENTS:    The number of arguments (input operands) that are
65  *                    required for this opcode type (1 through 6 args).
66  * yT - TARGETS:      The number of targets (output operands) that are required
67  *                    for this opcode type (0, 1, or 2 targets).
68  * zR - RETURN VALUE: Indicates whether this opcode type returns a value
69  *                    as the function return (0 or 1).
70  *
71  * The AcpiExOpcode* functions are called via the Dispatcher component with
72  * fully resolved operands.
73 !*/
74 /*******************************************************************************
75  *
76  * FUNCTION:    acpi_ex_opcode_2A_0T_0R
77  *
78  * PARAMETERS:  walk_state          - Current walk state
79  *
80  * RETURN:      Status
81  *
82  * DESCRIPTION: Execute opcode with two arguments, no target, and no return
83  *              value.
84  *
85  * ALLOCATION:  Deletes both operands
86  *
87  ******************************************************************************/
88 acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state)
89 {
90         union acpi_operand_object **operand = &walk_state->operands[0];
91         struct acpi_namespace_node *node;
92         u32 value;
93         acpi_status status = AE_OK;
94
95         ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_0R",
96                                 acpi_ps_get_opcode_name(walk_state->opcode));
97
98         /* Examine the opcode */
99
100         switch (walk_state->opcode) {
101         case AML_NOTIFY_OP:     /* Notify (notify_object, notify_value) */
102
103                 /* The first operand is a namespace node */
104
105                 node = (struct acpi_namespace_node *)operand[0];
106
107                 /* Second value is the notify value */
108
109                 value = (u32) operand[1]->integer.value;
110
111                 /* Are notifies allowed on this object? */
112
113                 if (!acpi_ev_is_notify_object(node)) {
114                         ACPI_ERROR((AE_INFO,
115                                     "Unexpected notify object type [%s]",
116                                     acpi_ut_get_type_name(node->type)));
117
118                         status = AE_AML_OPERAND_TYPE;
119                         break;
120                 }
121 #ifdef ACPI_GPE_NOTIFY_CHECK
122                 /*
123                  * GPE method wake/notify check.  Here, we want to ensure that we
124                  * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx
125                  * GPE method during system runtime.  If we do, the GPE is marked
126                  * as "wake-only" and disabled.
127                  *
128                  * 1) Is the Notify() value == device_wake?
129                  * 2) Is this a GPE deferred method?  (An _Lxx or _Exx method)
130                  * 3) Did the original GPE happen at system runtime?
131                  *    (versus during wake)
132                  *
133                  * If all three cases are true, this is a wake-only GPE that should
134                  * be disabled at runtime.
135                  */
136                 if (value == 2) {       /* device_wake */
137                         status =
138                             acpi_ev_check_for_wake_only_gpe(walk_state->
139                                                             gpe_event_info);
140                         if (ACPI_FAILURE(status)) {
141                                 /* AE_WAKE_ONLY_GPE only error, means ignore this notify */
142
143                                 return_ACPI_STATUS(AE_OK)
144                         }
145                 }
146 #endif
147
148                 /*
149                  * Dispatch the notify to the appropriate handler
150                  * NOTE: the request is queued for execution after this method
151                  * completes.  The notify handlers are NOT invoked synchronously
152                  * from this thread -- because handlers may in turn run other
153                  * control methods.
154                  */
155                 status = acpi_ev_queue_notify_request(node, value);
156                 break;
157
158         default:
159
160                 ACPI_ERROR((AE_INFO, "Unknown AML opcode %X",
161                             walk_state->opcode));
162                 status = AE_AML_BAD_OPCODE;
163         }
164
165         return_ACPI_STATUS(status);
166 }
167
168 /*******************************************************************************
169  *
170  * FUNCTION:    acpi_ex_opcode_2A_2T_1R
171  *
172  * PARAMETERS:  walk_state          - Current walk state
173  *
174  * RETURN:      Status
175  *
176  * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets
177  *              and one implicit return value.
178  *
179  ******************************************************************************/
180
181 acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state)
182 {
183         union acpi_operand_object **operand = &walk_state->operands[0];
184         union acpi_operand_object *return_desc1 = NULL;
185         union acpi_operand_object *return_desc2 = NULL;
186         acpi_status status;
187
188         ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_2T_1R",
189                                 acpi_ps_get_opcode_name(walk_state->opcode));
190
191         /* Execute the opcode */
192
193         switch (walk_state->opcode) {
194         case AML_DIVIDE_OP:
195
196                 /* Divide (Dividend, Divisor, remainder_result quotient_result) */
197
198                 return_desc1 =
199                     acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
200                 if (!return_desc1) {
201                         status = AE_NO_MEMORY;
202                         goto cleanup;
203                 }
204
205                 return_desc2 =
206                     acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
207                 if (!return_desc2) {
208                         status = AE_NO_MEMORY;
209                         goto cleanup;
210                 }
211
212                 /* Quotient to return_desc1, remainder to return_desc2 */
213
214                 status = acpi_ut_divide(operand[0]->integer.value,
215                                         operand[1]->integer.value,
216                                         &return_desc1->integer.value,
217                                         &return_desc2->integer.value);
218                 if (ACPI_FAILURE(status)) {
219                         goto cleanup;
220                 }
221                 break;
222
223         default:
224
225                 ACPI_ERROR((AE_INFO, "Unknown AML opcode %X",
226                             walk_state->opcode));
227                 status = AE_AML_BAD_OPCODE;
228                 goto cleanup;
229         }
230
231         /* Store the results to the target reference operands */
232
233         status = acpi_ex_store(return_desc2, operand[2], walk_state);
234         if (ACPI_FAILURE(status)) {
235                 goto cleanup;
236         }
237
238         status = acpi_ex_store(return_desc1, operand[3], walk_state);
239         if (ACPI_FAILURE(status)) {
240                 goto cleanup;
241         }
242
243         /* Return the remainder */
244
245         walk_state->result_obj = return_desc1;
246
247       cleanup:
248         /*
249          * Since the remainder is not returned indirectly, remove a reference to
250          * it. Only the quotient is returned indirectly.
251          */
252         acpi_ut_remove_reference(return_desc2);
253
254         if (ACPI_FAILURE(status)) {
255                 /* Delete the return object */
256
257                 acpi_ut_remove_reference(return_desc1);
258         }
259
260         return_ACPI_STATUS(status);
261 }
262
263 /*******************************************************************************
264  *
265  * FUNCTION:    acpi_ex_opcode_2A_1T_1R
266  *
267  * PARAMETERS:  walk_state          - Current walk state
268  *
269  * RETURN:      Status
270  *
271  * DESCRIPTION: Execute opcode with two arguments, one target, and a return
272  *              value.
273  *
274  ******************************************************************************/
275
276 acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
277 {
278         union acpi_operand_object **operand = &walk_state->operands[0];
279         union acpi_operand_object *return_desc = NULL;
280         acpi_integer index;
281         acpi_status status = AE_OK;
282         acpi_size length;
283
284         ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_1T_1R",
285                                 acpi_ps_get_opcode_name(walk_state->opcode));
286
287         /* Execute the opcode */
288
289         if (walk_state->op_info->flags & AML_MATH) {
290                 /* All simple math opcodes (add, etc.) */
291
292                 return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
293                 if (!return_desc) {
294                         status = AE_NO_MEMORY;
295                         goto cleanup;
296                 }
297
298                 return_desc->integer.value =
299                     acpi_ex_do_math_op(walk_state->opcode,
300                                        operand[0]->integer.value,
301                                        operand[1]->integer.value);
302                 goto store_result_to_target;
303         }
304
305         switch (walk_state->opcode) {
306         case AML_MOD_OP:        /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */
307
308                 return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
309                 if (!return_desc) {
310                         status = AE_NO_MEMORY;
311                         goto cleanup;
312                 }
313
314                 /* return_desc will contain the remainder */
315
316                 status = acpi_ut_divide(operand[0]->integer.value,
317                                         operand[1]->integer.value,
318                                         NULL, &return_desc->integer.value);
319                 break;
320
321         case AML_CONCAT_OP:     /* Concatenate (Data1, Data2, Result) */
322
323                 status = acpi_ex_do_concatenate(operand[0], operand[1],
324                                                 &return_desc, walk_state);
325                 break;
326
327         case AML_TO_STRING_OP:  /* to_string (Buffer, Length, Result) (ACPI 2.0) */
328
329                 /*
330                  * Input object is guaranteed to be a buffer at this point (it may have
331                  * been converted.)  Copy the raw buffer data to a new object of
332                  * type String.
333                  */
334
335                 /*
336                  * Get the length of the new string. It is the smallest of:
337                  * 1) Length of the input buffer
338                  * 2) Max length as specified in the to_string operator
339                  * 3) Length of input buffer up to a zero byte (null terminator)
340                  *
341                  * NOTE: A length of zero is ok, and will create a zero-length, null
342                  *       terminated string.
343                  */
344                 length = 0;
345                 while ((length < operand[0]->buffer.length) &&
346                        (length < operand[1]->integer.value) &&
347                        (operand[0]->buffer.pointer[length])) {
348                         length++;
349                 }
350
351                 /* Allocate a new string object */
352
353                 return_desc = acpi_ut_create_string_object(length);
354                 if (!return_desc) {
355                         status = AE_NO_MEMORY;
356                         goto cleanup;
357                 }
358
359                 /*
360                  * Copy the raw buffer data with no transform.
361                  * (NULL terminated already)
362                  */
363                 ACPI_MEMCPY(return_desc->string.pointer,
364                             operand[0]->buffer.pointer, length);
365                 break;
366
367         case AML_CONCAT_RES_OP:
368
369                 /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */
370
371                 status = acpi_ex_concat_template(operand[0], operand[1],
372                                                  &return_desc, walk_state);
373                 break;
374
375         case AML_INDEX_OP:      /* Index (Source Index Result) */
376
377                 /* Create the internal return object */
378
379                 return_desc =
380                     acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
381                 if (!return_desc) {
382                         status = AE_NO_MEMORY;
383                         goto cleanup;
384                 }
385
386                 index = operand[1]->integer.value;
387
388                 /* At this point, the Source operand is a Package, Buffer, or String */
389
390                 if (ACPI_GET_OBJECT_TYPE(operand[0]) == ACPI_TYPE_PACKAGE) {
391                         /* Object to be indexed is a Package */
392
393                         if (index >= operand[0]->package.count) {
394                                 ACPI_ERROR((AE_INFO,
395                                             "Index value (%X%8.8X) beyond package end (%X)",
396                                             ACPI_FORMAT_UINT64(index),
397                                             operand[0]->package.count));
398                                 status = AE_AML_PACKAGE_LIMIT;
399                                 goto cleanup;
400                         }
401
402                         return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
403                         return_desc->reference.object = operand[0];
404                         return_desc->reference.where =
405                             &operand[0]->package.elements[index];
406                 } else {
407                         /* Object to be indexed is a Buffer/String */
408
409                         if (index >= operand[0]->buffer.length) {
410                                 ACPI_ERROR((AE_INFO,
411                                             "Index value (%X%8.8X) beyond end of buffer (%X)",
412                                             ACPI_FORMAT_UINT64(index),
413                                             operand[0]->buffer.length));
414                                 status = AE_AML_BUFFER_LIMIT;
415                                 goto cleanup;
416                         }
417
418                         return_desc->reference.target_type =
419                             ACPI_TYPE_BUFFER_FIELD;
420                         return_desc->reference.object = operand[0];
421                 }
422
423                 /*
424                  * Add a reference to the target package/buffer/string for the life
425                  * of the index.
426                  */
427                 acpi_ut_add_reference(operand[0]);
428
429                 /* Complete the Index reference object */
430
431                 return_desc->reference.opcode = AML_INDEX_OP;
432                 return_desc->reference.offset = (u32) index;
433
434                 /* Store the reference to the Target */
435
436                 status = acpi_ex_store(return_desc, operand[2], walk_state);
437
438                 /* Return the reference */
439
440                 walk_state->result_obj = return_desc;
441                 goto cleanup;
442
443         default:
444
445                 ACPI_ERROR((AE_INFO, "Unknown AML opcode %X",
446                             walk_state->opcode));
447                 status = AE_AML_BAD_OPCODE;
448                 break;
449         }
450
451       store_result_to_target:
452
453         if (ACPI_SUCCESS(status)) {
454                 /*
455                  * Store the result of the operation (which is now in return_desc) into
456                  * the Target descriptor.
457                  */
458                 status = acpi_ex_store(return_desc, operand[2], walk_state);
459                 if (ACPI_FAILURE(status)) {
460                         goto cleanup;
461                 }
462
463                 if (!walk_state->result_obj) {
464                         walk_state->result_obj = return_desc;
465                 }
466         }
467
468       cleanup:
469
470         /* Delete return object on error */
471
472         if (ACPI_FAILURE(status)) {
473                 acpi_ut_remove_reference(return_desc);
474         }
475
476         return_ACPI_STATUS(status);
477 }
478
479 /*******************************************************************************
480  *
481  * FUNCTION:    acpi_ex_opcode_2A_0T_1R
482  *
483  * PARAMETERS:  walk_state          - Current walk state
484  *
485  * RETURN:      Status
486  *
487  * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value
488  *
489  ******************************************************************************/
490
491 acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state)
492 {
493         union acpi_operand_object **operand = &walk_state->operands[0];
494         union acpi_operand_object *return_desc = NULL;
495         acpi_status status = AE_OK;
496         u8 logical_result = FALSE;
497
498         ACPI_FUNCTION_TRACE_STR("ex_opcode_2A_0T_1R",
499                                 acpi_ps_get_opcode_name(walk_state->opcode));
500
501         /* Create the internal return object */
502
503         return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
504         if (!return_desc) {
505                 status = AE_NO_MEMORY;
506                 goto cleanup;
507         }
508
509         /* Execute the Opcode */
510
511         if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) {
512                 /* logical_op (Operand0, Operand1) */
513
514                 status = acpi_ex_do_logical_numeric_op(walk_state->opcode,
515                                                        operand[0]->integer.
516                                                        value,
517                                                        operand[1]->integer.
518                                                        value, &logical_result);
519                 goto store_logical_result;
520         } else if (walk_state->op_info->flags & AML_LOGICAL) {
521                 /* logical_op (Operand0, Operand1) */
522
523                 status = acpi_ex_do_logical_op(walk_state->opcode, operand[0],
524                                                operand[1], &logical_result);
525                 goto store_logical_result;
526         }
527
528         switch (walk_state->opcode) {
529         case AML_ACQUIRE_OP:    /* Acquire (mutex_object, Timeout) */
530
531                 status =
532                     acpi_ex_acquire_mutex(operand[1], operand[0], walk_state);
533                 if (status == AE_TIME) {
534                         logical_result = TRUE;  /* TRUE = Acquire timed out */
535                         status = AE_OK;
536                 }
537                 break;
538
539         case AML_WAIT_OP:       /* Wait (event_object, Timeout) */
540
541                 status = acpi_ex_system_wait_event(operand[1], operand[0]);
542                 if (status == AE_TIME) {
543                         logical_result = TRUE;  /* TRUE, Wait timed out */
544                         status = AE_OK;
545                 }
546                 break;
547
548         default:
549
550                 ACPI_ERROR((AE_INFO, "Unknown AML opcode %X",
551                             walk_state->opcode));
552                 status = AE_AML_BAD_OPCODE;
553                 goto cleanup;
554         }
555
556       store_logical_result:
557         /*
558          * Set return value to according to logical_result. logical TRUE (all ones)
559          * Default is FALSE (zero)
560          */
561         if (logical_result) {
562                 return_desc->integer.value = ACPI_INTEGER_MAX;
563         }
564
565         walk_state->result_obj = return_desc;
566
567       cleanup:
568
569         /* Delete return object on error */
570
571         if (ACPI_FAILURE(status)) {
572                 acpi_ut_remove_reference(return_desc);
573         }
574
575         return_ACPI_STATUS(status);
576 }