Import changeset
[linux-flexiantxendom0-3.2.10.git] / drivers / acpi / interpreter / ammisc.c
1
2 /******************************************************************************
3  *
4  * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes
5  *              $Revision: 71 $
6  *
7  *****************************************************************************/
8
9 /*
10  *  Copyright (C) 2000 R. Byron Moore
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27
28 #include "acpi.h"
29 #include "acparser.h"
30 #include "acinterp.h"
31 #include "amlcode.h"
32 #include "acdispat.h"
33
34
35 #define _COMPONENT          INTERPRETER
36          MODULE_NAME         ("ammisc")
37
38
39 /*******************************************************************************
40  *
41  * FUNCTION:    Acpi_aml_exec_fatal
42  *
43  * PARAMETERS:  none
44  *
45  * RETURN:      Status.  If the OS returns from the OSD call, we just keep
46  *              on going.
47  *
48  * DESCRIPTION: Execute Fatal operator
49  *
50  * ACPI SPECIFICATION REFERENCES:
51  *  Def_fatal   :=  Fatal_op Fatal_type Fatal_code  Fatal_arg
52  *  Fatal_type  :=  Byte_data
53  *  Fatal_code  :=  DWord_data
54  *  Fatal_arg   :=  Term_arg=>Integer
55  *
56  ******************************************************************************/
57
58 ACPI_STATUS
59 acpi_aml_exec_fatal (
60         ACPI_WALK_STATE         *walk_state)
61 {
62         ACPI_OPERAND_OBJECT     *type_desc;
63         ACPI_OPERAND_OBJECT     *code_desc;
64         ACPI_OPERAND_OBJECT     *arg_desc;
65         ACPI_STATUS             status;
66
67
68         /* Resolve operands */
69
70         status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS, walk_state);
71         /* Get operands */
72
73         status |= acpi_ds_obj_stack_pop_object (&arg_desc, walk_state);
74         status |= acpi_ds_obj_stack_pop_object (&code_desc, walk_state);
75         status |= acpi_ds_obj_stack_pop_object (&type_desc, walk_state);
76         if (ACPI_FAILURE (status)) {
77                 /* Invalid parameters on object stack  */
78
79                 goto cleanup;
80         }
81
82
83         /* Def_fatal   :=  Fatal_op Fatal_type Fatal_code  Fatal_arg   */
84
85
86         /*
87          * TBD: [Unhandled] call OSD interface to notify OS of fatal error
88          * requiring shutdown!
89          */
90
91
92 cleanup:
93
94         /* Free the operands */
95
96         acpi_cm_remove_reference (arg_desc);
97         acpi_cm_remove_reference (code_desc);
98         acpi_cm_remove_reference (type_desc);
99
100
101         /* If we get back from the OS call, we might as well keep going. */
102
103         REPORT_WARNING (("An AML \"fatal\" Opcode (Fatal_op) was executed\n"));
104         return (AE_OK);
105 }
106
107
108 /*******************************************************************************
109  *
110  * FUNCTION:    Acpi_aml_exec_index
111  *
112  * PARAMETERS:  none
113  *
114  * RETURN:      Status
115  *
116  * DESCRIPTION: Execute Index operator
117  *
118  * ALLOCATION:  Deletes one operand descriptor -- other remains on stack
119  *
120  *  ACPI SPECIFICATION REFERENCES:
121  *  Def_index   :=  Index_op Buff_pkg_obj Index_value Result
122  *  Index_value :=  Term_arg=>Integer
123  *  Name_string :=  <Root_char Name_path> | <Prefix_path Name_path>
124  *  Result      :=  Super_name
125  *  Super_name  :=  Name_string | Arg_obj | Local_obj | Debug_obj | Def_index
126  *                             Local4_op | Local5_op | Local6_op | Local7_op
127  *
128  ******************************************************************************/
129
130 ACPI_STATUS
131 acpi_aml_exec_index (
132         ACPI_WALK_STATE         *walk_state,
133         ACPI_OPERAND_OBJECT     **return_desc)
134 {
135         ACPI_OPERAND_OBJECT     *obj_desc;
136         ACPI_OPERAND_OBJECT     *idx_desc;
137         ACPI_OPERAND_OBJECT     *res_desc;
138         ACPI_OPERAND_OBJECT     *ret_desc = NULL;
139         ACPI_OPERAND_OBJECT     *tmp_desc;
140         ACPI_STATUS             status;
141
142
143         /* Resolve operands */
144         /* First operand can be either a package or a buffer */
145
146         status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS, walk_state);
147         /* Get all operands */
148
149         status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
150         status |= acpi_ds_obj_stack_pop_object (&idx_desc, walk_state);
151         status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state);
152         if (ACPI_FAILURE (status)) {
153                 /* Invalid parameters on object stack  */
154
155                 goto cleanup;
156         }
157
158
159         /* Create the internal return object */
160
161         ret_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
162         if (!ret_desc) {
163                 status = AE_NO_MEMORY;
164                 goto cleanup;
165         }
166
167
168         /*
169          * At this point, the Obj_desc operand is either a Package or a Buffer
170          */
171
172         if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
173                 /* Object to be indexed is a Package */
174
175                 if (idx_desc->number.value >= obj_desc->package.count) {
176                         status = AE_AML_PACKAGE_LIMIT;
177                         goto cleanup;
178                 }
179
180                 if ((res_desc->common.type == INTERNAL_TYPE_REFERENCE) &&
181                         (res_desc->reference.op_code == AML_ZERO_OP))
182                 {
183                         /*
184                          * There is no actual result descriptor (the Zero_op Result
185                          * descriptor is a placeholder), so just delete the placeholder and
186                          * return a reference to the package element
187                          */
188
189                         acpi_cm_remove_reference (res_desc);
190                 }
191
192                 else {
193                         /*
194                          * Each element of the package is an internal object.  Get the one
195                          * we are after.
196                          */
197
198                         tmp_desc                      = obj_desc->package.elements[idx_desc->number.value];
199                         ret_desc->reference.op_code   = AML_INDEX_OP;
200                         ret_desc->reference.target_type = tmp_desc->common.type;
201                         ret_desc->reference.object    = tmp_desc;
202
203                         status = acpi_aml_exec_store (ret_desc, res_desc, walk_state);
204                         ret_desc->reference.object    = NULL;
205                 }
206
207                 /*
208                  * The local return object must always be a reference to the package element,
209                  * not the element itself.
210                  */
211                 ret_desc->reference.op_code   = AML_INDEX_OP;
212                 ret_desc->reference.target_type = ACPI_TYPE_PACKAGE;
213                 ret_desc->reference.where     = &obj_desc->package.elements[idx_desc->number.value];
214         }
215
216         else {
217                 /* Object to be indexed is a Buffer */
218
219                 if (idx_desc->number.value >= obj_desc->buffer.length) {
220                         status = AE_AML_BUFFER_LIMIT;
221                         goto cleanup;
222                 }
223
224                 ret_desc->reference.op_code     = AML_INDEX_OP;
225                 ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
226                 ret_desc->reference.object      = obj_desc;
227                 ret_desc->reference.offset      = (u32) idx_desc->number.value;
228
229                 status = acpi_aml_exec_store (ret_desc, res_desc, walk_state);
230         }
231
232
233 cleanup:
234
235         /* Always delete operands */
236
237         acpi_cm_remove_reference (obj_desc);
238         acpi_cm_remove_reference (idx_desc);
239
240         /* Delete return object on error */
241
242         if (ACPI_FAILURE (status)) {
243                 acpi_cm_remove_reference (res_desc);
244
245                 if (ret_desc) {
246                         acpi_cm_remove_reference (ret_desc);
247                         ret_desc = NULL;
248                 }
249         }
250
251         /* Set the return object and exit */
252
253         *return_desc = ret_desc;
254         return (status);
255 }
256
257
258 /*******************************************************************************
259  *
260  * FUNCTION:    Acpi_aml_exec_match
261  *
262  * PARAMETERS:  none
263  *
264  * RETURN:      Status
265  *
266  * DESCRIPTION: Execute Match operator
267  *
268  * ACPI SPECIFICATION REFERENCES:
269  *  Def_match   :=  Match_op Search_pkg Opcode1     Operand1
270  *                              Opcode2 Operand2    Start_index
271  *  Opcode1     :=  Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
272  *  Opcode2     :=  Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
273  *  Operand1    :=  Term_arg=>Integer
274  *  Operand2    :=  Term_arg=>Integer
275  *  Search_pkg  :=  Term_arg=>Package_object
276  *  Start_index :=  Term_arg=>Integer
277  *
278  ******************************************************************************/
279
280 ACPI_STATUS
281 acpi_aml_exec_match (
282         ACPI_WALK_STATE         *walk_state,
283         ACPI_OPERAND_OBJECT     **return_desc)
284 {
285         ACPI_OPERAND_OBJECT     *pkg_desc;
286         ACPI_OPERAND_OBJECT     *op1_desc;
287         ACPI_OPERAND_OBJECT     *V1_desc;
288         ACPI_OPERAND_OBJECT     *op2_desc;
289         ACPI_OPERAND_OBJECT     *V2_desc;
290         ACPI_OPERAND_OBJECT     *start_desc;
291         ACPI_OPERAND_OBJECT     *ret_desc = NULL;
292         ACPI_STATUS             status;
293         u32                     index;
294         u32                     match_value = (u32) -1;
295
296
297         /* Resolve all operands */
298
299         status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS, walk_state);
300         /* Get all operands */
301
302         status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state);
303         status |= acpi_ds_obj_stack_pop_object (&V2_desc, walk_state);
304         status |= acpi_ds_obj_stack_pop_object (&op2_desc, walk_state);
305         status |= acpi_ds_obj_stack_pop_object (&V1_desc, walk_state);
306         status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state);
307         status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state);
308
309         if (ACPI_FAILURE (status)) {
310                 /* Invalid parameters on object stack  */
311
312                 goto cleanup;
313         }
314
315         /* Validate match comparison sub-opcodes */
316
317         if ((op1_desc->number.value > MAX_MATCH_OPERATOR) ||
318                 (op2_desc->number.value > MAX_MATCH_OPERATOR))
319         {
320                 status = AE_AML_OPERAND_VALUE;
321                 goto cleanup;
322         }
323
324         index = (u32) start_desc->number.value;
325         if (index >= (u32) pkg_desc->package.count) {
326                 status = AE_AML_PACKAGE_LIMIT;
327                 goto cleanup;
328         }
329
330         ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER);
331         if (!ret_desc) {
332                 status = AE_NO_MEMORY;
333                 goto cleanup;
334
335         }
336
337         /*
338          * Examine each element until a match is found.  Within the loop,
339          * "continue" signifies that the current element does not match
340          * and the next should be examined.
341          * Upon finding a match, the loop will terminate via "break" at
342          * the bottom.  If it terminates "normally", Match_value will be -1
343          * (its initial value) indicating that no match was found.  When
344          * returned as a Number, this will produce the Ones value as specified.
345          */
346
347         for ( ; index < pkg_desc->package.count; ++index) {
348                 /*
349                  * Treat any NULL or non-numeric elements as non-matching.
350                  * TBD [Unhandled] - if an element is a Name,
351                  *      should we examine its value?
352                  */
353                 if (!pkg_desc->package.elements[index] ||
354                         ACPI_TYPE_NUMBER != pkg_desc->package.elements[index]->common.type)
355                 {
356                         continue;
357                 }
358
359                 /*
360                  * Within these switch statements:
361                  *      "break" (exit from the switch) signifies a match;
362                  *      "continue" (proceed to next iteration of enclosing
363                  *          "for" loop) signifies a non-match.
364                  */
365                 switch (op1_desc->number.value)
366                 {
367
368                 case MATCH_MTR:   /* always true */
369
370                         break;
371
372
373                 case MATCH_MEQ:   /* true if equal   */
374
375                         if (pkg_desc->package.elements[index]->number.value
376                                  != V1_desc->number.value)
377                         {
378                                 continue;
379                         }
380                         break;
381
382
383                 case MATCH_MLE:   /* true if less than or equal  */
384
385                         if (pkg_desc->package.elements[index]->number.value
386                                  > V1_desc->number.value)
387                         {
388                                 continue;
389                         }
390                         break;
391
392
393                 case MATCH_MLT:   /* true if less than   */
394
395                         if (pkg_desc->package.elements[index]->number.value
396                                  >= V1_desc->number.value)
397                         {
398                                 continue;
399                         }
400                         break;
401
402
403                 case MATCH_MGE:   /* true if greater than or equal   */
404
405                         if (pkg_desc->package.elements[index]->number.value
406                                  < V1_desc->number.value)
407                         {
408                                 continue;
409                         }
410                         break;
411
412
413                 case MATCH_MGT:   /* true if greater than    */
414
415                         if (pkg_desc->package.elements[index]->number.value
416                                  <= V1_desc->number.value)
417                         {
418                                 continue;
419                         }
420                         break;
421
422
423                 default:    /* undefined   */
424
425                         continue;
426                 }
427
428
429                 switch(op2_desc->number.value)
430                 {
431
432                 case MATCH_MTR:
433
434                         break;
435
436
437                 case MATCH_MEQ:
438
439                         if (pkg_desc->package.elements[index]->number.value
440                                  != V2_desc->number.value)
441                         {
442                                 continue;
443                         }
444                         break;
445
446
447                 case MATCH_MLE:
448
449                         if (pkg_desc->package.elements[index]->number.value
450                                  > V2_desc->number.value)
451                         {
452                                 continue;
453                         }
454                         break;
455
456
457                 case MATCH_MLT:
458
459                         if (pkg_desc->package.elements[index]->number.value
460                                  >= V2_desc->number.value)
461                         {
462                                 continue;
463                         }
464                         break;
465
466
467                 case MATCH_MGE:
468
469                         if (pkg_desc->package.elements[index]->number.value
470                                  < V2_desc->number.value)
471                         {
472                                 continue;
473                         }
474                         break;
475
476
477                 case MATCH_MGT:
478
479                         if (pkg_desc->package.elements[index]->number.value
480                                  <= V2_desc->number.value)
481                         {
482                                 continue;
483                         }
484                         break;
485
486
487                 default:
488
489                         continue;
490                 }
491
492                 /* Match found: exit from loop */
493
494                 match_value = index;
495                 break;
496         }
497
498         /* Match_value is the return value */
499
500         ret_desc->number.value = match_value;
501
502
503 cleanup:
504
505         /* Free the operands */
506
507         acpi_cm_remove_reference (start_desc);
508         acpi_cm_remove_reference (V2_desc);
509         acpi_cm_remove_reference (op2_desc);
510         acpi_cm_remove_reference (V1_desc);
511         acpi_cm_remove_reference (op1_desc);
512         acpi_cm_remove_reference (pkg_desc);
513
514
515         /* Delete return object on error */
516
517         if (ACPI_FAILURE (status) &&
518                 (ret_desc))
519         {
520                 acpi_cm_remove_reference (ret_desc);
521                 ret_desc = NULL;
522         }
523
524
525         /* Set the return object and exit */
526
527         *return_desc = ret_desc;
528         return (status);
529 }