0d7cd73cde65a782f4f2627a84a45f9f7d9c083e
[reactos.git] / reactos / drivers / bus / acpi / executer / ammisc.c
1
2 /******************************************************************************
3 *
4 * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes
5 * $Revision: 1.1 $
6 *
7 *****************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 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 ACPI_EXECUTER
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->integer.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.opcode == AML_ZERO_OP)) {
182 /*
183 * There is no actual result descriptor (the Zero_op Result
184 * descriptor is a placeholder), so just delete the placeholder and
185 * return a reference to the package element
186 */
187
188 acpi_cm_remove_reference (res_desc);
189 }
190
191 else {
192 /*
193 * Each element of the package is an internal object. Get the one
194 * we are after.
195 */
196
197 tmp_desc = obj_desc->package.elements[idx_desc->integer.value];
198 ret_desc->reference.opcode = AML_INDEX_OP;
199 ret_desc->reference.target_type = tmp_desc->common.type;
200 ret_desc->reference.object = tmp_desc;
201
202 status = acpi_aml_exec_store (ret_desc, res_desc, walk_state);
203 ret_desc->reference.object = NULL;
204 }
205
206 /*
207 * The local return object must always be a reference to the package element,
208 * not the element itself.
209 */
210 ret_desc->reference.opcode = AML_INDEX_OP;
211 ret_desc->reference.target_type = ACPI_TYPE_PACKAGE;
212 ret_desc->reference.where = &obj_desc->package.elements[idx_desc->integer.value];
213 }
214
215 else {
216 /* Object to be indexed is a Buffer */
217
218 if (idx_desc->integer.value >= obj_desc->buffer.length) {
219 status = AE_AML_BUFFER_LIMIT;
220 goto cleanup;
221 }
222
223 ret_desc->reference.opcode = AML_INDEX_OP;
224 ret_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
225 ret_desc->reference.object = obj_desc;
226 ret_desc->reference.offset = (u32) idx_desc->integer.value;
227
228 status = acpi_aml_exec_store (ret_desc, res_desc, walk_state);
229 }
230
231
232 cleanup:
233
234 /* Always delete operands */
235
236 acpi_cm_remove_reference (obj_desc);
237 acpi_cm_remove_reference (idx_desc);
238
239 /* Delete return object on error */
240
241 if (ACPI_FAILURE (status)) {
242 acpi_cm_remove_reference (res_desc);
243
244 if (ret_desc) {
245 acpi_cm_remove_reference (ret_desc);
246 ret_desc = NULL;
247 }
248 }
249
250 /* Set the return object and exit */
251
252 *return_desc = ret_desc;
253 return (status);
254 }
255
256
257 /*******************************************************************************
258 *
259 * FUNCTION: Acpi_aml_exec_match
260 *
261 * PARAMETERS: none
262 *
263 * RETURN: Status
264 *
265 * DESCRIPTION: Execute Match operator
266 *
267 * ACPI SPECIFICATION REFERENCES:
268 * Def_match := Match_op Search_pkg Opcode1 Operand1
269 * Opcode2 Operand2 Start_index
270 * Opcode1 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
271 * Opcode2 := Byte_data: MTR, MEQ, MLE, MLT, MGE, or MGT
272 * Operand1 := Term_arg=>Integer
273 * Operand2 := Term_arg=>Integer
274 * Search_pkg := Term_arg=>Package_object
275 * Start_index := Term_arg=>Integer
276 *
277 ******************************************************************************/
278
279 ACPI_STATUS
280 acpi_aml_exec_match (
281 ACPI_WALK_STATE *walk_state,
282 ACPI_OPERAND_OBJECT **return_desc)
283 {
284 ACPI_OPERAND_OBJECT *pkg_desc;
285 ACPI_OPERAND_OBJECT *op1_desc;
286 ACPI_OPERAND_OBJECT *V1_desc;
287 ACPI_OPERAND_OBJECT *op2_desc;
288 ACPI_OPERAND_OBJECT *V2_desc;
289 ACPI_OPERAND_OBJECT *start_desc;
290 ACPI_OPERAND_OBJECT *ret_desc = NULL;
291 ACPI_STATUS status;
292 u32 index;
293 u32 match_value = (u32) -1;
294
295
296 /* Resolve all operands */
297
298 status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS, walk_state);
299 /* Get all operands */
300
301 status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state);
302 status |= acpi_ds_obj_stack_pop_object (&V2_desc, walk_state);
303 status |= acpi_ds_obj_stack_pop_object (&op2_desc, walk_state);
304 status |= acpi_ds_obj_stack_pop_object (&V1_desc, walk_state);
305 status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state);
306 status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state);
307
308 if (ACPI_FAILURE (status)) {
309 /* Invalid parameters on object stack */
310
311 goto cleanup;
312 }
313
314 /* Validate match comparison sub-opcodes */
315
316 if ((op1_desc->integer.value > MAX_MATCH_OPERATOR) ||
317 (op2_desc->integer.value > MAX_MATCH_OPERATOR)) {
318 status = AE_AML_OPERAND_VALUE;
319 goto cleanup;
320 }
321
322 index = (u32) start_desc->integer.value;
323 if (index >= (u32) pkg_desc->package.count) {
324 status = AE_AML_PACKAGE_LIMIT;
325 goto cleanup;
326 }
327
328 ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_INTEGER);
329 if (!ret_desc) {
330 status = AE_NO_MEMORY;
331 goto cleanup;
332
333 }
334
335 /*
336 * Examine each element until a match is found. Within the loop,
337 * "continue" signifies that the current element does not match
338 * and the next should be examined.
339 * Upon finding a match, the loop will terminate via "break" at
340 * the bottom. If it terminates "normally", Match_value will be -1
341 * (its initial value) indicating that no match was found. When
342 * returned as a Number, this will produce the Ones value as specified.
343 */
344
345 for ( ; index < pkg_desc->package.count; ++index) {
346 /*
347 * Treat any NULL or non-numeric elements as non-matching.
348 * TBD [Unhandled] - if an element is a Name,
349 * should we examine its value?
350 */
351 if (!pkg_desc->package.elements[index] ||
352 ACPI_TYPE_INTEGER != pkg_desc->package.elements[index]->common.type) {
353 continue;
354 }
355
356 /*
357 * Within these switch statements:
358 * "break" (exit from the switch) signifies a match;
359 * "continue" (proceed to next iteration of enclosing
360 * "for" loop) signifies a non-match.
361 */
362 switch (op1_desc->integer.value) {
363
364 case MATCH_MTR: /* always true */
365
366 break;
367
368
369 case MATCH_MEQ: /* true if equal */
370
371 if (pkg_desc->package.elements[index]->integer.value
372 != V1_desc->integer.value) {
373 continue;
374 }
375 break;
376
377
378 case MATCH_MLE: /* true if less than or equal */
379
380 if (pkg_desc->package.elements[index]->integer.value
381 > V1_desc->integer.value) {
382 continue;
383 }
384 break;
385
386
387 case MATCH_MLT: /* true if less than */
388
389 if (pkg_desc->package.elements[index]->integer.value
390 >= V1_desc->integer.value) {
391 continue;
392 }
393 break;
394
395
396 case MATCH_MGE: /* true if greater than or equal */
397
398 if (pkg_desc->package.elements[index]->integer.value
399 < V1_desc->integer.value) {
400 continue;
401 }
402 break;
403
404
405 case MATCH_MGT: /* true if greater than */
406
407 if (pkg_desc->package.elements[index]->integer.value
408 <= V1_desc->integer.value) {
409 continue;
410 }
411 break;
412
413
414 default: /* undefined */
415
416 continue;
417 }
418
419
420 switch(op2_desc->integer.value) {
421
422 case MATCH_MTR:
423
424 break;
425
426
427 case MATCH_MEQ:
428
429 if (pkg_desc->package.elements[index]->integer.value
430 != V2_desc->integer.value) {
431 continue;
432 }
433 break;
434
435
436 case MATCH_MLE:
437
438 if (pkg_desc->package.elements[index]->integer.value
439 > V2_desc->integer.value) {
440 continue;
441 }
442 break;
443
444
445 case MATCH_MLT:
446
447 if (pkg_desc->package.elements[index]->integer.value
448 >= V2_desc->integer.value) {
449 continue;
450 }
451 break;
452
453
454 case MATCH_MGE:
455
456 if (pkg_desc->package.elements[index]->integer.value
457 < V2_desc->integer.value) {
458 continue;
459 }
460 break;
461
462
463 case MATCH_MGT:
464
465 if (pkg_desc->package.elements[index]->integer.value
466 <= V2_desc->integer.value) {
467 continue;
468 }
469 break;
470
471
472 default:
473
474 continue;
475 }
476
477 /* Match found: exit from loop */
478
479 match_value = index;
480 break;
481 }
482
483 /* Match_value is the return value */
484
485 ret_desc->integer.value = match_value;
486
487
488 cleanup:
489
490 /* Free the operands */
491
492 acpi_cm_remove_reference (start_desc);
493 acpi_cm_remove_reference (V2_desc);
494 acpi_cm_remove_reference (op2_desc);
495 acpi_cm_remove_reference (V1_desc);
496 acpi_cm_remove_reference (op1_desc);
497 acpi_cm_remove_reference (pkg_desc);
498
499
500 /* Delete return object on error */
501
502 if (ACPI_FAILURE (status) &&
503 (ret_desc)) {
504 acpi_cm_remove_reference (ret_desc);
505 ret_desc = NULL;
506 }
507
508
509 /* Set the return object and exit */
510
511 *return_desc = ret_desc;
512 return (status);
513 }