diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/acpi/dispatcher |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/acpi/dispatcher')
-rw-r--r-- | drivers/acpi/dispatcher/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsfield.c | 601 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsinit.c | 235 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsmethod.c | 597 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsmthdat.c | 715 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsobject.c | 618 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 1151 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsutils.c | 744 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswexec.c | 751 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswload.c | 976 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswscope.c | 229 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswstate.c | 1100 |
12 files changed, 7726 insertions, 0 deletions
diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile new file mode 100644 index 000000000000..eb7e602a83cd --- /dev/null +++ b/drivers/acpi/dispatcher/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for all Linux ACPI interpreter subdirectories | ||
3 | # | ||
4 | |||
5 | obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ | ||
6 | dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ | ||
7 | dsinit.o | ||
8 | |||
9 | EXTRA_CFLAGS += $(ACPI_CFLAGS) | ||
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c new file mode 100644 index 000000000000..2779211be756 --- /dev/null +++ b/drivers/acpi/dispatcher/dsfield.c | |||
@@ -0,0 +1,601 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dsfield - Dispatcher field routines | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/amlcode.h> | ||
47 | #include <acpi/acdispat.h> | ||
48 | #include <acpi/acinterp.h> | ||
49 | #include <acpi/acnamesp.h> | ||
50 | #include <acpi/acparser.h> | ||
51 | |||
52 | |||
53 | #define _COMPONENT ACPI_DISPATCHER | ||
54 | ACPI_MODULE_NAME ("dsfield") | ||
55 | |||
56 | |||
57 | /******************************************************************************* | ||
58 | * | ||
59 | * FUNCTION: acpi_ds_create_buffer_field | ||
60 | * | ||
61 | * PARAMETERS: Opcode - The opcode to be executed | ||
62 | * Operands - List of operands for the opcode | ||
63 | * walk_state - Current state | ||
64 | * | ||
65 | * RETURN: Status | ||
66 | * | ||
67 | * DESCRIPTION: Execute the create_field operators: | ||
68 | * create_bit_field_op, | ||
69 | * create_byte_field_op, | ||
70 | * create_word_field_op, | ||
71 | * create_dword_field_op, | ||
72 | * create_qword_field_op, | ||
73 | * create_field_op (all of which define fields in buffers) | ||
74 | * | ||
75 | ******************************************************************************/ | ||
76 | |||
77 | acpi_status | ||
78 | acpi_ds_create_buffer_field ( | ||
79 | union acpi_parse_object *op, | ||
80 | struct acpi_walk_state *walk_state) | ||
81 | { | ||
82 | union acpi_parse_object *arg; | ||
83 | struct acpi_namespace_node *node; | ||
84 | acpi_status status; | ||
85 | union acpi_operand_object *obj_desc; | ||
86 | union acpi_operand_object *second_desc = NULL; | ||
87 | u32 flags; | ||
88 | |||
89 | |||
90 | ACPI_FUNCTION_TRACE ("ds_create_buffer_field"); | ||
91 | |||
92 | |||
93 | /* Get the name_string argument */ | ||
94 | |||
95 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { | ||
96 | arg = acpi_ps_get_arg (op, 3); | ||
97 | } | ||
98 | else { | ||
99 | /* Create Bit/Byte/Word/Dword field */ | ||
100 | |||
101 | arg = acpi_ps_get_arg (op, 2); | ||
102 | } | ||
103 | |||
104 | if (!arg) { | ||
105 | return_ACPI_STATUS (AE_AML_NO_OPERAND); | ||
106 | } | ||
107 | |||
108 | if (walk_state->deferred_node) { | ||
109 | node = walk_state->deferred_node; | ||
110 | status = AE_OK; | ||
111 | } | ||
112 | else { | ||
113 | /* | ||
114 | * During the load phase, we want to enter the name of the field into | ||
115 | * the namespace. During the execute phase (when we evaluate the size | ||
116 | * operand), we want to lookup the name | ||
117 | */ | ||
118 | if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { | ||
119 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; | ||
120 | } | ||
121 | else { | ||
122 | flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Enter the name_string into the namespace | ||
127 | */ | ||
128 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, | ||
129 | ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1, | ||
130 | flags, walk_state, &(node)); | ||
131 | if (ACPI_FAILURE (status)) { | ||
132 | ACPI_REPORT_NSERROR (arg->common.value.string, status); | ||
133 | return_ACPI_STATUS (status); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /* We could put the returned object (Node) on the object stack for later, but | ||
138 | * for now, we will put it in the "op" object that the parser uses, so we | ||
139 | * can get it again at the end of this scope | ||
140 | */ | ||
141 | op->common.node = node; | ||
142 | |||
143 | /* | ||
144 | * If there is no object attached to the node, this node was just created and | ||
145 | * we need to create the field object. Otherwise, this was a lookup of an | ||
146 | * existing node and we don't want to create the field object again. | ||
147 | */ | ||
148 | obj_desc = acpi_ns_get_attached_object (node); | ||
149 | if (obj_desc) { | ||
150 | return_ACPI_STATUS (AE_OK); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * The Field definition is not fully parsed at this time. | ||
155 | * (We must save the address of the AML for the buffer and index operands) | ||
156 | */ | ||
157 | |||
158 | /* Create the buffer field object */ | ||
159 | |||
160 | obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER_FIELD); | ||
161 | if (!obj_desc) { | ||
162 | status = AE_NO_MEMORY; | ||
163 | goto cleanup; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * Remember location in AML stream of the field unit | ||
168 | * opcode and operands -- since the buffer and index | ||
169 | * operands must be evaluated. | ||
170 | */ | ||
171 | second_desc = obj_desc->common.next_object; | ||
172 | second_desc->extra.aml_start = op->named.data; | ||
173 | second_desc->extra.aml_length = op->named.length; | ||
174 | obj_desc->buffer_field.node = node; | ||
175 | |||
176 | /* Attach constructed field descriptors to parent node */ | ||
177 | |||
178 | status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_BUFFER_FIELD); | ||
179 | if (ACPI_FAILURE (status)) { | ||
180 | goto cleanup; | ||
181 | } | ||
182 | |||
183 | |||
184 | cleanup: | ||
185 | |||
186 | /* Remove local reference to the object */ | ||
187 | |||
188 | acpi_ut_remove_reference (obj_desc); | ||
189 | return_ACPI_STATUS (status); | ||
190 | } | ||
191 | |||
192 | |||
193 | /******************************************************************************* | ||
194 | * | ||
195 | * FUNCTION: acpi_ds_get_field_names | ||
196 | * | ||
197 | * PARAMETERS: Info - create_field info structure | ||
198 | * ` walk_state - Current method state | ||
199 | * Arg - First parser arg for the field name list | ||
200 | * | ||
201 | * RETURN: Status | ||
202 | * | ||
203 | * DESCRIPTION: Process all named fields in a field declaration. Names are | ||
204 | * entered into the namespace. | ||
205 | * | ||
206 | ******************************************************************************/ | ||
207 | |||
208 | acpi_status | ||
209 | acpi_ds_get_field_names ( | ||
210 | struct acpi_create_field_info *info, | ||
211 | struct acpi_walk_state *walk_state, | ||
212 | union acpi_parse_object *arg) | ||
213 | { | ||
214 | acpi_status status; | ||
215 | acpi_integer position; | ||
216 | |||
217 | |||
218 | ACPI_FUNCTION_TRACE_PTR ("ds_get_field_names", info); | ||
219 | |||
220 | |||
221 | /* First field starts at bit zero */ | ||
222 | |||
223 | info->field_bit_position = 0; | ||
224 | |||
225 | /* Process all elements in the field list (of parse nodes) */ | ||
226 | |||
227 | while (arg) { | ||
228 | /* | ||
229 | * Three types of field elements are handled: | ||
230 | * 1) Offset - specifies a bit offset | ||
231 | * 2) access_as - changes the access mode | ||
232 | * 3) Name - Enters a new named field into the namespace | ||
233 | */ | ||
234 | switch (arg->common.aml_opcode) { | ||
235 | case AML_INT_RESERVEDFIELD_OP: | ||
236 | |||
237 | position = (acpi_integer) info->field_bit_position | ||
238 | + (acpi_integer) arg->common.value.size; | ||
239 | |||
240 | if (position > ACPI_UINT32_MAX) { | ||
241 | ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n")); | ||
242 | return_ACPI_STATUS (AE_SUPPORT); | ||
243 | } | ||
244 | |||
245 | info->field_bit_position = (u32) position; | ||
246 | break; | ||
247 | |||
248 | |||
249 | case AML_INT_ACCESSFIELD_OP: | ||
250 | |||
251 | /* | ||
252 | * Get a new access_type and access_attribute -- to be used for all | ||
253 | * field units that follow, until field end or another access_as keyword. | ||
254 | * | ||
255 | * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits | ||
256 | */ | ||
257 | info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | | ||
258 | ((u8) ((u32) arg->common.value.integer >> 8))); | ||
259 | |||
260 | info->attribute = (u8) (arg->common.value.integer); | ||
261 | break; | ||
262 | |||
263 | |||
264 | case AML_INT_NAMEDFIELD_OP: | ||
265 | |||
266 | /* Lookup the name */ | ||
267 | |||
268 | status = acpi_ns_lookup (walk_state->scope_info, | ||
269 | (char *) &arg->named.name, | ||
270 | info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, | ||
271 | walk_state, &info->field_node); | ||
272 | if (ACPI_FAILURE (status)) { | ||
273 | ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); | ||
274 | if (status != AE_ALREADY_EXISTS) { | ||
275 | return_ACPI_STATUS (status); | ||
276 | } | ||
277 | |||
278 | /* Already exists, ignore error */ | ||
279 | } | ||
280 | else { | ||
281 | arg->common.node = info->field_node; | ||
282 | info->field_bit_length = arg->common.value.size; | ||
283 | |||
284 | /* Create and initialize an object for the new Field Node */ | ||
285 | |||
286 | status = acpi_ex_prep_field_value (info); | ||
287 | if (ACPI_FAILURE (status)) { | ||
288 | return_ACPI_STATUS (status); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* Keep track of bit position for the next field */ | ||
293 | |||
294 | position = (acpi_integer) info->field_bit_position | ||
295 | + (acpi_integer) arg->common.value.size; | ||
296 | |||
297 | if (position > ACPI_UINT32_MAX) { | ||
298 | ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", | ||
299 | (char *) &info->field_node->name)); | ||
300 | return_ACPI_STATUS (AE_SUPPORT); | ||
301 | } | ||
302 | |||
303 | info->field_bit_position += info->field_bit_length; | ||
304 | break; | ||
305 | |||
306 | |||
307 | default: | ||
308 | |||
309 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n", | ||
310 | arg->common.aml_opcode)); | ||
311 | return_ACPI_STATUS (AE_AML_BAD_OPCODE); | ||
312 | } | ||
313 | |||
314 | arg = arg->common.next; | ||
315 | } | ||
316 | |||
317 | return_ACPI_STATUS (AE_OK); | ||
318 | } | ||
319 | |||
320 | |||
321 | /******************************************************************************* | ||
322 | * | ||
323 | * FUNCTION: acpi_ds_create_field | ||
324 | * | ||
325 | * PARAMETERS: Op - Op containing the Field definition and args | ||
326 | * region_node - Object for the containing Operation Region | ||
327 | * ` walk_state - Current method state | ||
328 | * | ||
329 | * RETURN: Status | ||
330 | * | ||
331 | * DESCRIPTION: Create a new field in the specified operation region | ||
332 | * | ||
333 | ******************************************************************************/ | ||
334 | |||
335 | acpi_status | ||
336 | acpi_ds_create_field ( | ||
337 | union acpi_parse_object *op, | ||
338 | struct acpi_namespace_node *region_node, | ||
339 | struct acpi_walk_state *walk_state) | ||
340 | { | ||
341 | acpi_status status; | ||
342 | union acpi_parse_object *arg; | ||
343 | struct acpi_create_field_info info; | ||
344 | |||
345 | |||
346 | ACPI_FUNCTION_TRACE_PTR ("ds_create_field", op); | ||
347 | |||
348 | |||
349 | /* First arg is the name of the parent op_region (must already exist) */ | ||
350 | |||
351 | arg = op->common.value.arg; | ||
352 | if (!region_node) { | ||
353 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, | ||
354 | ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, | ||
355 | ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); | ||
356 | if (ACPI_FAILURE (status)) { | ||
357 | ACPI_REPORT_NSERROR (arg->common.value.name, status); | ||
358 | return_ACPI_STATUS (status); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* Second arg is the field flags */ | ||
363 | |||
364 | arg = arg->common.next; | ||
365 | info.field_flags = (u8) arg->common.value.integer; | ||
366 | info.attribute = 0; | ||
367 | |||
368 | /* Each remaining arg is a Named Field */ | ||
369 | |||
370 | info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD; | ||
371 | info.region_node = region_node; | ||
372 | |||
373 | status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); | ||
374 | |||
375 | return_ACPI_STATUS (status); | ||
376 | } | ||
377 | |||
378 | |||
379 | /******************************************************************************* | ||
380 | * | ||
381 | * FUNCTION: acpi_ds_init_field_objects | ||
382 | * | ||
383 | * PARAMETERS: Op - Op containing the Field definition and args | ||
384 | * ` walk_state - Current method state | ||
385 | * | ||
386 | * RETURN: Status | ||
387 | * | ||
388 | * DESCRIPTION: For each "Field Unit" name in the argument list that is | ||
389 | * part of the field declaration, enter the name into the | ||
390 | * namespace. | ||
391 | * | ||
392 | ******************************************************************************/ | ||
393 | |||
394 | acpi_status | ||
395 | acpi_ds_init_field_objects ( | ||
396 | union acpi_parse_object *op, | ||
397 | struct acpi_walk_state *walk_state) | ||
398 | { | ||
399 | acpi_status status; | ||
400 | union acpi_parse_object *arg = NULL; | ||
401 | struct acpi_namespace_node *node; | ||
402 | u8 type = 0; | ||
403 | |||
404 | |||
405 | ACPI_FUNCTION_TRACE_PTR ("ds_init_field_objects", op); | ||
406 | |||
407 | |||
408 | switch (walk_state->opcode) { | ||
409 | case AML_FIELD_OP: | ||
410 | arg = acpi_ps_get_arg (op, 2); | ||
411 | type = ACPI_TYPE_LOCAL_REGION_FIELD; | ||
412 | break; | ||
413 | |||
414 | case AML_BANK_FIELD_OP: | ||
415 | arg = acpi_ps_get_arg (op, 4); | ||
416 | type = ACPI_TYPE_LOCAL_BANK_FIELD; | ||
417 | break; | ||
418 | |||
419 | case AML_INDEX_FIELD_OP: | ||
420 | arg = acpi_ps_get_arg (op, 3); | ||
421 | type = ACPI_TYPE_LOCAL_INDEX_FIELD; | ||
422 | break; | ||
423 | |||
424 | default: | ||
425 | return_ACPI_STATUS (AE_BAD_PARAMETER); | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * Walk the list of entries in the field_list | ||
430 | */ | ||
431 | while (arg) { | ||
432 | /* Ignore OFFSET and ACCESSAS terms here */ | ||
433 | |||
434 | if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { | ||
435 | status = acpi_ns_lookup (walk_state->scope_info, | ||
436 | (char *) &arg->named.name, | ||
437 | type, ACPI_IMODE_LOAD_PASS1, | ||
438 | ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, | ||
439 | walk_state, &node); | ||
440 | if (ACPI_FAILURE (status)) { | ||
441 | ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); | ||
442 | if (status != AE_ALREADY_EXISTS) { | ||
443 | return_ACPI_STATUS (status); | ||
444 | } | ||
445 | |||
446 | /* Name already exists, just ignore this error */ | ||
447 | |||
448 | status = AE_OK; | ||
449 | } | ||
450 | |||
451 | arg->common.node = node; | ||
452 | } | ||
453 | |||
454 | /* Move to next field in the list */ | ||
455 | |||
456 | arg = arg->common.next; | ||
457 | } | ||
458 | |||
459 | return_ACPI_STATUS (AE_OK); | ||
460 | } | ||
461 | |||
462 | |||
463 | /******************************************************************************* | ||
464 | * | ||
465 | * FUNCTION: acpi_ds_create_bank_field | ||
466 | * | ||
467 | * PARAMETERS: Op - Op containing the Field definition and args | ||
468 | * region_node - Object for the containing Operation Region | ||
469 | * ` walk_state - Current method state | ||
470 | * | ||
471 | * RETURN: Status | ||
472 | * | ||
473 | * DESCRIPTION: Create a new bank field in the specified operation region | ||
474 | * | ||
475 | ******************************************************************************/ | ||
476 | |||
477 | acpi_status | ||
478 | acpi_ds_create_bank_field ( | ||
479 | union acpi_parse_object *op, | ||
480 | struct acpi_namespace_node *region_node, | ||
481 | struct acpi_walk_state *walk_state) | ||
482 | { | ||
483 | acpi_status status; | ||
484 | union acpi_parse_object *arg; | ||
485 | struct acpi_create_field_info info; | ||
486 | |||
487 | |||
488 | ACPI_FUNCTION_TRACE_PTR ("ds_create_bank_field", op); | ||
489 | |||
490 | |||
491 | /* First arg is the name of the parent op_region (must already exist) */ | ||
492 | |||
493 | arg = op->common.value.arg; | ||
494 | if (!region_node) { | ||
495 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, | ||
496 | ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, | ||
497 | ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); | ||
498 | if (ACPI_FAILURE (status)) { | ||
499 | ACPI_REPORT_NSERROR (arg->common.value.name, status); | ||
500 | return_ACPI_STATUS (status); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | /* Second arg is the Bank Register (Field) (must already exist) */ | ||
505 | |||
506 | arg = arg->common.next; | ||
507 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, | ||
508 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | ||
509 | ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); | ||
510 | if (ACPI_FAILURE (status)) { | ||
511 | ACPI_REPORT_NSERROR (arg->common.value.string, status); | ||
512 | return_ACPI_STATUS (status); | ||
513 | } | ||
514 | |||
515 | /* Third arg is the bank_value */ | ||
516 | |||
517 | arg = arg->common.next; | ||
518 | info.bank_value = (u32) arg->common.value.integer; | ||
519 | |||
520 | /* Fourth arg is the field flags */ | ||
521 | |||
522 | arg = arg->common.next; | ||
523 | info.field_flags = (u8) arg->common.value.integer; | ||
524 | |||
525 | /* Each remaining arg is a Named Field */ | ||
526 | |||
527 | info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; | ||
528 | info.region_node = region_node; | ||
529 | |||
530 | status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); | ||
531 | |||
532 | return_ACPI_STATUS (status); | ||
533 | } | ||
534 | |||
535 | |||
536 | /******************************************************************************* | ||
537 | * | ||
538 | * FUNCTION: acpi_ds_create_index_field | ||
539 | * | ||
540 | * PARAMETERS: Op - Op containing the Field definition and args | ||
541 | * region_node - Object for the containing Operation Region | ||
542 | * ` walk_state - Current method state | ||
543 | * | ||
544 | * RETURN: Status | ||
545 | * | ||
546 | * DESCRIPTION: Create a new index field in the specified operation region | ||
547 | * | ||
548 | ******************************************************************************/ | ||
549 | |||
550 | acpi_status | ||
551 | acpi_ds_create_index_field ( | ||
552 | union acpi_parse_object *op, | ||
553 | struct acpi_namespace_node *region_node, | ||
554 | struct acpi_walk_state *walk_state) | ||
555 | { | ||
556 | acpi_status status; | ||
557 | union acpi_parse_object *arg; | ||
558 | struct acpi_create_field_info info; | ||
559 | |||
560 | |||
561 | ACPI_FUNCTION_TRACE_PTR ("ds_create_index_field", op); | ||
562 | |||
563 | |||
564 | /* First arg is the name of the Index register (must already exist) */ | ||
565 | |||
566 | arg = op->common.value.arg; | ||
567 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, | ||
568 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | ||
569 | ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); | ||
570 | if (ACPI_FAILURE (status)) { | ||
571 | ACPI_REPORT_NSERROR (arg->common.value.string, status); | ||
572 | return_ACPI_STATUS (status); | ||
573 | } | ||
574 | |||
575 | /* Second arg is the data register (must already exist) */ | ||
576 | |||
577 | arg = arg->common.next; | ||
578 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, | ||
579 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | ||
580 | ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node); | ||
581 | if (ACPI_FAILURE (status)) { | ||
582 | ACPI_REPORT_NSERROR (arg->common.value.string, status); | ||
583 | return_ACPI_STATUS (status); | ||
584 | } | ||
585 | |||
586 | /* Next arg is the field flags */ | ||
587 | |||
588 | arg = arg->common.next; | ||
589 | info.field_flags = (u8) arg->common.value.integer; | ||
590 | |||
591 | /* Each remaining arg is a Named Field */ | ||
592 | |||
593 | info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD; | ||
594 | info.region_node = region_node; | ||
595 | |||
596 | status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); | ||
597 | |||
598 | return_ACPI_STATUS (status); | ||
599 | } | ||
600 | |||
601 | |||
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c new file mode 100644 index 000000000000..b4d264dbbf67 --- /dev/null +++ b/drivers/acpi/dispatcher/dsinit.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dsinit - Object initialization namespace walk | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acdispat.h> | ||
47 | #include <acpi/acnamesp.h> | ||
48 | |||
49 | #define _COMPONENT ACPI_DISPATCHER | ||
50 | ACPI_MODULE_NAME ("dsinit") | ||
51 | |||
52 | |||
53 | /******************************************************************************* | ||
54 | * | ||
55 | * FUNCTION: acpi_ds_init_one_object | ||
56 | * | ||
57 | * PARAMETERS: obj_handle - Node | ||
58 | * Level - Current nesting level | ||
59 | * Context - Points to a init info struct | ||
60 | * return_value - Not used | ||
61 | * | ||
62 | * RETURN: Status | ||
63 | * | ||
64 | * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object | ||
65 | * within the namespace. | ||
66 | * | ||
67 | * Currently, the only objects that require initialization are: | ||
68 | * 1) Methods | ||
69 | * 2) Operation Regions | ||
70 | * | ||
71 | ******************************************************************************/ | ||
72 | |||
73 | acpi_status | ||
74 | acpi_ds_init_one_object ( | ||
75 | acpi_handle obj_handle, | ||
76 | u32 level, | ||
77 | void *context, | ||
78 | void **return_value) | ||
79 | { | ||
80 | acpi_object_type type; | ||
81 | acpi_status status; | ||
82 | struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; | ||
83 | |||
84 | |||
85 | ACPI_FUNCTION_NAME ("ds_init_one_object"); | ||
86 | |||
87 | |||
88 | /* | ||
89 | * We are only interested in objects owned by the table that | ||
90 | * was just loaded | ||
91 | */ | ||
92 | if (((struct acpi_namespace_node *) obj_handle)->owner_id != | ||
93 | info->table_desc->table_id) { | ||
94 | return (AE_OK); | ||
95 | } | ||
96 | |||
97 | info->object_count++; | ||
98 | |||
99 | /* And even then, we are only interested in a few object types */ | ||
100 | |||
101 | type = acpi_ns_get_type (obj_handle); | ||
102 | |||
103 | switch (type) { | ||
104 | case ACPI_TYPE_REGION: | ||
105 | |||
106 | status = acpi_ds_initialize_region (obj_handle); | ||
107 | if (ACPI_FAILURE (status)) { | ||
108 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", | ||
109 | obj_handle, acpi_ut_get_node_name (obj_handle), | ||
110 | acpi_format_exception (status))); | ||
111 | } | ||
112 | |||
113 | info->op_region_count++; | ||
114 | break; | ||
115 | |||
116 | |||
117 | case ACPI_TYPE_METHOD: | ||
118 | |||
119 | info->method_count++; | ||
120 | |||
121 | /* Print a dot for each method unless we are going to print the entire pathname */ | ||
122 | |||
123 | if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { | ||
124 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Set the execution data width (32 or 64) based upon the | ||
129 | * revision number of the parent ACPI table. | ||
130 | * TBD: This is really for possible future support of integer width | ||
131 | * on a per-table basis. Currently, we just use a global for the width. | ||
132 | */ | ||
133 | if (info->table_desc->pointer->revision == 1) { | ||
134 | ((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Always parse methods to detect errors, we will delete | ||
139 | * the parse tree below | ||
140 | */ | ||
141 | status = acpi_ds_parse_method (obj_handle); | ||
142 | if (ACPI_FAILURE (status)) { | ||
143 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", | ||
144 | obj_handle, acpi_ut_get_node_name (obj_handle), | ||
145 | acpi_format_exception (status))); | ||
146 | |||
147 | /* This parse failed, but we will continue parsing more methods */ | ||
148 | |||
149 | break; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Delete the parse tree. We simply re-parse the method | ||
154 | * for every execution since there isn't much overhead | ||
155 | */ | ||
156 | acpi_ns_delete_namespace_subtree (obj_handle); | ||
157 | acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); | ||
158 | break; | ||
159 | |||
160 | |||
161 | case ACPI_TYPE_DEVICE: | ||
162 | |||
163 | info->device_count++; | ||
164 | break; | ||
165 | |||
166 | |||
167 | default: | ||
168 | break; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * We ignore errors from above, and always return OK, since | ||
173 | * we don't want to abort the walk on a single error. | ||
174 | */ | ||
175 | return (AE_OK); | ||
176 | } | ||
177 | |||
178 | |||
179 | /******************************************************************************* | ||
180 | * | ||
181 | * FUNCTION: acpi_ds_initialize_objects | ||
182 | * | ||
183 | * PARAMETERS: table_desc - Descriptor for parent ACPI table | ||
184 | * start_node - Root of subtree to be initialized. | ||
185 | * | ||
186 | * RETURN: Status | ||
187 | * | ||
188 | * DESCRIPTION: Walk the namespace starting at "start_node" and perform any | ||
189 | * necessary initialization on the objects found therein | ||
190 | * | ||
191 | ******************************************************************************/ | ||
192 | |||
193 | acpi_status | ||
194 | acpi_ds_initialize_objects ( | ||
195 | struct acpi_table_desc *table_desc, | ||
196 | struct acpi_namespace_node *start_node) | ||
197 | { | ||
198 | acpi_status status; | ||
199 | struct acpi_init_walk_info info; | ||
200 | |||
201 | |||
202 | ACPI_FUNCTION_TRACE ("ds_initialize_objects"); | ||
203 | |||
204 | |||
205 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
206 | "**** Starting initialization of namespace objects ****\n")); | ||
207 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Parsing all Control Methods:")); | ||
208 | |||
209 | info.method_count = 0; | ||
210 | info.op_region_count = 0; | ||
211 | info.object_count = 0; | ||
212 | info.device_count = 0; | ||
213 | info.table_desc = table_desc; | ||
214 | |||
215 | /* Walk entire namespace from the supplied root */ | ||
216 | |||
217 | status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, | ||
218 | acpi_ds_init_one_object, &info, NULL); | ||
219 | if (ACPI_FAILURE (status)) { | ||
220 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed, %s\n", | ||
221 | acpi_format_exception (status))); | ||
222 | } | ||
223 | |||
224 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, | ||
225 | "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n", | ||
226 | table_desc->pointer->signature, table_desc->table_id, info.object_count, | ||
227 | info.device_count, info.method_count, info.op_region_count)); | ||
228 | |||
229 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
230 | "%hd Methods, %hd Regions\n", info.method_count, info.op_region_count)); | ||
231 | |||
232 | return_ACPI_STATUS (AE_OK); | ||
233 | } | ||
234 | |||
235 | |||
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c new file mode 100644 index 000000000000..9f0456cb9bb5 --- /dev/null +++ b/drivers/acpi/dispatcher/dsmethod.c | |||
@@ -0,0 +1,597 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dsmethod - Parser/Interpreter interface - control method parsing | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acparser.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | #include <acpi/acnamesp.h> | ||
51 | |||
52 | |||
53 | #define _COMPONENT ACPI_DISPATCHER | ||
54 | ACPI_MODULE_NAME ("dsmethod") | ||
55 | |||
56 | |||
57 | /******************************************************************************* | ||
58 | * | ||
59 | * FUNCTION: acpi_ds_parse_method | ||
60 | * | ||
61 | * PARAMETERS: obj_handle - Method node | ||
62 | * | ||
63 | * RETURN: Status | ||
64 | * | ||
65 | * DESCRIPTION: Call the parser and parse the AML that is associated with the | ||
66 | * method. | ||
67 | * | ||
68 | * MUTEX: Assumes parser is locked | ||
69 | * | ||
70 | ******************************************************************************/ | ||
71 | |||
72 | acpi_status | ||
73 | acpi_ds_parse_method ( | ||
74 | acpi_handle obj_handle) | ||
75 | { | ||
76 | acpi_status status; | ||
77 | union acpi_operand_object *obj_desc; | ||
78 | union acpi_parse_object *op; | ||
79 | struct acpi_namespace_node *node; | ||
80 | acpi_owner_id owner_id; | ||
81 | struct acpi_walk_state *walk_state; | ||
82 | |||
83 | |||
84 | ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle); | ||
85 | |||
86 | |||
87 | /* Parameter Validation */ | ||
88 | |||
89 | if (!obj_handle) { | ||
90 | return_ACPI_STATUS (AE_NULL_ENTRY); | ||
91 | } | ||
92 | |||
93 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n", | ||
94 | acpi_ut_get_node_name (obj_handle), obj_handle)); | ||
95 | |||
96 | /* Extract the method object from the method Node */ | ||
97 | |||
98 | node = (struct acpi_namespace_node *) obj_handle; | ||
99 | obj_desc = acpi_ns_get_attached_object (node); | ||
100 | if (!obj_desc) { | ||
101 | return_ACPI_STATUS (AE_NULL_OBJECT); | ||
102 | } | ||
103 | |||
104 | /* Create a mutex for the method if there is a concurrency limit */ | ||
105 | |||
106 | if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && | ||
107 | (!obj_desc->method.semaphore)) { | ||
108 | status = acpi_os_create_semaphore (obj_desc->method.concurrency, | ||
109 | obj_desc->method.concurrency, | ||
110 | &obj_desc->method.semaphore); | ||
111 | if (ACPI_FAILURE (status)) { | ||
112 | return_ACPI_STATUS (status); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Allocate a new parser op to be the root of the parsed | ||
118 | * method tree | ||
119 | */ | ||
120 | op = acpi_ps_alloc_op (AML_METHOD_OP); | ||
121 | if (!op) { | ||
122 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
123 | } | ||
124 | |||
125 | /* Init new op with the method name and pointer back to the Node */ | ||
126 | |||
127 | acpi_ps_set_name (op, node->name.integer); | ||
128 | op->common.node = node; | ||
129 | |||
130 | /* | ||
131 | * Get a new owner_id for objects created by this method. Namespace | ||
132 | * objects (such as Operation Regions) can be created during the | ||
133 | * first pass parse. | ||
134 | */ | ||
135 | owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); | ||
136 | obj_desc->method.owning_id = owner_id; | ||
137 | |||
138 | /* Create and initialize a new walk state */ | ||
139 | |||
140 | walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL); | ||
141 | if (!walk_state) { | ||
142 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
143 | } | ||
144 | |||
145 | status = acpi_ds_init_aml_walk (walk_state, op, node, | ||
146 | obj_desc->method.aml_start, | ||
147 | obj_desc->method.aml_length, NULL, 1); | ||
148 | if (ACPI_FAILURE (status)) { | ||
149 | acpi_ds_delete_walk_state (walk_state); | ||
150 | return_ACPI_STATUS (status); | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Parse the method, first pass | ||
155 | * | ||
156 | * The first pass load is where newly declared named objects are | ||
157 | * added into the namespace. Actual evaluation of | ||
158 | * the named objects (what would be called a "second | ||
159 | * pass") happens during the actual execution of the | ||
160 | * method so that operands to the named objects can | ||
161 | * take on dynamic run-time values. | ||
162 | */ | ||
163 | status = acpi_ps_parse_aml (walk_state); | ||
164 | if (ACPI_FAILURE (status)) { | ||
165 | return_ACPI_STATUS (status); | ||
166 | } | ||
167 | |||
168 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, | ||
169 | "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", | ||
170 | acpi_ut_get_node_name (obj_handle), obj_handle, op)); | ||
171 | |||
172 | acpi_ps_delete_parse_tree (op); | ||
173 | return_ACPI_STATUS (status); | ||
174 | } | ||
175 | |||
176 | |||
177 | /******************************************************************************* | ||
178 | * | ||
179 | * FUNCTION: acpi_ds_begin_method_execution | ||
180 | * | ||
181 | * PARAMETERS: method_node - Node of the method | ||
182 | * obj_desc - The method object | ||
183 | * calling_method_node - Caller of this method (if non-null) | ||
184 | * | ||
185 | * RETURN: Status | ||
186 | * | ||
187 | * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, | ||
188 | * increments the thread count, and waits at the method semaphore | ||
189 | * for clearance to execute. | ||
190 | * | ||
191 | ******************************************************************************/ | ||
192 | |||
193 | acpi_status | ||
194 | acpi_ds_begin_method_execution ( | ||
195 | struct acpi_namespace_node *method_node, | ||
196 | union acpi_operand_object *obj_desc, | ||
197 | struct acpi_namespace_node *calling_method_node) | ||
198 | { | ||
199 | acpi_status status = AE_OK; | ||
200 | |||
201 | |||
202 | ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node); | ||
203 | |||
204 | |||
205 | if (!method_node) { | ||
206 | return_ACPI_STATUS (AE_NULL_ENTRY); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * If there is a concurrency limit on this method, we need to | ||
211 | * obtain a unit from the method semaphore. | ||
212 | */ | ||
213 | if (obj_desc->method.semaphore) { | ||
214 | /* | ||
215 | * Allow recursive method calls, up to the reentrancy/concurrency | ||
216 | * limit imposed by the SERIALIZED rule and the sync_level method | ||
217 | * parameter. | ||
218 | * | ||
219 | * The point of this code is to avoid permanently blocking a | ||
220 | * thread that is making recursive method calls. | ||
221 | */ | ||
222 | if (method_node == calling_method_node) { | ||
223 | if (obj_desc->method.thread_count >= obj_desc->method.concurrency) { | ||
224 | return_ACPI_STATUS (AE_AML_METHOD_LIMIT); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * Get a unit from the method semaphore. This releases the | ||
230 | * interpreter if we block | ||
231 | */ | ||
232 | status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore, | ||
233 | ACPI_WAIT_FOREVER); | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Increment the method parse tree thread count since it has been | ||
238 | * reentered one more time (even if it is the same thread) | ||
239 | */ | ||
240 | obj_desc->method.thread_count++; | ||
241 | return_ACPI_STATUS (status); | ||
242 | } | ||
243 | |||
244 | |||
245 | /******************************************************************************* | ||
246 | * | ||
247 | * FUNCTION: acpi_ds_call_control_method | ||
248 | * | ||
249 | * PARAMETERS: Thread - Info for this thread | ||
250 | * this_walk_state - Current walk state | ||
251 | * Op - Current Op to be walked | ||
252 | * | ||
253 | * RETURN: Status | ||
254 | * | ||
255 | * DESCRIPTION: Transfer execution to a called control method | ||
256 | * | ||
257 | ******************************************************************************/ | ||
258 | |||
259 | acpi_status | ||
260 | acpi_ds_call_control_method ( | ||
261 | struct acpi_thread_state *thread, | ||
262 | struct acpi_walk_state *this_walk_state, | ||
263 | union acpi_parse_object *op) | ||
264 | { | ||
265 | acpi_status status; | ||
266 | struct acpi_namespace_node *method_node; | ||
267 | struct acpi_walk_state *next_walk_state; | ||
268 | union acpi_operand_object *obj_desc; | ||
269 | struct acpi_parameter_info info; | ||
270 | u32 i; | ||
271 | |||
272 | |||
273 | ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state); | ||
274 | |||
275 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", | ||
276 | this_walk_state->prev_op, this_walk_state)); | ||
277 | |||
278 | /* | ||
279 | * Get the namespace entry for the control method we are about to call | ||
280 | */ | ||
281 | method_node = this_walk_state->method_call_node; | ||
282 | if (!method_node) { | ||
283 | return_ACPI_STATUS (AE_NULL_ENTRY); | ||
284 | } | ||
285 | |||
286 | obj_desc = acpi_ns_get_attached_object (method_node); | ||
287 | if (!obj_desc) { | ||
288 | return_ACPI_STATUS (AE_NULL_OBJECT); | ||
289 | } | ||
290 | |||
291 | obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); | ||
292 | |||
293 | /* Init for new method, wait on concurrency semaphore */ | ||
294 | |||
295 | status = acpi_ds_begin_method_execution (method_node, obj_desc, | ||
296 | this_walk_state->method_node); | ||
297 | if (ACPI_FAILURE (status)) { | ||
298 | return_ACPI_STATUS (status); | ||
299 | } | ||
300 | |||
301 | if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { | ||
302 | /* 1) Parse: Create a new walk state for the preempting walk */ | ||
303 | |||
304 | next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, | ||
305 | op, obj_desc, NULL); | ||
306 | if (!next_walk_state) { | ||
307 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
308 | } | ||
309 | |||
310 | /* Create and init a Root Node */ | ||
311 | |||
312 | op = acpi_ps_create_scope_op (); | ||
313 | if (!op) { | ||
314 | status = AE_NO_MEMORY; | ||
315 | goto cleanup; | ||
316 | } | ||
317 | |||
318 | status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, | ||
319 | obj_desc->method.aml_start, obj_desc->method.aml_length, | ||
320 | NULL, 1); | ||
321 | if (ACPI_FAILURE (status)) { | ||
322 | acpi_ds_delete_walk_state (next_walk_state); | ||
323 | goto cleanup; | ||
324 | } | ||
325 | |||
326 | /* Begin AML parse */ | ||
327 | |||
328 | status = acpi_ps_parse_aml (next_walk_state); | ||
329 | acpi_ps_delete_parse_tree (op); | ||
330 | } | ||
331 | |||
332 | /* 2) Execute: Create a new state for the preempting walk */ | ||
333 | |||
334 | next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, | ||
335 | NULL, obj_desc, thread); | ||
336 | if (!next_walk_state) { | ||
337 | status = AE_NO_MEMORY; | ||
338 | goto cleanup; | ||
339 | } | ||
340 | /* | ||
341 | * The resolved arguments were put on the previous walk state's operand | ||
342 | * stack. Operands on the previous walk state stack always | ||
343 | * start at index 0. | ||
344 | * Null terminate the list of arguments | ||
345 | */ | ||
346 | this_walk_state->operands [this_walk_state->num_operands] = NULL; | ||
347 | |||
348 | info.parameters = &this_walk_state->operands[0]; | ||
349 | info.parameter_type = ACPI_PARAM_ARGS; | ||
350 | |||
351 | status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node, | ||
352 | obj_desc->method.aml_start, obj_desc->method.aml_length, | ||
353 | &info, 3); | ||
354 | if (ACPI_FAILURE (status)) { | ||
355 | goto cleanup; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Delete the operands on the previous walkstate operand stack | ||
360 | * (they were copied to new objects) | ||
361 | */ | ||
362 | for (i = 0; i < obj_desc->method.param_count; i++) { | ||
363 | acpi_ut_remove_reference (this_walk_state->operands [i]); | ||
364 | this_walk_state->operands [i] = NULL; | ||
365 | } | ||
366 | |||
367 | /* Clear the operand stack */ | ||
368 | |||
369 | this_walk_state->num_operands = 0; | ||
370 | |||
371 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
372 | "Starting nested execution, newstate=%p\n", next_walk_state)); | ||
373 | |||
374 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | ||
375 | status = obj_desc->method.implementation (next_walk_state); | ||
376 | return_ACPI_STATUS (status); | ||
377 | } | ||
378 | |||
379 | return_ACPI_STATUS (AE_OK); | ||
380 | |||
381 | |||
382 | /* On error, we must delete the new walk state */ | ||
383 | |||
384 | cleanup: | ||
385 | if (next_walk_state && (next_walk_state->method_desc)) { | ||
386 | /* Decrement the thread count on the method parse tree */ | ||
387 | |||
388 | next_walk_state->method_desc->method.thread_count--; | ||
389 | } | ||
390 | (void) acpi_ds_terminate_control_method (next_walk_state); | ||
391 | acpi_ds_delete_walk_state (next_walk_state); | ||
392 | return_ACPI_STATUS (status); | ||
393 | } | ||
394 | |||
395 | |||
396 | /******************************************************************************* | ||
397 | * | ||
398 | * FUNCTION: acpi_ds_restart_control_method | ||
399 | * | ||
400 | * PARAMETERS: walk_state - State for preempted method (caller) | ||
401 | * return_desc - Return value from the called method | ||
402 | * | ||
403 | * RETURN: Status | ||
404 | * | ||
405 | * DESCRIPTION: Restart a method that was preempted by another (nested) method | ||
406 | * invocation. Handle the return value (if any) from the callee. | ||
407 | * | ||
408 | ******************************************************************************/ | ||
409 | |||
410 | acpi_status | ||
411 | acpi_ds_restart_control_method ( | ||
412 | struct acpi_walk_state *walk_state, | ||
413 | union acpi_operand_object *return_desc) | ||
414 | { | ||
415 | acpi_status status; | ||
416 | |||
417 | |||
418 | ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state); | ||
419 | |||
420 | |||
421 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
422 | "****Restart [%4.4s] Op %p return_value_from_callee %p\n", | ||
423 | (char *) &walk_state->method_node->name, walk_state->method_call_op, | ||
424 | return_desc)); | ||
425 | |||
426 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
427 | " return_from_this_method_used?=%X res_stack %p Walk %p\n", | ||
428 | walk_state->return_used, | ||
429 | walk_state->results, walk_state)); | ||
430 | |||
431 | /* Did the called method return a value? */ | ||
432 | |||
433 | if (return_desc) { | ||
434 | /* Are we actually going to use the return value? */ | ||
435 | |||
436 | if (walk_state->return_used) { | ||
437 | /* Save the return value from the previous method */ | ||
438 | |||
439 | status = acpi_ds_result_push (return_desc, walk_state); | ||
440 | if (ACPI_FAILURE (status)) { | ||
441 | acpi_ut_remove_reference (return_desc); | ||
442 | return_ACPI_STATUS (status); | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * Save as THIS method's return value in case it is returned | ||
447 | * immediately to yet another method | ||
448 | */ | ||
449 | walk_state->return_desc = return_desc; | ||
450 | } | ||
451 | |||
452 | /* | ||
453 | * The following code is the | ||
454 | * optional support for a so-called "implicit return". Some AML code | ||
455 | * assumes that the last value of the method is "implicitly" returned | ||
456 | * to the caller. Just save the last result as the return value. | ||
457 | * NOTE: this is optional because the ASL language does not actually | ||
458 | * support this behavior. | ||
459 | */ | ||
460 | else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) { | ||
461 | /* | ||
462 | * Delete the return value if it will not be used by the | ||
463 | * calling method | ||
464 | */ | ||
465 | acpi_ut_remove_reference (return_desc); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | return_ACPI_STATUS (AE_OK); | ||
470 | } | ||
471 | |||
472 | |||
473 | /******************************************************************************* | ||
474 | * | ||
475 | * FUNCTION: acpi_ds_terminate_control_method | ||
476 | * | ||
477 | * PARAMETERS: walk_state - State of the method | ||
478 | * | ||
479 | * RETURN: Status | ||
480 | * | ||
481 | * DESCRIPTION: Terminate a control method. Delete everything that the method | ||
482 | * created, delete all locals and arguments, and delete the parse | ||
483 | * tree if requested. | ||
484 | * | ||
485 | ******************************************************************************/ | ||
486 | |||
487 | acpi_status | ||
488 | acpi_ds_terminate_control_method ( | ||
489 | struct acpi_walk_state *walk_state) | ||
490 | { | ||
491 | union acpi_operand_object *obj_desc; | ||
492 | struct acpi_namespace_node *method_node; | ||
493 | acpi_status status; | ||
494 | |||
495 | |||
496 | ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state); | ||
497 | |||
498 | |||
499 | if (!walk_state) { | ||
500 | return (AE_BAD_PARAMETER); | ||
501 | } | ||
502 | |||
503 | /* The current method object was saved in the walk state */ | ||
504 | |||
505 | obj_desc = walk_state->method_desc; | ||
506 | if (!obj_desc) { | ||
507 | return_ACPI_STATUS (AE_OK); | ||
508 | } | ||
509 | |||
510 | /* Delete all arguments and locals */ | ||
511 | |||
512 | acpi_ds_method_data_delete_all (walk_state); | ||
513 | |||
514 | /* | ||
515 | * Lock the parser while we terminate this method. | ||
516 | * If this is the last thread executing the method, | ||
517 | * we have additional cleanup to perform | ||
518 | */ | ||
519 | status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER); | ||
520 | if (ACPI_FAILURE (status)) { | ||
521 | return_ACPI_STATUS (status); | ||
522 | } | ||
523 | |||
524 | /* Signal completion of the execution of this method if necessary */ | ||
525 | |||
526 | if (walk_state->method_desc->method.semaphore) { | ||
527 | status = acpi_os_signal_semaphore ( | ||
528 | walk_state->method_desc->method.semaphore, 1); | ||
529 | if (ACPI_FAILURE (status)) { | ||
530 | ACPI_REPORT_ERROR (("Could not signal method semaphore\n")); | ||
531 | status = AE_OK; | ||
532 | |||
533 | /* Ignore error and continue cleanup */ | ||
534 | } | ||
535 | } | ||
536 | |||
537 | if (walk_state->method_desc->method.thread_count) { | ||
538 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
539 | "*** Not deleting method namespace, there are still %d threads\n", | ||
540 | walk_state->method_desc->method.thread_count)); | ||
541 | } | ||
542 | |||
543 | if (!walk_state->method_desc->method.thread_count) { | ||
544 | /* | ||
545 | * Support to dynamically change a method from not_serialized to | ||
546 | * Serialized if it appears that the method is written foolishly and | ||
547 | * does not support multiple thread execution. The best example of this | ||
548 | * is if such a method creates namespace objects and blocks. A second | ||
549 | * thread will fail with an AE_ALREADY_EXISTS exception | ||
550 | * | ||
551 | * This code is here because we must wait until the last thread exits | ||
552 | * before creating the synchronization semaphore. | ||
553 | */ | ||
554 | if ((walk_state->method_desc->method.concurrency == 1) && | ||
555 | (!walk_state->method_desc->method.semaphore)) { | ||
556 | status = acpi_os_create_semaphore (1, | ||
557 | 1, | ||
558 | &walk_state->method_desc->method.semaphore); | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * There are no more threads executing this method. Perform | ||
563 | * additional cleanup. | ||
564 | * | ||
565 | * The method Node is stored in the walk state | ||
566 | */ | ||
567 | method_node = walk_state->method_node; | ||
568 | |||
569 | /* | ||
570 | * Delete any namespace entries created immediately underneath | ||
571 | * the method | ||
572 | */ | ||
573 | status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); | ||
574 | if (ACPI_FAILURE (status)) { | ||
575 | return_ACPI_STATUS (status); | ||
576 | } | ||
577 | |||
578 | if (method_node->child) { | ||
579 | acpi_ns_delete_namespace_subtree (method_node); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * Delete any namespace entries created anywhere else within | ||
584 | * the namespace | ||
585 | */ | ||
586 | acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id); | ||
587 | status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); | ||
588 | if (ACPI_FAILURE (status)) { | ||
589 | return_ACPI_STATUS (status); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | status = acpi_ut_release_mutex (ACPI_MTX_PARSER); | ||
594 | return_ACPI_STATUS (status); | ||
595 | } | ||
596 | |||
597 | |||
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c new file mode 100644 index 000000000000..f31d095f9833 --- /dev/null +++ b/drivers/acpi/dispatcher/dsmthdat.c | |||
@@ -0,0 +1,715 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Module Name: dsmthdat - control method arguments and local variables | ||
4 | * | ||
5 | ******************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acdispat.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acnamesp.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | |||
51 | |||
52 | #define _COMPONENT ACPI_DISPATCHER | ||
53 | ACPI_MODULE_NAME ("dsmthdat") | ||
54 | |||
55 | |||
56 | /******************************************************************************* | ||
57 | * | ||
58 | * FUNCTION: acpi_ds_method_data_init | ||
59 | * | ||
60 | * PARAMETERS: walk_state - Current walk state object | ||
61 | * | ||
62 | * RETURN: Status | ||
63 | * | ||
64 | * DESCRIPTION: Initialize the data structures that hold the method's arguments | ||
65 | * and locals. The data struct is an array of NTEs for each. | ||
66 | * This allows ref_of and de_ref_of to work properly for these | ||
67 | * special data types. | ||
68 | * | ||
69 | * NOTES: walk_state fields are initialized to zero by the | ||
70 | * ACPI_MEM_CALLOCATE(). | ||
71 | * | ||
72 | * A pseudo-Namespace Node is assigned to each argument and local | ||
73 | * so that ref_of() can return a pointer to the Node. | ||
74 | * | ||
75 | ******************************************************************************/ | ||
76 | |||
77 | void | ||
78 | acpi_ds_method_data_init ( | ||
79 | struct acpi_walk_state *walk_state) | ||
80 | { | ||
81 | u32 i; | ||
82 | |||
83 | |||
84 | ACPI_FUNCTION_TRACE ("ds_method_data_init"); | ||
85 | |||
86 | |||
87 | /* Init the method arguments */ | ||
88 | |||
89 | for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { | ||
90 | ACPI_MOVE_32_TO_32 (&walk_state->arguments[i].name, | ||
91 | NAMEOF_ARG_NTE); | ||
92 | walk_state->arguments[i].name.integer |= (i << 24); | ||
93 | walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; | ||
94 | walk_state->arguments[i].type = ACPI_TYPE_ANY; | ||
95 | walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; | ||
96 | } | ||
97 | |||
98 | /* Init the method locals */ | ||
99 | |||
100 | for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { | ||
101 | ACPI_MOVE_32_TO_32 (&walk_state->local_variables[i].name, | ||
102 | NAMEOF_LOCAL_NTE); | ||
103 | |||
104 | walk_state->local_variables[i].name.integer |= (i << 24); | ||
105 | walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED; | ||
106 | walk_state->local_variables[i].type = ACPI_TYPE_ANY; | ||
107 | walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; | ||
108 | } | ||
109 | |||
110 | return_VOID; | ||
111 | } | ||
112 | |||
113 | |||
114 | /******************************************************************************* | ||
115 | * | ||
116 | * FUNCTION: acpi_ds_method_data_delete_all | ||
117 | * | ||
118 | * PARAMETERS: walk_state - Current walk state object | ||
119 | * | ||
120 | * RETURN: None | ||
121 | * | ||
122 | * DESCRIPTION: Delete method locals and arguments. Arguments are only | ||
123 | * deleted if this method was called from another method. | ||
124 | * | ||
125 | ******************************************************************************/ | ||
126 | |||
127 | void | ||
128 | acpi_ds_method_data_delete_all ( | ||
129 | struct acpi_walk_state *walk_state) | ||
130 | { | ||
131 | u32 index; | ||
132 | |||
133 | |||
134 | ACPI_FUNCTION_TRACE ("ds_method_data_delete_all"); | ||
135 | |||
136 | |||
137 | /* Detach the locals */ | ||
138 | |||
139 | for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) { | ||
140 | if (walk_state->local_variables[index].object) { | ||
141 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n", | ||
142 | index, walk_state->local_variables[index].object)); | ||
143 | |||
144 | /* Detach object (if present) and remove a reference */ | ||
145 | |||
146 | acpi_ns_detach_object (&walk_state->local_variables[index]); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | /* Detach the arguments */ | ||
151 | |||
152 | for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) { | ||
153 | if (walk_state->arguments[index].object) { | ||
154 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n", | ||
155 | index, walk_state->arguments[index].object)); | ||
156 | |||
157 | /* Detach object (if present) and remove a reference */ | ||
158 | |||
159 | acpi_ns_detach_object (&walk_state->arguments[index]); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return_VOID; | ||
164 | } | ||
165 | |||
166 | |||
167 | /******************************************************************************* | ||
168 | * | ||
169 | * FUNCTION: acpi_ds_method_data_init_args | ||
170 | * | ||
171 | * PARAMETERS: *Params - Pointer to a parameter list for the method | ||
172 | * max_param_count - The arg count for this method | ||
173 | * walk_state - Current walk state object | ||
174 | * | ||
175 | * RETURN: Status | ||
176 | * | ||
177 | * DESCRIPTION: Initialize arguments for a method. The parameter list is a list | ||
178 | * of ACPI operand objects, either null terminated or whose length | ||
179 | * is defined by max_param_count. | ||
180 | * | ||
181 | ******************************************************************************/ | ||
182 | |||
183 | acpi_status | ||
184 | acpi_ds_method_data_init_args ( | ||
185 | union acpi_operand_object **params, | ||
186 | u32 max_param_count, | ||
187 | struct acpi_walk_state *walk_state) | ||
188 | { | ||
189 | acpi_status status; | ||
190 | u32 index = 0; | ||
191 | |||
192 | |||
193 | ACPI_FUNCTION_TRACE_PTR ("ds_method_data_init_args", params); | ||
194 | |||
195 | |||
196 | if (!params) { | ||
197 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "No param list passed to method\n")); | ||
198 | return_ACPI_STATUS (AE_OK); | ||
199 | } | ||
200 | |||
201 | /* Copy passed parameters into the new method stack frame */ | ||
202 | |||
203 | while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) { | ||
204 | /* | ||
205 | * A valid parameter. | ||
206 | * Store the argument in the method/walk descriptor. | ||
207 | * Do not copy the arg in order to implement call by reference | ||
208 | */ | ||
209 | status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state); | ||
210 | if (ACPI_FAILURE (status)) { | ||
211 | return_ACPI_STATUS (status); | ||
212 | } | ||
213 | |||
214 | index++; | ||
215 | } | ||
216 | |||
217 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", index)); | ||
218 | return_ACPI_STATUS (AE_OK); | ||
219 | } | ||
220 | |||
221 | |||
222 | /******************************************************************************* | ||
223 | * | ||
224 | * FUNCTION: acpi_ds_method_data_get_node | ||
225 | * | ||
226 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
227 | * Index - which local_var or argument whose type | ||
228 | * to get | ||
229 | * walk_state - Current walk state object | ||
230 | * | ||
231 | * RETURN: Get the Node associated with a local or arg. | ||
232 | * | ||
233 | ******************************************************************************/ | ||
234 | |||
235 | acpi_status | ||
236 | acpi_ds_method_data_get_node ( | ||
237 | u16 opcode, | ||
238 | u32 index, | ||
239 | struct acpi_walk_state *walk_state, | ||
240 | struct acpi_namespace_node **node) | ||
241 | { | ||
242 | ACPI_FUNCTION_TRACE ("ds_method_data_get_node"); | ||
243 | |||
244 | |||
245 | /* | ||
246 | * Method Locals and Arguments are supported | ||
247 | */ | ||
248 | switch (opcode) { | ||
249 | case AML_LOCAL_OP: | ||
250 | |||
251 | if (index > ACPI_METHOD_MAX_LOCAL) { | ||
252 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", | ||
253 | index, ACPI_METHOD_MAX_LOCAL)); | ||
254 | return_ACPI_STATUS (AE_AML_INVALID_INDEX); | ||
255 | } | ||
256 | |||
257 | /* Return a pointer to the pseudo-node */ | ||
258 | |||
259 | *node = &walk_state->local_variables[index]; | ||
260 | break; | ||
261 | |||
262 | case AML_ARG_OP: | ||
263 | |||
264 | if (index > ACPI_METHOD_MAX_ARG) { | ||
265 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", | ||
266 | index, ACPI_METHOD_MAX_ARG)); | ||
267 | return_ACPI_STATUS (AE_AML_INVALID_INDEX); | ||
268 | } | ||
269 | |||
270 | /* Return a pointer to the pseudo-node */ | ||
271 | |||
272 | *node = &walk_state->arguments[index]; | ||
273 | break; | ||
274 | |||
275 | default: | ||
276 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode)); | ||
277 | return_ACPI_STATUS (AE_AML_BAD_OPCODE); | ||
278 | } | ||
279 | |||
280 | return_ACPI_STATUS (AE_OK); | ||
281 | } | ||
282 | |||
283 | |||
284 | /******************************************************************************* | ||
285 | * | ||
286 | * FUNCTION: acpi_ds_method_data_set_value | ||
287 | * | ||
288 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
289 | * Index - which local_var or argument to get | ||
290 | * Object - Object to be inserted into the stack entry | ||
291 | * walk_state - Current walk state object | ||
292 | * | ||
293 | * RETURN: Status | ||
294 | * | ||
295 | * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. | ||
296 | * Note: There is no "implicit conversion" for locals. | ||
297 | * | ||
298 | ******************************************************************************/ | ||
299 | |||
300 | acpi_status | ||
301 | acpi_ds_method_data_set_value ( | ||
302 | u16 opcode, | ||
303 | u32 index, | ||
304 | union acpi_operand_object *object, | ||
305 | struct acpi_walk_state *walk_state) | ||
306 | { | ||
307 | acpi_status status; | ||
308 | struct acpi_namespace_node *node; | ||
309 | |||
310 | |||
311 | ACPI_FUNCTION_TRACE ("ds_method_data_set_value"); | ||
312 | |||
313 | |||
314 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
315 | "new_obj %p Opcode %X, Refs=%d [%s]\n", object, | ||
316 | opcode, object->common.reference_count, | ||
317 | acpi_ut_get_type_name (object->common.type))); | ||
318 | |||
319 | /* Get the namespace node for the arg/local */ | ||
320 | |||
321 | status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); | ||
322 | if (ACPI_FAILURE (status)) { | ||
323 | return_ACPI_STATUS (status); | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * Increment ref count so object can't be deleted while installed. | ||
328 | * NOTE: We do not copy the object in order to preserve the call by | ||
329 | * reference semantics of ACPI Control Method invocation. | ||
330 | * (See ACPI specification 2.0_c) | ||
331 | */ | ||
332 | acpi_ut_add_reference (object); | ||
333 | |||
334 | /* Install the object */ | ||
335 | |||
336 | node->object = object; | ||
337 | return_ACPI_STATUS (status); | ||
338 | } | ||
339 | |||
340 | |||
341 | /******************************************************************************* | ||
342 | * | ||
343 | * FUNCTION: acpi_ds_method_data_get_type | ||
344 | * | ||
345 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
346 | * Index - which local_var or argument whose type | ||
347 | * to get | ||
348 | * walk_state - Current walk state object | ||
349 | * | ||
350 | * RETURN: Data type of current value of the selected Arg or Local | ||
351 | * | ||
352 | ******************************************************************************/ | ||
353 | #ifdef ACPI_FUTURE_USAGE | ||
354 | acpi_object_type | ||
355 | acpi_ds_method_data_get_type ( | ||
356 | u16 opcode, | ||
357 | u32 index, | ||
358 | struct acpi_walk_state *walk_state) | ||
359 | { | ||
360 | acpi_status status; | ||
361 | struct acpi_namespace_node *node; | ||
362 | union acpi_operand_object *object; | ||
363 | |||
364 | |||
365 | ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); | ||
366 | |||
367 | |||
368 | /* Get the namespace node for the arg/local */ | ||
369 | |||
370 | status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); | ||
371 | if (ACPI_FAILURE (status)) { | ||
372 | return_VALUE ((ACPI_TYPE_NOT_FOUND)); | ||
373 | } | ||
374 | |||
375 | /* Get the object */ | ||
376 | |||
377 | object = acpi_ns_get_attached_object (node); | ||
378 | if (!object) { | ||
379 | /* Uninitialized local/arg, return TYPE_ANY */ | ||
380 | |||
381 | return_VALUE (ACPI_TYPE_ANY); | ||
382 | } | ||
383 | |||
384 | /* Get the object type */ | ||
385 | |||
386 | return_VALUE (ACPI_GET_OBJECT_TYPE (object)); | ||
387 | } | ||
388 | #endif /* ACPI_FUTURE_USAGE */ | ||
389 | |||
390 | |||
391 | /******************************************************************************* | ||
392 | * | ||
393 | * FUNCTION: acpi_ds_method_data_get_value | ||
394 | * | ||
395 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
396 | * Index - which local_var or argument to get | ||
397 | * walk_state - Current walk state object | ||
398 | * *dest_desc - Ptr to Descriptor into which selected Arg | ||
399 | * or Local value should be copied | ||
400 | * | ||
401 | * RETURN: Status | ||
402 | * | ||
403 | * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame | ||
404 | * at the current top of the method stack. | ||
405 | * Used only in acpi_ex_resolve_to_value(). | ||
406 | * | ||
407 | ******************************************************************************/ | ||
408 | |||
409 | acpi_status | ||
410 | acpi_ds_method_data_get_value ( | ||
411 | u16 opcode, | ||
412 | u32 index, | ||
413 | struct acpi_walk_state *walk_state, | ||
414 | union acpi_operand_object **dest_desc) | ||
415 | { | ||
416 | acpi_status status; | ||
417 | struct acpi_namespace_node *node; | ||
418 | union acpi_operand_object *object; | ||
419 | |||
420 | |||
421 | ACPI_FUNCTION_TRACE ("ds_method_data_get_value"); | ||
422 | |||
423 | |||
424 | /* Validate the object descriptor */ | ||
425 | |||
426 | if (!dest_desc) { | ||
427 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null object descriptor pointer\n")); | ||
428 | return_ACPI_STATUS (AE_BAD_PARAMETER); | ||
429 | } | ||
430 | |||
431 | /* Get the namespace node for the arg/local */ | ||
432 | |||
433 | status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); | ||
434 | if (ACPI_FAILURE (status)) { | ||
435 | return_ACPI_STATUS (status); | ||
436 | } | ||
437 | |||
438 | /* Get the object from the node */ | ||
439 | |||
440 | object = node->object; | ||
441 | |||
442 | /* Examine the returned object, it must be valid. */ | ||
443 | |||
444 | if (!object) { | ||
445 | /* | ||
446 | * Index points to uninitialized object. | ||
447 | * This means that either 1) The expected argument was | ||
448 | * not passed to the method, or 2) A local variable | ||
449 | * was referenced by the method (via the ASL) | ||
450 | * before it was initialized. Either case is an error. | ||
451 | */ | ||
452 | |||
453 | /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ | ||
454 | |||
455 | if (acpi_gbl_enable_interpreter_slack) { | ||
456 | object = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); | ||
457 | if (!object) { | ||
458 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
459 | } | ||
460 | |||
461 | object->integer.value = 0; | ||
462 | node->object = object; | ||
463 | } | ||
464 | |||
465 | /* Otherwise, return the error */ | ||
466 | |||
467 | else switch (opcode) { | ||
468 | case AML_ARG_OP: | ||
469 | |||
470 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n", | ||
471 | index, node)); | ||
472 | |||
473 | return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); | ||
474 | |||
475 | case AML_LOCAL_OP: | ||
476 | |||
477 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n", | ||
478 | index, node)); | ||
479 | |||
480 | return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); | ||
481 | |||
482 | default: | ||
483 | ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", opcode)); | ||
484 | return_ACPI_STATUS (AE_AML_INTERNAL); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | * The Index points to an initialized and valid object. | ||
490 | * Return an additional reference to the object | ||
491 | */ | ||
492 | *dest_desc = object; | ||
493 | acpi_ut_add_reference (object); | ||
494 | |||
495 | return_ACPI_STATUS (AE_OK); | ||
496 | } | ||
497 | |||
498 | |||
499 | /******************************************************************************* | ||
500 | * | ||
501 | * FUNCTION: acpi_ds_method_data_delete_value | ||
502 | * | ||
503 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
504 | * Index - which local_var or argument to delete | ||
505 | * walk_state - Current walk state object | ||
506 | * | ||
507 | * RETURN: None | ||
508 | * | ||
509 | * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts | ||
510 | * a null into the stack slot after the object is deleted. | ||
511 | * | ||
512 | ******************************************************************************/ | ||
513 | |||
514 | void | ||
515 | acpi_ds_method_data_delete_value ( | ||
516 | u16 opcode, | ||
517 | u32 index, | ||
518 | struct acpi_walk_state *walk_state) | ||
519 | { | ||
520 | acpi_status status; | ||
521 | struct acpi_namespace_node *node; | ||
522 | union acpi_operand_object *object; | ||
523 | |||
524 | |||
525 | ACPI_FUNCTION_TRACE ("ds_method_data_delete_value"); | ||
526 | |||
527 | |||
528 | /* Get the namespace node for the arg/local */ | ||
529 | |||
530 | status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); | ||
531 | if (ACPI_FAILURE (status)) { | ||
532 | return_VOID; | ||
533 | } | ||
534 | |||
535 | /* Get the associated object */ | ||
536 | |||
537 | object = acpi_ns_get_attached_object (node); | ||
538 | |||
539 | /* | ||
540 | * Undefine the Arg or Local by setting its descriptor | ||
541 | * pointer to NULL. Locals/Args can contain both | ||
542 | * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs | ||
543 | */ | ||
544 | node->object = NULL; | ||
545 | |||
546 | if ((object) && | ||
547 | (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_OPERAND)) { | ||
548 | /* | ||
549 | * There is a valid object. | ||
550 | * Decrement the reference count by one to balance the | ||
551 | * increment when the object was stored. | ||
552 | */ | ||
553 | acpi_ut_remove_reference (object); | ||
554 | } | ||
555 | |||
556 | return_VOID; | ||
557 | } | ||
558 | |||
559 | |||
560 | /******************************************************************************* | ||
561 | * | ||
562 | * FUNCTION: acpi_ds_store_object_to_local | ||
563 | * | ||
564 | * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP | ||
565 | * Index - which local_var or argument to set | ||
566 | * obj_desc - Value to be stored | ||
567 | * walk_state - Current walk state | ||
568 | * | ||
569 | * RETURN: Status | ||
570 | * | ||
571 | * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed | ||
572 | * as the new value for the Arg or Local and the reference count | ||
573 | * for obj_desc is incremented. | ||
574 | * | ||
575 | ******************************************************************************/ | ||
576 | |||
577 | acpi_status | ||
578 | acpi_ds_store_object_to_local ( | ||
579 | u16 opcode, | ||
580 | u32 index, | ||
581 | union acpi_operand_object *obj_desc, | ||
582 | struct acpi_walk_state *walk_state) | ||
583 | { | ||
584 | acpi_status status; | ||
585 | struct acpi_namespace_node *node; | ||
586 | union acpi_operand_object *current_obj_desc; | ||
587 | union acpi_operand_object *new_obj_desc; | ||
588 | |||
589 | |||
590 | ACPI_FUNCTION_TRACE ("ds_store_object_to_local"); | ||
591 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", | ||
592 | opcode, index, obj_desc)); | ||
593 | |||
594 | /* Parameter validation */ | ||
595 | |||
596 | if (!obj_desc) { | ||
597 | return_ACPI_STATUS (AE_BAD_PARAMETER); | ||
598 | } | ||
599 | |||
600 | /* Get the namespace node for the arg/local */ | ||
601 | |||
602 | status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); | ||
603 | if (ACPI_FAILURE (status)) { | ||
604 | return_ACPI_STATUS (status); | ||
605 | } | ||
606 | |||
607 | current_obj_desc = acpi_ns_get_attached_object (node); | ||
608 | if (current_obj_desc == obj_desc) { | ||
609 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", | ||
610 | obj_desc)); | ||
611 | return_ACPI_STATUS (status); | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * If the reference count on the object is more than one, we must | ||
616 | * take a copy of the object before we store. A reference count | ||
617 | * of exactly 1 means that the object was just created during the | ||
618 | * evaluation of an expression, and we can safely use it since it | ||
619 | * is not used anywhere else. | ||
620 | */ | ||
621 | new_obj_desc = obj_desc; | ||
622 | if (obj_desc->common.reference_count > 1) { | ||
623 | status = acpi_ut_copy_iobject_to_iobject (obj_desc, &new_obj_desc, walk_state); | ||
624 | if (ACPI_FAILURE (status)) { | ||
625 | return_ACPI_STATUS (status); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | /* | ||
630 | * If there is an object already in this slot, we either | ||
631 | * have to delete it, or if this is an argument and there | ||
632 | * is an object reference stored there, we have to do | ||
633 | * an indirect store! | ||
634 | */ | ||
635 | if (current_obj_desc) { | ||
636 | /* | ||
637 | * Check for an indirect store if an argument | ||
638 | * contains an object reference (stored as an Node). | ||
639 | * We don't allow this automatic dereferencing for | ||
640 | * locals, since a store to a local should overwrite | ||
641 | * anything there, including an object reference. | ||
642 | * | ||
643 | * If both Arg0 and Local0 contain ref_of (Local4): | ||
644 | * | ||
645 | * Store (1, Arg0) - Causes indirect store to local4 | ||
646 | * Store (1, Local0) - Stores 1 in local0, overwriting | ||
647 | * the reference to local4 | ||
648 | * Store (1, de_refof (Local0)) - Causes indirect store to local4 | ||
649 | * | ||
650 | * Weird, but true. | ||
651 | */ | ||
652 | if (opcode == AML_ARG_OP) { | ||
653 | /* | ||
654 | * Make sure that the object is the correct type. This may be overkill, but | ||
655 | * it is here because references were NS nodes in the past. Now they are | ||
656 | * operand objects of type Reference. | ||
657 | */ | ||
658 | if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) { | ||
659 | ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n", | ||
660 | acpi_ut_get_descriptor_name (current_obj_desc))); | ||
661 | return_ACPI_STATUS (AE_AML_INTERNAL); | ||
662 | } | ||
663 | |||
664 | /* | ||
665 | * If we have a valid reference object that came from ref_of(), do the | ||
666 | * indirect store | ||
667 | */ | ||
668 | if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && | ||
669 | (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { | ||
670 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
671 | "Arg (%p) is an obj_ref(Node), storing in node %p\n", | ||
672 | new_obj_desc, current_obj_desc)); | ||
673 | |||
674 | /* | ||
675 | * Store this object to the Node (perform the indirect store) | ||
676 | * NOTE: No implicit conversion is performed, as per the ACPI | ||
677 | * specification rules on storing to Locals/Args. | ||
678 | */ | ||
679 | status = acpi_ex_store_object_to_node (new_obj_desc, | ||
680 | current_obj_desc->reference.object, walk_state, | ||
681 | ACPI_NO_IMPLICIT_CONVERSION); | ||
682 | |||
683 | /* Remove local reference if we copied the object above */ | ||
684 | |||
685 | if (new_obj_desc != obj_desc) { | ||
686 | acpi_ut_remove_reference (new_obj_desc); | ||
687 | } | ||
688 | return_ACPI_STATUS (status); | ||
689 | } | ||
690 | } | ||
691 | |||
692 | /* | ||
693 | * Delete the existing object | ||
694 | * before storing the new one | ||
695 | */ | ||
696 | acpi_ds_method_data_delete_value (opcode, index, walk_state); | ||
697 | } | ||
698 | |||
699 | /* | ||
700 | * Install the Obj descriptor (*new_obj_desc) into | ||
701 | * the descriptor for the Arg or Local. | ||
702 | * (increments the object reference count by one) | ||
703 | */ | ||
704 | status = acpi_ds_method_data_set_value (opcode, index, new_obj_desc, walk_state); | ||
705 | |||
706 | /* Remove local reference if we copied the object above */ | ||
707 | |||
708 | if (new_obj_desc != obj_desc) { | ||
709 | acpi_ut_remove_reference (new_obj_desc); | ||
710 | } | ||
711 | |||
712 | return_ACPI_STATUS (status); | ||
713 | } | ||
714 | |||
715 | |||
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c new file mode 100644 index 000000000000..eb8af4785bcb --- /dev/null +++ b/drivers/acpi/dispatcher/dsobject.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dsobject - Dispatcher object management routines | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acparser.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acnamesp.h> | ||
50 | #include <acpi/acinterp.h> | ||
51 | |||
52 | #define _COMPONENT ACPI_DISPATCHER | ||
53 | ACPI_MODULE_NAME ("dsobject") | ||
54 | |||
55 | |||
56 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
57 | /***************************************************************************** | ||
58 | * | ||
59 | * FUNCTION: acpi_ds_build_internal_object | ||
60 | * | ||
61 | * PARAMETERS: walk_state - Current walk state | ||
62 | * Op - Parser object to be translated | ||
63 | * obj_desc_ptr - Where the ACPI internal object is returned | ||
64 | * | ||
65 | * RETURN: Status | ||
66 | * | ||
67 | * DESCRIPTION: Translate a parser Op object to the equivalent namespace object | ||
68 | * Simple objects are any objects other than a package object! | ||
69 | * | ||
70 | ****************************************************************************/ | ||
71 | |||
72 | acpi_status | ||
73 | acpi_ds_build_internal_object ( | ||
74 | struct acpi_walk_state *walk_state, | ||
75 | union acpi_parse_object *op, | ||
76 | union acpi_operand_object **obj_desc_ptr) | ||
77 | { | ||
78 | union acpi_operand_object *obj_desc; | ||
79 | acpi_status status; | ||
80 | |||
81 | |||
82 | ACPI_FUNCTION_TRACE ("ds_build_internal_object"); | ||
83 | |||
84 | |||
85 | *obj_desc_ptr = NULL; | ||
86 | if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { | ||
87 | /* | ||
88 | * This is an named object reference. If this name was | ||
89 | * previously looked up in the namespace, it was stored in this op. | ||
90 | * Otherwise, go ahead and look it up now | ||
91 | */ | ||
92 | if (!op->common.node) { | ||
93 | status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, | ||
94 | ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, | ||
95 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, | ||
96 | (struct acpi_namespace_node **) &(op->common.node)); | ||
97 | |||
98 | if (ACPI_FAILURE (status)) { | ||
99 | ACPI_REPORT_NSERROR (op->common.value.string, status); | ||
100 | return_ACPI_STATUS (status); | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /* Create and init the internal ACPI object */ | ||
106 | |||
107 | obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); | ||
108 | if (!obj_desc) { | ||
109 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
110 | } | ||
111 | |||
112 | status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc); | ||
113 | if (ACPI_FAILURE (status)) { | ||
114 | acpi_ut_remove_reference (obj_desc); | ||
115 | return_ACPI_STATUS (status); | ||
116 | } | ||
117 | |||
118 | *obj_desc_ptr = obj_desc; | ||
119 | return_ACPI_STATUS (AE_OK); | ||
120 | } | ||
121 | |||
122 | |||
123 | /***************************************************************************** | ||
124 | * | ||
125 | * FUNCTION: acpi_ds_build_internal_buffer_obj | ||
126 | * | ||
127 | * PARAMETERS: walk_state - Current walk state | ||
128 | * Op - Parser object to be translated | ||
129 | * buffer_length - Length of the buffer | ||
130 | * obj_desc_ptr - Where the ACPI internal object is returned | ||
131 | * | ||
132 | * RETURN: Status | ||
133 | * | ||
134 | * DESCRIPTION: Translate a parser Op package object to the equivalent | ||
135 | * namespace object | ||
136 | * | ||
137 | ****************************************************************************/ | ||
138 | |||
139 | acpi_status | ||
140 | acpi_ds_build_internal_buffer_obj ( | ||
141 | struct acpi_walk_state *walk_state, | ||
142 | union acpi_parse_object *op, | ||
143 | u32 buffer_length, | ||
144 | union acpi_operand_object **obj_desc_ptr) | ||
145 | { | ||
146 | union acpi_parse_object *arg; | ||
147 | union acpi_operand_object *obj_desc; | ||
148 | union acpi_parse_object *byte_list; | ||
149 | u32 byte_list_length = 0; | ||
150 | |||
151 | |||
152 | ACPI_FUNCTION_TRACE ("ds_build_internal_buffer_obj"); | ||
153 | |||
154 | |||
155 | obj_desc = *obj_desc_ptr; | ||
156 | if (obj_desc) { | ||
157 | /* | ||
158 | * We are evaluating a Named buffer object "Name (xxxx, Buffer)". | ||
159 | * The buffer object already exists (from the NS node) | ||
160 | */ | ||
161 | } | ||
162 | else { | ||
163 | /* Create a new buffer object */ | ||
164 | |||
165 | obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); | ||
166 | *obj_desc_ptr = obj_desc; | ||
167 | if (!obj_desc) { | ||
168 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Second arg is the buffer data (optional) byte_list can be either | ||
174 | * individual bytes or a string initializer. In either case, a | ||
175 | * byte_list appears in the AML. | ||
176 | */ | ||
177 | arg = op->common.value.arg; /* skip first arg */ | ||
178 | |||
179 | byte_list = arg->named.next; | ||
180 | if (byte_list) { | ||
181 | if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) { | ||
182 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
183 | "Expecting bytelist, got AML opcode %X in op %p\n", | ||
184 | byte_list->common.aml_opcode, byte_list)); | ||
185 | |||
186 | acpi_ut_remove_reference (obj_desc); | ||
187 | return (AE_TYPE); | ||
188 | } | ||
189 | |||
190 | byte_list_length = (u32) byte_list->common.value.integer; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * The buffer length (number of bytes) will be the larger of: | ||
195 | * 1) The specified buffer length and | ||
196 | * 2) The length of the initializer byte list | ||
197 | */ | ||
198 | obj_desc->buffer.length = buffer_length; | ||
199 | if (byte_list_length > buffer_length) { | ||
200 | obj_desc->buffer.length = byte_list_length; | ||
201 | } | ||
202 | |||
203 | /* Allocate the buffer */ | ||
204 | |||
205 | if (obj_desc->buffer.length == 0) { | ||
206 | obj_desc->buffer.pointer = NULL; | ||
207 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
208 | "Buffer defined with zero length in AML, creating\n")); | ||
209 | } | ||
210 | else { | ||
211 | obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE ( | ||
212 | obj_desc->buffer.length); | ||
213 | if (!obj_desc->buffer.pointer) { | ||
214 | acpi_ut_delete_object_desc (obj_desc); | ||
215 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
216 | } | ||
217 | |||
218 | /* Initialize buffer from the byte_list (if present) */ | ||
219 | |||
220 | if (byte_list) { | ||
221 | ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->named.data, | ||
222 | byte_list_length); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; | ||
227 | op->common.node = (struct acpi_namespace_node *) obj_desc; | ||
228 | return_ACPI_STATUS (AE_OK); | ||
229 | } | ||
230 | |||
231 | |||
232 | /***************************************************************************** | ||
233 | * | ||
234 | * FUNCTION: acpi_ds_build_internal_package_obj | ||
235 | * | ||
236 | * PARAMETERS: walk_state - Current walk state | ||
237 | * Op - Parser object to be translated | ||
238 | * package_length - Number of elements in the package | ||
239 | * obj_desc_ptr - Where the ACPI internal object is returned | ||
240 | * | ||
241 | * RETURN: Status | ||
242 | * | ||
243 | * DESCRIPTION: Translate a parser Op package object to the equivalent | ||
244 | * namespace object | ||
245 | * | ||
246 | ****************************************************************************/ | ||
247 | |||
248 | acpi_status | ||
249 | acpi_ds_build_internal_package_obj ( | ||
250 | struct acpi_walk_state *walk_state, | ||
251 | union acpi_parse_object *op, | ||
252 | u32 package_length, | ||
253 | union acpi_operand_object **obj_desc_ptr) | ||
254 | { | ||
255 | union acpi_parse_object *arg; | ||
256 | union acpi_parse_object *parent; | ||
257 | union acpi_operand_object *obj_desc = NULL; | ||
258 | u32 package_list_length; | ||
259 | acpi_status status = AE_OK; | ||
260 | u32 i; | ||
261 | |||
262 | |||
263 | ACPI_FUNCTION_TRACE ("ds_build_internal_package_obj"); | ||
264 | |||
265 | |||
266 | /* Find the parent of a possibly nested package */ | ||
267 | |||
268 | parent = op->common.parent; | ||
269 | while ((parent->common.aml_opcode == AML_PACKAGE_OP) || | ||
270 | (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { | ||
271 | parent = parent->common.parent; | ||
272 | } | ||
273 | |||
274 | obj_desc = *obj_desc_ptr; | ||
275 | if (obj_desc) { | ||
276 | /* | ||
277 | * We are evaluating a Named package object "Name (xxxx, Package)". | ||
278 | * Get the existing package object from the NS node | ||
279 | */ | ||
280 | } | ||
281 | else { | ||
282 | obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); | ||
283 | *obj_desc_ptr = obj_desc; | ||
284 | if (!obj_desc) { | ||
285 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
286 | } | ||
287 | |||
288 | obj_desc->package.node = parent->common.node; | ||
289 | } | ||
290 | |||
291 | obj_desc->package.count = package_length; | ||
292 | |||
293 | /* Count the number of items in the package list */ | ||
294 | |||
295 | package_list_length = 0; | ||
296 | arg = op->common.value.arg; | ||
297 | arg = arg->common.next; | ||
298 | while (arg) { | ||
299 | package_list_length++; | ||
300 | arg = arg->common.next; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * The package length (number of elements) will be the greater | ||
305 | * of the specified length and the length of the initializer list | ||
306 | */ | ||
307 | if (package_list_length > package_length) { | ||
308 | obj_desc->package.count = package_list_length; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Allocate the pointer array (array of pointers to the | ||
313 | * individual objects). Add an extra pointer slot so | ||
314 | * that the list is always null terminated. | ||
315 | */ | ||
316 | obj_desc->package.elements = ACPI_MEM_CALLOCATE ( | ||
317 | ((acpi_size) obj_desc->package.count + 1) * sizeof (void *)); | ||
318 | |||
319 | if (!obj_desc->package.elements) { | ||
320 | acpi_ut_delete_object_desc (obj_desc); | ||
321 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Now init the elements of the package | ||
326 | */ | ||
327 | i = 0; | ||
328 | arg = op->common.value.arg; | ||
329 | arg = arg->common.next; | ||
330 | while (arg) { | ||
331 | if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { | ||
332 | /* Object (package or buffer) is already built */ | ||
333 | |||
334 | obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); | ||
335 | } | ||
336 | else { | ||
337 | status = acpi_ds_build_internal_object (walk_state, arg, | ||
338 | &obj_desc->package.elements[i]); | ||
339 | } | ||
340 | |||
341 | i++; | ||
342 | arg = arg->common.next; | ||
343 | } | ||
344 | |||
345 | obj_desc->package.flags |= AOPOBJ_DATA_VALID; | ||
346 | op->common.node = (struct acpi_namespace_node *) obj_desc; | ||
347 | return_ACPI_STATUS (status); | ||
348 | } | ||
349 | |||
350 | |||
351 | /***************************************************************************** | ||
352 | * | ||
353 | * FUNCTION: acpi_ds_create_node | ||
354 | * | ||
355 | * PARAMETERS: walk_state - Current walk state | ||
356 | * Node - NS Node to be initialized | ||
357 | * Op - Parser object to be translated | ||
358 | * | ||
359 | * RETURN: Status | ||
360 | * | ||
361 | * DESCRIPTION: Create the object to be associated with a namespace node | ||
362 | * | ||
363 | ****************************************************************************/ | ||
364 | |||
365 | acpi_status | ||
366 | acpi_ds_create_node ( | ||
367 | struct acpi_walk_state *walk_state, | ||
368 | struct acpi_namespace_node *node, | ||
369 | union acpi_parse_object *op) | ||
370 | { | ||
371 | acpi_status status; | ||
372 | union acpi_operand_object *obj_desc; | ||
373 | |||
374 | |||
375 | ACPI_FUNCTION_TRACE_PTR ("ds_create_node", op); | ||
376 | |||
377 | |||
378 | /* | ||
379 | * Because of the execution pass through the non-control-method | ||
380 | * parts of the table, we can arrive here twice. Only init | ||
381 | * the named object node the first time through | ||
382 | */ | ||
383 | if (acpi_ns_get_attached_object (node)) { | ||
384 | return_ACPI_STATUS (AE_OK); | ||
385 | } | ||
386 | |||
387 | if (!op->common.value.arg) { | ||
388 | /* No arguments, there is nothing to do */ | ||
389 | |||
390 | return_ACPI_STATUS (AE_OK); | ||
391 | } | ||
392 | |||
393 | /* Build an internal object for the argument(s) */ | ||
394 | |||
395 | status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc); | ||
396 | if (ACPI_FAILURE (status)) { | ||
397 | return_ACPI_STATUS (status); | ||
398 | } | ||
399 | |||
400 | /* Re-type the object according to its argument */ | ||
401 | |||
402 | node->type = ACPI_GET_OBJECT_TYPE (obj_desc); | ||
403 | |||
404 | /* Attach obj to node */ | ||
405 | |||
406 | status = acpi_ns_attach_object (node, obj_desc, node->type); | ||
407 | |||
408 | /* Remove local reference to the object */ | ||
409 | |||
410 | acpi_ut_remove_reference (obj_desc); | ||
411 | return_ACPI_STATUS (status); | ||
412 | } | ||
413 | |||
414 | #endif /* ACPI_NO_METHOD_EXECUTION */ | ||
415 | |||
416 | |||
417 | /***************************************************************************** | ||
418 | * | ||
419 | * FUNCTION: acpi_ds_init_object_from_op | ||
420 | * | ||
421 | * PARAMETERS: walk_state - Current walk state | ||
422 | * Op - Parser op used to init the internal object | ||
423 | * Opcode - AML opcode associated with the object | ||
424 | * ret_obj_desc - Namespace object to be initialized | ||
425 | * | ||
426 | * RETURN: Status | ||
427 | * | ||
428 | * DESCRIPTION: Initialize a namespace object from a parser Op and its | ||
429 | * associated arguments. The namespace object is a more compact | ||
430 | * representation of the Op and its arguments. | ||
431 | * | ||
432 | ****************************************************************************/ | ||
433 | |||
434 | acpi_status | ||
435 | acpi_ds_init_object_from_op ( | ||
436 | struct acpi_walk_state *walk_state, | ||
437 | union acpi_parse_object *op, | ||
438 | u16 opcode, | ||
439 | union acpi_operand_object **ret_obj_desc) | ||
440 | { | ||
441 | const struct acpi_opcode_info *op_info; | ||
442 | union acpi_operand_object *obj_desc; | ||
443 | acpi_status status = AE_OK; | ||
444 | |||
445 | |||
446 | ACPI_FUNCTION_TRACE ("ds_init_object_from_op"); | ||
447 | |||
448 | |||
449 | obj_desc = *ret_obj_desc; | ||
450 | op_info = acpi_ps_get_opcode_info (opcode); | ||
451 | if (op_info->class == AML_CLASS_UNKNOWN) { | ||
452 | /* Unknown opcode */ | ||
453 | |||
454 | return_ACPI_STATUS (AE_TYPE); | ||
455 | } | ||
456 | |||
457 | /* Perform per-object initialization */ | ||
458 | |||
459 | switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { | ||
460 | case ACPI_TYPE_BUFFER: | ||
461 | |||
462 | /* | ||
463 | * Defer evaluation of Buffer term_arg operand | ||
464 | */ | ||
465 | obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0]; | ||
466 | obj_desc->buffer.aml_start = op->named.data; | ||
467 | obj_desc->buffer.aml_length = op->named.length; | ||
468 | break; | ||
469 | |||
470 | |||
471 | case ACPI_TYPE_PACKAGE: | ||
472 | |||
473 | /* | ||
474 | * Defer evaluation of Package term_arg operand | ||
475 | */ | ||
476 | obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0]; | ||
477 | obj_desc->package.aml_start = op->named.data; | ||
478 | obj_desc->package.aml_length = op->named.length; | ||
479 | break; | ||
480 | |||
481 | |||
482 | case ACPI_TYPE_INTEGER: | ||
483 | |||
484 | switch (op_info->type) { | ||
485 | case AML_TYPE_CONSTANT: | ||
486 | /* | ||
487 | * Resolve AML Constants here - AND ONLY HERE! | ||
488 | * All constants are integers. | ||
489 | * We mark the integer with a flag that indicates that it started life | ||
490 | * as a constant -- so that stores to constants will perform as expected (noop). | ||
491 | * (zero_op is used as a placeholder for optional target operands.) | ||
492 | */ | ||
493 | obj_desc->common.flags = AOPOBJ_AML_CONSTANT; | ||
494 | |||
495 | switch (opcode) { | ||
496 | case AML_ZERO_OP: | ||
497 | |||
498 | obj_desc->integer.value = 0; | ||
499 | break; | ||
500 | |||
501 | case AML_ONE_OP: | ||
502 | |||
503 | obj_desc->integer.value = 1; | ||
504 | break; | ||
505 | |||
506 | case AML_ONES_OP: | ||
507 | |||
508 | obj_desc->integer.value = ACPI_INTEGER_MAX; | ||
509 | |||
510 | /* Truncate value if we are executing from a 32-bit ACPI table */ | ||
511 | |||
512 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
513 | acpi_ex_truncate_for32bit_table (obj_desc); | ||
514 | #endif | ||
515 | break; | ||
516 | |||
517 | case AML_REVISION_OP: | ||
518 | |||
519 | obj_desc->integer.value = ACPI_CA_VERSION; | ||
520 | break; | ||
521 | |||
522 | default: | ||
523 | |||
524 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); | ||
525 | status = AE_AML_OPERAND_TYPE; | ||
526 | break; | ||
527 | } | ||
528 | break; | ||
529 | |||
530 | |||
531 | case AML_TYPE_LITERAL: | ||
532 | |||
533 | obj_desc->integer.value = op->common.value.integer; | ||
534 | break; | ||
535 | |||
536 | |||
537 | default: | ||
538 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); | ||
539 | status = AE_AML_OPERAND_TYPE; | ||
540 | break; | ||
541 | } | ||
542 | break; | ||
543 | |||
544 | |||
545 | case ACPI_TYPE_STRING: | ||
546 | |||
547 | obj_desc->string.pointer = op->common.value.string; | ||
548 | obj_desc->string.length = (u32) ACPI_STRLEN (op->common.value.string); | ||
549 | |||
550 | /* | ||
551 | * The string is contained in the ACPI table, don't ever try | ||
552 | * to delete it | ||
553 | */ | ||
554 | obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; | ||
555 | break; | ||
556 | |||
557 | |||
558 | case ACPI_TYPE_METHOD: | ||
559 | break; | ||
560 | |||
561 | |||
562 | case ACPI_TYPE_LOCAL_REFERENCE: | ||
563 | |||
564 | switch (op_info->type) { | ||
565 | case AML_TYPE_LOCAL_VARIABLE: | ||
566 | |||
567 | /* Split the opcode into a base opcode + offset */ | ||
568 | |||
569 | obj_desc->reference.opcode = AML_LOCAL_OP; | ||
570 | obj_desc->reference.offset = opcode - AML_LOCAL_OP; | ||
571 | |||
572 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
573 | status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, | ||
574 | walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); | ||
575 | #endif | ||
576 | break; | ||
577 | |||
578 | |||
579 | case AML_TYPE_METHOD_ARGUMENT: | ||
580 | |||
581 | /* Split the opcode into a base opcode + offset */ | ||
582 | |||
583 | obj_desc->reference.opcode = AML_ARG_OP; | ||
584 | obj_desc->reference.offset = opcode - AML_ARG_OP; | ||
585 | |||
586 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
587 | status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset, | ||
588 | walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); | ||
589 | #endif | ||
590 | break; | ||
591 | |||
592 | default: /* Other literals, etc.. */ | ||
593 | |||
594 | if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { | ||
595 | /* Node was saved in Op */ | ||
596 | |||
597 | obj_desc->reference.node = op->common.node; | ||
598 | } | ||
599 | |||
600 | obj_desc->reference.opcode = opcode; | ||
601 | break; | ||
602 | } | ||
603 | break; | ||
604 | |||
605 | |||
606 | default: | ||
607 | |||
608 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n", | ||
609 | ACPI_GET_OBJECT_TYPE (obj_desc))); | ||
610 | |||
611 | status = AE_AML_OPERAND_TYPE; | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | return_ACPI_STATUS (status); | ||
616 | } | ||
617 | |||
618 | |||
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c new file mode 100644 index 000000000000..5c987a0e7b75 --- /dev/null +++ b/drivers/acpi/dispatcher/dsopcode.c | |||
@@ -0,0 +1,1151 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dsopcode - Dispatcher Op Region support and handling of | ||
4 | * "control" opcodes | ||
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/acparser.h> | ||
48 | #include <acpi/amlcode.h> | ||
49 | #include <acpi/acdispat.h> | ||
50 | #include <acpi/acinterp.h> | ||
51 | #include <acpi/acnamesp.h> | ||
52 | #include <acpi/acevents.h> | ||
53 | |||
54 | #define _COMPONENT ACPI_DISPATCHER | ||
55 | ACPI_MODULE_NAME ("dsopcode") | ||
56 | |||
57 | |||
58 | /***************************************************************************** | ||
59 | * | ||
60 | * FUNCTION: acpi_ds_execute_arguments | ||
61 | * | ||
62 | * PARAMETERS: Node - Parent NS node | ||
63 | * aml_length - Length of executable AML | ||
64 | * aml_start - Pointer to the AML | ||
65 | * | ||
66 | * RETURN: Status. | ||
67 | * | ||
68 | * DESCRIPTION: Late (deferred) execution of region or field arguments | ||
69 | * | ||
70 | ****************************************************************************/ | ||
71 | |||
72 | acpi_status | ||
73 | acpi_ds_execute_arguments ( | ||
74 | struct acpi_namespace_node *node, | ||
75 | struct acpi_namespace_node *scope_node, | ||
76 | u32 aml_length, | ||
77 | u8 *aml_start) | ||
78 | { | ||
79 | acpi_status status; | ||
80 | union acpi_parse_object *op; | ||
81 | struct acpi_walk_state *walk_state; | ||
82 | |||
83 | |||
84 | ACPI_FUNCTION_TRACE ("ds_execute_arguments"); | ||
85 | |||
86 | |||
87 | /* | ||
88 | * Allocate a new parser op to be the root of the parsed tree | ||
89 | */ | ||
90 | op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); | ||
91 | if (!op) { | ||
92 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
93 | } | ||
94 | |||
95 | /* Save the Node for use in acpi_ps_parse_aml */ | ||
96 | |||
97 | op->common.node = scope_node; | ||
98 | |||
99 | /* Create and initialize a new parser state */ | ||
100 | |||
101 | walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); | ||
102 | if (!walk_state) { | ||
103 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
104 | } | ||
105 | |||
106 | status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, | ||
107 | aml_length, NULL, 1); | ||
108 | if (ACPI_FAILURE (status)) { | ||
109 | acpi_ds_delete_walk_state (walk_state); | ||
110 | return_ACPI_STATUS (status); | ||
111 | } | ||
112 | |||
113 | /* Mark this parse as a deferred opcode */ | ||
114 | |||
115 | walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; | ||
116 | walk_state->deferred_node = node; | ||
117 | |||
118 | /* Pass1: Parse the entire declaration */ | ||
119 | |||
120 | status = acpi_ps_parse_aml (walk_state); | ||
121 | if (ACPI_FAILURE (status)) { | ||
122 | acpi_ps_delete_parse_tree (op); | ||
123 | return_ACPI_STATUS (status); | ||
124 | } | ||
125 | |||
126 | /* Get and init the Op created above */ | ||
127 | |||
128 | op->common.node = node; | ||
129 | acpi_ps_delete_parse_tree (op); | ||
130 | |||
131 | /* Evaluate the deferred arguments */ | ||
132 | |||
133 | op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); | ||
134 | if (!op) { | ||
135 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
136 | } | ||
137 | |||
138 | op->common.node = scope_node; | ||
139 | |||
140 | /* Create and initialize a new parser state */ | ||
141 | |||
142 | walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); | ||
143 | if (!walk_state) { | ||
144 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
145 | } | ||
146 | |||
147 | /* Execute the opcode and arguments */ | ||
148 | |||
149 | status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, | ||
150 | aml_length, NULL, 3); | ||
151 | if (ACPI_FAILURE (status)) { | ||
152 | acpi_ds_delete_walk_state (walk_state); | ||
153 | return_ACPI_STATUS (status); | ||
154 | } | ||
155 | |||
156 | /* Mark this execution as a deferred opcode */ | ||
157 | |||
158 | walk_state->deferred_node = node; | ||
159 | status = acpi_ps_parse_aml (walk_state); | ||
160 | acpi_ps_delete_parse_tree (op); | ||
161 | return_ACPI_STATUS (status); | ||
162 | } | ||
163 | |||
164 | |||
165 | /***************************************************************************** | ||
166 | * | ||
167 | * FUNCTION: acpi_ds_get_buffer_field_arguments | ||
168 | * | ||
169 | * PARAMETERS: obj_desc - A valid buffer_field object | ||
170 | * | ||
171 | * RETURN: Status. | ||
172 | * | ||
173 | * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late | ||
174 | * evaluation of these field attributes. | ||
175 | * | ||
176 | ****************************************************************************/ | ||
177 | |||
178 | acpi_status | ||
179 | acpi_ds_get_buffer_field_arguments ( | ||
180 | union acpi_operand_object *obj_desc) | ||
181 | { | ||
182 | union acpi_operand_object *extra_desc; | ||
183 | struct acpi_namespace_node *node; | ||
184 | acpi_status status; | ||
185 | |||
186 | |||
187 | ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_field_arguments", obj_desc); | ||
188 | |||
189 | |||
190 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { | ||
191 | return_ACPI_STATUS (AE_OK); | ||
192 | } | ||
193 | |||
194 | /* Get the AML pointer (method object) and buffer_field node */ | ||
195 | |||
196 | extra_desc = acpi_ns_get_secondary_object (obj_desc); | ||
197 | node = obj_desc->buffer_field.node; | ||
198 | |||
199 | ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL)); | ||
200 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n", | ||
201 | acpi_ut_get_node_name (node))); | ||
202 | |||
203 | /* Execute the AML code for the term_arg arguments */ | ||
204 | |||
205 | status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), | ||
206 | extra_desc->extra.aml_length, extra_desc->extra.aml_start); | ||
207 | return_ACPI_STATUS (status); | ||
208 | } | ||
209 | |||
210 | |||
211 | /***************************************************************************** | ||
212 | * | ||
213 | * FUNCTION: acpi_ds_get_buffer_arguments | ||
214 | * | ||
215 | * PARAMETERS: obj_desc - A valid Buffer object | ||
216 | * | ||
217 | * RETURN: Status. | ||
218 | * | ||
219 | * DESCRIPTION: Get Buffer length and initializer byte list. This implements | ||
220 | * the late evaluation of these attributes. | ||
221 | * | ||
222 | ****************************************************************************/ | ||
223 | |||
224 | acpi_status | ||
225 | acpi_ds_get_buffer_arguments ( | ||
226 | union acpi_operand_object *obj_desc) | ||
227 | { | ||
228 | struct acpi_namespace_node *node; | ||
229 | acpi_status status; | ||
230 | |||
231 | |||
232 | ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_arguments", obj_desc); | ||
233 | |||
234 | |||
235 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { | ||
236 | return_ACPI_STATUS (AE_OK); | ||
237 | } | ||
238 | |||
239 | /* Get the Buffer node */ | ||
240 | |||
241 | node = obj_desc->buffer.node; | ||
242 | if (!node) { | ||
243 | ACPI_REPORT_ERROR (( | ||
244 | "No pointer back to NS node in buffer obj %p\n", obj_desc)); | ||
245 | return_ACPI_STATUS (AE_AML_INTERNAL); | ||
246 | } | ||
247 | |||
248 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer Arg Init\n")); | ||
249 | |||
250 | /* Execute the AML code for the term_arg arguments */ | ||
251 | |||
252 | status = acpi_ds_execute_arguments (node, node, | ||
253 | obj_desc->buffer.aml_length, obj_desc->buffer.aml_start); | ||
254 | return_ACPI_STATUS (status); | ||
255 | } | ||
256 | |||
257 | |||
258 | /***************************************************************************** | ||
259 | * | ||
260 | * FUNCTION: acpi_ds_get_package_arguments | ||
261 | * | ||
262 | * PARAMETERS: obj_desc - A valid Package object | ||
263 | * | ||
264 | * RETURN: Status. | ||
265 | * | ||
266 | * DESCRIPTION: Get Package length and initializer byte list. This implements | ||
267 | * the late evaluation of these attributes. | ||
268 | * | ||
269 | ****************************************************************************/ | ||
270 | |||
271 | acpi_status | ||
272 | acpi_ds_get_package_arguments ( | ||
273 | union acpi_operand_object *obj_desc) | ||
274 | { | ||
275 | struct acpi_namespace_node *node; | ||
276 | acpi_status status; | ||
277 | |||
278 | |||
279 | ACPI_FUNCTION_TRACE_PTR ("ds_get_package_arguments", obj_desc); | ||
280 | |||
281 | |||
282 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { | ||
283 | return_ACPI_STATUS (AE_OK); | ||
284 | } | ||
285 | |||
286 | /* Get the Package node */ | ||
287 | |||
288 | node = obj_desc->package.node; | ||
289 | if (!node) { | ||
290 | ACPI_REPORT_ERROR (( | ||
291 | "No pointer back to NS node in package %p\n", obj_desc)); | ||
292 | return_ACPI_STATUS (AE_AML_INTERNAL); | ||
293 | } | ||
294 | |||
295 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package Arg Init\n")); | ||
296 | |||
297 | /* Execute the AML code for the term_arg arguments */ | ||
298 | |||
299 | status = acpi_ds_execute_arguments (node, node, | ||
300 | obj_desc->package.aml_length, obj_desc->package.aml_start); | ||
301 | return_ACPI_STATUS (status); | ||
302 | } | ||
303 | |||
304 | |||
305 | /***************************************************************************** | ||
306 | * | ||
307 | * FUNCTION: acpi_ds_get_region_arguments | ||
308 | * | ||
309 | * PARAMETERS: obj_desc - A valid region object | ||
310 | * | ||
311 | * RETURN: Status. | ||
312 | * | ||
313 | * DESCRIPTION: Get region address and length. This implements the late | ||
314 | * evaluation of these region attributes. | ||
315 | * | ||
316 | ****************************************************************************/ | ||
317 | |||
318 | acpi_status | ||
319 | acpi_ds_get_region_arguments ( | ||
320 | union acpi_operand_object *obj_desc) | ||
321 | { | ||
322 | struct acpi_namespace_node *node; | ||
323 | acpi_status status; | ||
324 | union acpi_operand_object *extra_desc; | ||
325 | |||
326 | |||
327 | ACPI_FUNCTION_TRACE_PTR ("ds_get_region_arguments", obj_desc); | ||
328 | |||
329 | |||
330 | if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { | ||
331 | return_ACPI_STATUS (AE_OK); | ||
332 | } | ||
333 | |||
334 | extra_desc = acpi_ns_get_secondary_object (obj_desc); | ||
335 | if (!extra_desc) { | ||
336 | return_ACPI_STATUS (AE_NOT_EXIST); | ||
337 | } | ||
338 | |||
339 | /* Get the Region node */ | ||
340 | |||
341 | node = obj_desc->region.node; | ||
342 | |||
343 | ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); | ||
344 | |||
345 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Arg Init at AML %p\n", | ||
346 | acpi_ut_get_node_name (node), extra_desc->extra.aml_start)); | ||
347 | |||
348 | /* Execute the argument AML */ | ||
349 | |||
350 | status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), | ||
351 | extra_desc->extra.aml_length, extra_desc->extra.aml_start); | ||
352 | return_ACPI_STATUS (status); | ||
353 | } | ||
354 | |||
355 | |||
356 | /***************************************************************************** | ||
357 | * | ||
358 | * FUNCTION: acpi_ds_initialize_region | ||
359 | * | ||
360 | * PARAMETERS: Op - A valid region Op object | ||
361 | * | ||
362 | * RETURN: Status | ||
363 | * | ||
364 | * DESCRIPTION: Front end to ev_initialize_region | ||
365 | * | ||
366 | ****************************************************************************/ | ||
367 | |||
368 | acpi_status | ||
369 | acpi_ds_initialize_region ( | ||
370 | acpi_handle obj_handle) | ||
371 | { | ||
372 | union acpi_operand_object *obj_desc; | ||
373 | acpi_status status; | ||
374 | |||
375 | |||
376 | obj_desc = acpi_ns_get_attached_object (obj_handle); | ||
377 | |||
378 | /* Namespace is NOT locked */ | ||
379 | |||
380 | status = acpi_ev_initialize_region (obj_desc, FALSE); | ||
381 | return (status); | ||
382 | } | ||
383 | |||
384 | |||
385 | /***************************************************************************** | ||
386 | * | ||
387 | * FUNCTION: acpi_ds_init_buffer_field | ||
388 | * | ||
389 | * PARAMETERS: aml_opcode - create_xxx_field | ||
390 | * obj_desc - buffer_field object | ||
391 | * buffer_desc - Host Buffer | ||
392 | * offset_desc - Offset into buffer | ||
393 | * Length - Length of field (CREATE_FIELD_OP only) | ||
394 | * Result - Where to store the result | ||
395 | * | ||
396 | * RETURN: Status | ||
397 | * | ||
398 | * DESCRIPTION: Perform actual initialization of a buffer field | ||
399 | * | ||
400 | ****************************************************************************/ | ||
401 | |||
402 | acpi_status | ||
403 | acpi_ds_init_buffer_field ( | ||
404 | u16 aml_opcode, | ||
405 | union acpi_operand_object *obj_desc, | ||
406 | union acpi_operand_object *buffer_desc, | ||
407 | union acpi_operand_object *offset_desc, | ||
408 | union acpi_operand_object *length_desc, | ||
409 | union acpi_operand_object *result_desc) | ||
410 | { | ||
411 | u32 offset; | ||
412 | u32 bit_offset; | ||
413 | u32 bit_count; | ||
414 | u8 field_flags; | ||
415 | acpi_status status; | ||
416 | |||
417 | |||
418 | ACPI_FUNCTION_TRACE_PTR ("ds_init_buffer_field", obj_desc); | ||
419 | |||
420 | |||
421 | /* Host object must be a Buffer */ | ||
422 | |||
423 | if (ACPI_GET_OBJECT_TYPE (buffer_desc) != ACPI_TYPE_BUFFER) { | ||
424 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
425 | "Target of Create Field is not a Buffer object - %s\n", | ||
426 | acpi_ut_get_object_type_name (buffer_desc))); | ||
427 | |||
428 | status = AE_AML_OPERAND_TYPE; | ||
429 | goto cleanup; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * The last parameter to all of these opcodes (result_desc) started | ||
434 | * out as a name_string, and should therefore now be a NS node | ||
435 | * after resolution in acpi_ex_resolve_operands(). | ||
436 | */ | ||
437 | if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { | ||
438 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n", | ||
439 | acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc))); | ||
440 | |||
441 | status = AE_AML_OPERAND_TYPE; | ||
442 | goto cleanup; | ||
443 | } | ||
444 | |||
445 | offset = (u32) offset_desc->integer.value; | ||
446 | |||
447 | /* | ||
448 | * Setup the Bit offsets and counts, according to the opcode | ||
449 | */ | ||
450 | switch (aml_opcode) { | ||
451 | case AML_CREATE_FIELD_OP: | ||
452 | |||
453 | /* Offset is in bits, count is in bits */ | ||
454 | |||
455 | bit_offset = offset; | ||
456 | bit_count = (u32) length_desc->integer.value; | ||
457 | field_flags = AML_FIELD_ACCESS_BYTE; | ||
458 | break; | ||
459 | |||
460 | case AML_CREATE_BIT_FIELD_OP: | ||
461 | |||
462 | /* Offset is in bits, Field is one bit */ | ||
463 | |||
464 | bit_offset = offset; | ||
465 | bit_count = 1; | ||
466 | field_flags = AML_FIELD_ACCESS_BYTE; | ||
467 | break; | ||
468 | |||
469 | case AML_CREATE_BYTE_FIELD_OP: | ||
470 | |||
471 | /* Offset is in bytes, field is one byte */ | ||
472 | |||
473 | bit_offset = 8 * offset; | ||
474 | bit_count = 8; | ||
475 | field_flags = AML_FIELD_ACCESS_BYTE; | ||
476 | break; | ||
477 | |||
478 | case AML_CREATE_WORD_FIELD_OP: | ||
479 | |||
480 | /* Offset is in bytes, field is one word */ | ||
481 | |||
482 | bit_offset = 8 * offset; | ||
483 | bit_count = 16; | ||
484 | field_flags = AML_FIELD_ACCESS_WORD; | ||
485 | break; | ||
486 | |||
487 | case AML_CREATE_DWORD_FIELD_OP: | ||
488 | |||
489 | /* Offset is in bytes, field is one dword */ | ||
490 | |||
491 | bit_offset = 8 * offset; | ||
492 | bit_count = 32; | ||
493 | field_flags = AML_FIELD_ACCESS_DWORD; | ||
494 | break; | ||
495 | |||
496 | case AML_CREATE_QWORD_FIELD_OP: | ||
497 | |||
498 | /* Offset is in bytes, field is one qword */ | ||
499 | |||
500 | bit_offset = 8 * offset; | ||
501 | bit_count = 64; | ||
502 | field_flags = AML_FIELD_ACCESS_QWORD; | ||
503 | break; | ||
504 | |||
505 | default: | ||
506 | |||
507 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
508 | "Unknown field creation opcode %02x\n", | ||
509 | aml_opcode)); | ||
510 | status = AE_AML_BAD_OPCODE; | ||
511 | goto cleanup; | ||
512 | } | ||
513 | |||
514 | /* Entire field must fit within the current length of the buffer */ | ||
515 | |||
516 | if ((bit_offset + bit_count) > | ||
517 | (8 * (u32) buffer_desc->buffer.length)) { | ||
518 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
519 | "Field [%4.4s] size %d exceeds Buffer [%4.4s] size %d (bits)\n", | ||
520 | acpi_ut_get_node_name (result_desc), | ||
521 | bit_offset + bit_count, | ||
522 | acpi_ut_get_node_name (buffer_desc->buffer.node), | ||
523 | 8 * (u32) buffer_desc->buffer.length)); | ||
524 | status = AE_AML_BUFFER_LIMIT; | ||
525 | goto cleanup; | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * Initialize areas of the field object that are common to all fields | ||
530 | * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) | ||
531 | */ | ||
532 | status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0, | ||
533 | bit_offset, bit_count); | ||
534 | if (ACPI_FAILURE (status)) { | ||
535 | goto cleanup; | ||
536 | } | ||
537 | |||
538 | obj_desc->buffer_field.buffer_obj = buffer_desc; | ||
539 | |||
540 | /* Reference count for buffer_desc inherits obj_desc count */ | ||
541 | |||
542 | buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + | ||
543 | obj_desc->common.reference_count); | ||
544 | |||
545 | |||
546 | cleanup: | ||
547 | |||
548 | /* Always delete the operands */ | ||
549 | |||
550 | acpi_ut_remove_reference (offset_desc); | ||
551 | acpi_ut_remove_reference (buffer_desc); | ||
552 | |||
553 | if (aml_opcode == AML_CREATE_FIELD_OP) { | ||
554 | acpi_ut_remove_reference (length_desc); | ||
555 | } | ||
556 | |||
557 | /* On failure, delete the result descriptor */ | ||
558 | |||
559 | if (ACPI_FAILURE (status)) { | ||
560 | acpi_ut_remove_reference (result_desc); /* Result descriptor */ | ||
561 | } | ||
562 | else { | ||
563 | /* Now the address and length are valid for this buffer_field */ | ||
564 | |||
565 | obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; | ||
566 | } | ||
567 | |||
568 | return_ACPI_STATUS (status); | ||
569 | } | ||
570 | |||
571 | |||
572 | /***************************************************************************** | ||
573 | * | ||
574 | * FUNCTION: acpi_ds_eval_buffer_field_operands | ||
575 | * | ||
576 | * PARAMETERS: walk_state - Current walk | ||
577 | * Op - A valid buffer_field Op object | ||
578 | * | ||
579 | * RETURN: Status | ||
580 | * | ||
581 | * DESCRIPTION: Get buffer_field Buffer and Index | ||
582 | * Called from acpi_ds_exec_end_op during buffer_field parse tree walk | ||
583 | * | ||
584 | ****************************************************************************/ | ||
585 | |||
586 | acpi_status | ||
587 | acpi_ds_eval_buffer_field_operands ( | ||
588 | struct acpi_walk_state *walk_state, | ||
589 | union acpi_parse_object *op) | ||
590 | { | ||
591 | acpi_status status; | ||
592 | union acpi_operand_object *obj_desc; | ||
593 | struct acpi_namespace_node *node; | ||
594 | union acpi_parse_object *next_op; | ||
595 | |||
596 | |||
597 | ACPI_FUNCTION_TRACE_PTR ("ds_eval_buffer_field_operands", op); | ||
598 | |||
599 | |||
600 | /* | ||
601 | * This is where we evaluate the address and length fields of the | ||
602 | * create_xxx_field declaration | ||
603 | */ | ||
604 | node = op->common.node; | ||
605 | |||
606 | /* next_op points to the op that holds the Buffer */ | ||
607 | |||
608 | next_op = op->common.value.arg; | ||
609 | |||
610 | /* Evaluate/create the address and length operands */ | ||
611 | |||
612 | status = acpi_ds_create_operands (walk_state, next_op); | ||
613 | if (ACPI_FAILURE (status)) { | ||
614 | return_ACPI_STATUS (status); | ||
615 | } | ||
616 | |||
617 | obj_desc = acpi_ns_get_attached_object (node); | ||
618 | if (!obj_desc) { | ||
619 | return_ACPI_STATUS (AE_NOT_EXIST); | ||
620 | } | ||
621 | |||
622 | /* Resolve the operands */ | ||
623 | |||
624 | status = acpi_ex_resolve_operands (op->common.aml_opcode, | ||
625 | ACPI_WALK_OPERANDS, walk_state); | ||
626 | |||
627 | ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, | ||
628 | acpi_ps_get_opcode_name (op->common.aml_opcode), | ||
629 | walk_state->num_operands, "after acpi_ex_resolve_operands"); | ||
630 | |||
631 | if (ACPI_FAILURE (status)) { | ||
632 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) bad operand(s) (%X)\n", | ||
633 | acpi_ps_get_opcode_name (op->common.aml_opcode), status)); | ||
634 | |||
635 | return_ACPI_STATUS (status); | ||
636 | } | ||
637 | |||
638 | /* Initialize the Buffer Field */ | ||
639 | |||
640 | if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { | ||
641 | /* NOTE: Slightly different operands for this opcode */ | ||
642 | |||
643 | status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, | ||
644 | walk_state->operands[0], walk_state->operands[1], | ||
645 | walk_state->operands[2], walk_state->operands[3]); | ||
646 | } | ||
647 | else { | ||
648 | /* All other, create_xxx_field opcodes */ | ||
649 | |||
650 | status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, | ||
651 | walk_state->operands[0], walk_state->operands[1], | ||
652 | NULL, walk_state->operands[2]); | ||
653 | } | ||
654 | |||
655 | return_ACPI_STATUS (status); | ||
656 | } | ||
657 | |||
658 | |||
659 | /***************************************************************************** | ||
660 | * | ||
661 | * FUNCTION: acpi_ds_eval_region_operands | ||
662 | * | ||
663 | * PARAMETERS: walk_state - Current walk | ||
664 | * Op - A valid region Op object | ||
665 | * | ||
666 | * RETURN: Status | ||
667 | * | ||
668 | * DESCRIPTION: Get region address and length | ||
669 | * Called from acpi_ds_exec_end_op during op_region parse tree walk | ||
670 | * | ||
671 | ****************************************************************************/ | ||
672 | |||
673 | acpi_status | ||
674 | acpi_ds_eval_region_operands ( | ||
675 | struct acpi_walk_state *walk_state, | ||
676 | union acpi_parse_object *op) | ||
677 | { | ||
678 | acpi_status status; | ||
679 | union acpi_operand_object *obj_desc; | ||
680 | union acpi_operand_object *operand_desc; | ||
681 | struct acpi_namespace_node *node; | ||
682 | union acpi_parse_object *next_op; | ||
683 | |||
684 | |||
685 | ACPI_FUNCTION_TRACE_PTR ("ds_eval_region_operands", op); | ||
686 | |||
687 | |||
688 | /* | ||
689 | * This is where we evaluate the address and length fields of the op_region declaration | ||
690 | */ | ||
691 | node = op->common.node; | ||
692 | |||
693 | /* next_op points to the op that holds the space_iD */ | ||
694 | |||
695 | next_op = op->common.value.arg; | ||
696 | |||
697 | /* next_op points to address op */ | ||
698 | |||
699 | next_op = next_op->common.next; | ||
700 | |||
701 | /* Evaluate/create the address and length operands */ | ||
702 | |||
703 | status = acpi_ds_create_operands (walk_state, next_op); | ||
704 | if (ACPI_FAILURE (status)) { | ||
705 | return_ACPI_STATUS (status); | ||
706 | } | ||
707 | |||
708 | /* Resolve the length and address operands to numbers */ | ||
709 | |||
710 | status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); | ||
711 | if (ACPI_FAILURE (status)) { | ||
712 | return_ACPI_STATUS (status); | ||
713 | } | ||
714 | |||
715 | ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, | ||
716 | acpi_ps_get_opcode_name (op->common.aml_opcode), | ||
717 | 1, "after acpi_ex_resolve_operands"); | ||
718 | |||
719 | obj_desc = acpi_ns_get_attached_object (node); | ||
720 | if (!obj_desc) { | ||
721 | return_ACPI_STATUS (AE_NOT_EXIST); | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * Get the length operand and save it | ||
726 | * (at Top of stack) | ||
727 | */ | ||
728 | operand_desc = walk_state->operands[walk_state->num_operands - 1]; | ||
729 | |||
730 | obj_desc->region.length = (u32) operand_desc->integer.value; | ||
731 | acpi_ut_remove_reference (operand_desc); | ||
732 | |||
733 | /* | ||
734 | * Get the address and save it | ||
735 | * (at top of stack - 1) | ||
736 | */ | ||
737 | operand_desc = walk_state->operands[walk_state->num_operands - 2]; | ||
738 | |||
739 | obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value; | ||
740 | acpi_ut_remove_reference (operand_desc); | ||
741 | |||
742 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", | ||
743 | obj_desc, | ||
744 | ACPI_FORMAT_UINT64 (obj_desc->region.address), | ||
745 | obj_desc->region.length)); | ||
746 | |||
747 | /* Now the address and length are valid for this opregion */ | ||
748 | |||
749 | obj_desc->region.flags |= AOPOBJ_DATA_VALID; | ||
750 | |||
751 | return_ACPI_STATUS (status); | ||
752 | } | ||
753 | |||
754 | |||
755 | /***************************************************************************** | ||
756 | * | ||
757 | * FUNCTION: acpi_ds_eval_data_object_operands | ||
758 | * | ||
759 | * PARAMETERS: walk_state - Current walk | ||
760 | * Op - A valid data_object Op object | ||
761 | * obj_desc - data_object | ||
762 | * | ||
763 | * RETURN: Status | ||
764 | * | ||
765 | * DESCRIPTION: Get the operands and complete the following data object types: | ||
766 | * Buffer, Package. | ||
767 | * | ||
768 | ****************************************************************************/ | ||
769 | |||
770 | acpi_status | ||
771 | acpi_ds_eval_data_object_operands ( | ||
772 | struct acpi_walk_state *walk_state, | ||
773 | union acpi_parse_object *op, | ||
774 | union acpi_operand_object *obj_desc) | ||
775 | { | ||
776 | acpi_status status; | ||
777 | union acpi_operand_object *arg_desc; | ||
778 | u32 length; | ||
779 | |||
780 | |||
781 | ACPI_FUNCTION_TRACE ("ds_eval_data_object_operands"); | ||
782 | |||
783 | |||
784 | /* The first operand (for all of these data objects) is the length */ | ||
785 | |||
786 | status = acpi_ds_create_operand (walk_state, op->common.value.arg, 1); | ||
787 | if (ACPI_FAILURE (status)) { | ||
788 | return_ACPI_STATUS (status); | ||
789 | } | ||
790 | |||
791 | status = acpi_ex_resolve_operands (walk_state->opcode, | ||
792 | &(walk_state->operands [walk_state->num_operands -1]), | ||
793 | walk_state); | ||
794 | if (ACPI_FAILURE (status)) { | ||
795 | return_ACPI_STATUS (status); | ||
796 | } | ||
797 | |||
798 | /* Extract length operand */ | ||
799 | |||
800 | arg_desc = walk_state->operands [walk_state->num_operands - 1]; | ||
801 | length = (u32) arg_desc->integer.value; | ||
802 | |||
803 | /* Cleanup for length operand */ | ||
804 | |||
805 | status = acpi_ds_obj_stack_pop (1, walk_state); | ||
806 | if (ACPI_FAILURE (status)) { | ||
807 | return_ACPI_STATUS (status); | ||
808 | } | ||
809 | |||
810 | acpi_ut_remove_reference (arg_desc); | ||
811 | |||
812 | /* | ||
813 | * Create the actual data object | ||
814 | */ | ||
815 | switch (op->common.aml_opcode) { | ||
816 | case AML_BUFFER_OP: | ||
817 | |||
818 | status = acpi_ds_build_internal_buffer_obj (walk_state, op, length, &obj_desc); | ||
819 | break; | ||
820 | |||
821 | case AML_PACKAGE_OP: | ||
822 | case AML_VAR_PACKAGE_OP: | ||
823 | |||
824 | status = acpi_ds_build_internal_package_obj (walk_state, op, length, &obj_desc); | ||
825 | break; | ||
826 | |||
827 | default: | ||
828 | return_ACPI_STATUS (AE_AML_BAD_OPCODE); | ||
829 | } | ||
830 | |||
831 | if (ACPI_SUCCESS (status)) { | ||
832 | /* | ||
833 | * Return the object in the walk_state, unless the parent is a package -- | ||
834 | * in this case, the return object will be stored in the parse tree | ||
835 | * for the package. | ||
836 | */ | ||
837 | if ((!op->common.parent) || | ||
838 | ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && | ||
839 | (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) && | ||
840 | (op->common.parent->common.aml_opcode != AML_NAME_OP))) { | ||
841 | walk_state->result_obj = obj_desc; | ||
842 | } | ||
843 | } | ||
844 | |||
845 | return_ACPI_STATUS (status); | ||
846 | } | ||
847 | |||
848 | |||
849 | /******************************************************************************* | ||
850 | * | ||
851 | * FUNCTION: acpi_ds_exec_begin_control_op | ||
852 | * | ||
853 | * PARAMETERS: walk_list - The list that owns the walk stack | ||
854 | * Op - The control Op | ||
855 | * | ||
856 | * RETURN: Status | ||
857 | * | ||
858 | * DESCRIPTION: Handles all control ops encountered during control method | ||
859 | * execution. | ||
860 | * | ||
861 | ******************************************************************************/ | ||
862 | |||
863 | acpi_status | ||
864 | acpi_ds_exec_begin_control_op ( | ||
865 | struct acpi_walk_state *walk_state, | ||
866 | union acpi_parse_object *op) | ||
867 | { | ||
868 | acpi_status status = AE_OK; | ||
869 | union acpi_generic_state *control_state; | ||
870 | |||
871 | |||
872 | ACPI_FUNCTION_NAME ("ds_exec_begin_control_op"); | ||
873 | |||
874 | |||
875 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op, | ||
876 | op->common.aml_opcode, walk_state)); | ||
877 | |||
878 | switch (op->common.aml_opcode) { | ||
879 | case AML_IF_OP: | ||
880 | case AML_WHILE_OP: | ||
881 | |||
882 | /* | ||
883 | * IF/WHILE: Create a new control state to manage these | ||
884 | * constructs. We need to manage these as a stack, in order | ||
885 | * to handle nesting. | ||
886 | */ | ||
887 | control_state = acpi_ut_create_control_state (); | ||
888 | if (!control_state) { | ||
889 | status = AE_NO_MEMORY; | ||
890 | break; | ||
891 | } | ||
892 | /* | ||
893 | * Save a pointer to the predicate for multiple executions | ||
894 | * of a loop | ||
895 | */ | ||
896 | control_state->control.aml_predicate_start = walk_state->parser_state.aml - 1; | ||
897 | control_state->control.package_end = walk_state->parser_state.pkg_end; | ||
898 | control_state->control.opcode = op->common.aml_opcode; | ||
899 | |||
900 | |||
901 | /* Push the control state on this walk's control stack */ | ||
902 | |||
903 | acpi_ut_push_generic_state (&walk_state->control_state, control_state); | ||
904 | break; | ||
905 | |||
906 | case AML_ELSE_OP: | ||
907 | |||
908 | /* Predicate is in the state object */ | ||
909 | /* If predicate is true, the IF was executed, ignore ELSE part */ | ||
910 | |||
911 | if (walk_state->last_predicate) { | ||
912 | status = AE_CTRL_TRUE; | ||
913 | } | ||
914 | |||
915 | break; | ||
916 | |||
917 | case AML_RETURN_OP: | ||
918 | |||
919 | break; | ||
920 | |||
921 | default: | ||
922 | break; | ||
923 | } | ||
924 | |||
925 | return (status); | ||
926 | } | ||
927 | |||
928 | |||
929 | /******************************************************************************* | ||
930 | * | ||
931 | * FUNCTION: acpi_ds_exec_end_control_op | ||
932 | * | ||
933 | * PARAMETERS: walk_list - The list that owns the walk stack | ||
934 | * Op - The control Op | ||
935 | * | ||
936 | * RETURN: Status | ||
937 | * | ||
938 | * DESCRIPTION: Handles all control ops encountered during control method | ||
939 | * execution. | ||
940 | * | ||
941 | ******************************************************************************/ | ||
942 | |||
943 | acpi_status | ||
944 | acpi_ds_exec_end_control_op ( | ||
945 | struct acpi_walk_state *walk_state, | ||
946 | union acpi_parse_object *op) | ||
947 | { | ||
948 | acpi_status status = AE_OK; | ||
949 | union acpi_generic_state *control_state; | ||
950 | |||
951 | |||
952 | ACPI_FUNCTION_NAME ("ds_exec_end_control_op"); | ||
953 | |||
954 | |||
955 | switch (op->common.aml_opcode) { | ||
956 | case AML_IF_OP: | ||
957 | |||
958 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); | ||
959 | |||
960 | /* | ||
961 | * Save the result of the predicate in case there is an | ||
962 | * ELSE to come | ||
963 | */ | ||
964 | walk_state->last_predicate = | ||
965 | (u8) walk_state->control_state->common.value; | ||
966 | |||
967 | /* | ||
968 | * Pop the control state that was created at the start | ||
969 | * of the IF and free it | ||
970 | */ | ||
971 | control_state = acpi_ut_pop_generic_state (&walk_state->control_state); | ||
972 | acpi_ut_delete_generic_state (control_state); | ||
973 | break; | ||
974 | |||
975 | |||
976 | case AML_ELSE_OP: | ||
977 | |||
978 | break; | ||
979 | |||
980 | |||
981 | case AML_WHILE_OP: | ||
982 | |||
983 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); | ||
984 | |||
985 | if (walk_state->control_state->common.value) { | ||
986 | /* Predicate was true, go back and evaluate it again! */ | ||
987 | |||
988 | status = AE_CTRL_PENDING; | ||
989 | } | ||
990 | |||
991 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); | ||
992 | |||
993 | /* Pop this control state and free it */ | ||
994 | |||
995 | control_state = acpi_ut_pop_generic_state (&walk_state->control_state); | ||
996 | |||
997 | walk_state->aml_last_while = control_state->control.aml_predicate_start; | ||
998 | acpi_ut_delete_generic_state (control_state); | ||
999 | break; | ||
1000 | |||
1001 | |||
1002 | case AML_RETURN_OP: | ||
1003 | |||
1004 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
1005 | "[RETURN_OP] Op=%p Arg=%p\n",op, op->common.value.arg)); | ||
1006 | |||
1007 | /* | ||
1008 | * One optional operand -- the return value | ||
1009 | * It can be either an immediate operand or a result that | ||
1010 | * has been bubbled up the tree | ||
1011 | */ | ||
1012 | if (op->common.value.arg) { | ||
1013 | /* Since we have a real Return(), delete any implicit return */ | ||
1014 | |||
1015 | acpi_ds_clear_implicit_return (walk_state); | ||
1016 | |||
1017 | /* Return statement has an immediate operand */ | ||
1018 | |||
1019 | status = acpi_ds_create_operands (walk_state, op->common.value.arg); | ||
1020 | if (ACPI_FAILURE (status)) { | ||
1021 | return (status); | ||
1022 | } | ||
1023 | |||
1024 | /* | ||
1025 | * If value being returned is a Reference (such as | ||
1026 | * an arg or local), resolve it now because it may | ||
1027 | * cease to exist at the end of the method. | ||
1028 | */ | ||
1029 | status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state); | ||
1030 | if (ACPI_FAILURE (status)) { | ||
1031 | return (status); | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * Get the return value and save as the last result | ||
1036 | * value. This is the only place where walk_state->return_desc | ||
1037 | * is set to anything other than zero! | ||
1038 | */ | ||
1039 | walk_state->return_desc = walk_state->operands[0]; | ||
1040 | } | ||
1041 | else if ((walk_state->results) && | ||
1042 | (walk_state->results->results.num_results > 0)) { | ||
1043 | /* Since we have a real Return(), delete any implicit return */ | ||
1044 | |||
1045 | acpi_ds_clear_implicit_return (walk_state); | ||
1046 | |||
1047 | /* | ||
1048 | * The return value has come from a previous calculation. | ||
1049 | * | ||
1050 | * If value being returned is a Reference (such as | ||
1051 | * an arg or local), resolve it now because it may | ||
1052 | * cease to exist at the end of the method. | ||
1053 | * | ||
1054 | * Allow references created by the Index operator to return unchanged. | ||
1055 | */ | ||
1056 | if ((ACPI_GET_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc[0]) == ACPI_DESC_TYPE_OPERAND) && | ||
1057 | (ACPI_GET_OBJECT_TYPE (walk_state->results->results.obj_desc [0]) == ACPI_TYPE_LOCAL_REFERENCE) && | ||
1058 | ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) { | ||
1059 | status = acpi_ex_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); | ||
1060 | if (ACPI_FAILURE (status)) { | ||
1061 | return (status); | ||
1062 | } | ||
1063 | } | ||
1064 | |||
1065 | walk_state->return_desc = walk_state->results->results.obj_desc [0]; | ||
1066 | } | ||
1067 | else { | ||
1068 | /* No return operand */ | ||
1069 | |||
1070 | if (walk_state->num_operands) { | ||
1071 | acpi_ut_remove_reference (walk_state->operands [0]); | ||
1072 | } | ||
1073 | |||
1074 | walk_state->operands [0] = NULL; | ||
1075 | walk_state->num_operands = 0; | ||
1076 | walk_state->return_desc = NULL; | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
1081 | "Completed RETURN_OP State=%p, ret_val=%p\n", | ||
1082 | walk_state, walk_state->return_desc)); | ||
1083 | |||
1084 | /* End the control method execution right now */ | ||
1085 | |||
1086 | status = AE_CTRL_TERMINATE; | ||
1087 | break; | ||
1088 | |||
1089 | |||
1090 | case AML_NOOP_OP: | ||
1091 | |||
1092 | /* Just do nothing! */ | ||
1093 | break; | ||
1094 | |||
1095 | |||
1096 | case AML_BREAK_POINT_OP: | ||
1097 | |||
1098 | /* Call up to the OS service layer to handle this */ | ||
1099 | |||
1100 | status = acpi_os_signal (ACPI_SIGNAL_BREAKPOINT, "Executed AML Breakpoint opcode"); | ||
1101 | |||
1102 | /* If and when it returns, all done. */ | ||
1103 | |||
1104 | break; | ||
1105 | |||
1106 | |||
1107 | case AML_BREAK_OP: | ||
1108 | case AML_CONTINUE_OP: /* ACPI 2.0 */ | ||
1109 | |||
1110 | |||
1111 | /* Pop and delete control states until we find a while */ | ||
1112 | |||
1113 | while (walk_state->control_state && | ||
1114 | (walk_state->control_state->control.opcode != AML_WHILE_OP)) { | ||
1115 | control_state = acpi_ut_pop_generic_state (&walk_state->control_state); | ||
1116 | acpi_ut_delete_generic_state (control_state); | ||
1117 | } | ||
1118 | |||
1119 | /* No while found? */ | ||
1120 | |||
1121 | if (!walk_state->control_state) { | ||
1122 | return (AE_AML_NO_WHILE); | ||
1123 | } | ||
1124 | |||
1125 | /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */ | ||
1126 | |||
1127 | walk_state->aml_last_while = walk_state->control_state->control.package_end; | ||
1128 | |||
1129 | /* Return status depending on opcode */ | ||
1130 | |||
1131 | if (op->common.aml_opcode == AML_BREAK_OP) { | ||
1132 | status = AE_CTRL_BREAK; | ||
1133 | } | ||
1134 | else { | ||
1135 | status = AE_CTRL_CONTINUE; | ||
1136 | } | ||
1137 | break; | ||
1138 | |||
1139 | |||
1140 | default: | ||
1141 | |||
1142 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown control opcode=%X Op=%p\n", | ||
1143 | op->common.aml_opcode, op)); | ||
1144 | |||
1145 | status = AE_AML_BAD_OPCODE; | ||
1146 | break; | ||
1147 | } | ||
1148 | |||
1149 | return (status); | ||
1150 | } | ||
1151 | |||
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c new file mode 100644 index 000000000000..462c5d83e747 --- /dev/null +++ b/drivers/acpi/dispatcher/dsutils.c | |||
@@ -0,0 +1,744 @@ | |||
1 | /******************************************************************************* | ||
2 | * | ||
3 | * Module Name: dsutils - Dispatcher utilities | ||
4 | * | ||
5 | ******************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acparser.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | #include <acpi/acnamesp.h> | ||
51 | #include <acpi/acdebug.h> | ||
52 | |||
53 | #define _COMPONENT ACPI_DISPATCHER | ||
54 | ACPI_MODULE_NAME ("dsutils") | ||
55 | |||
56 | |||
57 | /******************************************************************************* | ||
58 | * | ||
59 | * FUNCTION: acpi_ds_clear_implicit_return | ||
60 | * | ||
61 | * PARAMETERS: walk_state - Current State | ||
62 | * | ||
63 | * RETURN: None. | ||
64 | * | ||
65 | * DESCRIPTION: Clear and remove a reference on an implicit return value. Used | ||
66 | * to delete "stale" return values (if enabled, the return value | ||
67 | * from every operator is saved at least momentarily, in case the | ||
68 | * parent method exits.) | ||
69 | * | ||
70 | ******************************************************************************/ | ||
71 | |||
72 | void | ||
73 | acpi_ds_clear_implicit_return ( | ||
74 | struct acpi_walk_state *walk_state) | ||
75 | { | ||
76 | ACPI_FUNCTION_NAME ("ds_clear_implicit_return"); | ||
77 | |||
78 | |||
79 | /* | ||
80 | * Slack must be enabled for this feature | ||
81 | */ | ||
82 | if (!acpi_gbl_enable_interpreter_slack) { | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | if (walk_state->implicit_return_obj) { | ||
87 | /* | ||
88 | * Delete any "stale" implicit return. However, in | ||
89 | * complex statements, the implicit return value can be | ||
90 | * bubbled up several levels. | ||
91 | */ | ||
92 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
93 | "Removing reference on stale implicit return obj %p\n", | ||
94 | walk_state->implicit_return_obj)); | ||
95 | |||
96 | acpi_ut_remove_reference (walk_state->implicit_return_obj); | ||
97 | walk_state->implicit_return_obj = NULL; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
103 | |||
104 | /******************************************************************************* | ||
105 | * | ||
106 | * FUNCTION: acpi_ds_do_implicit_return | ||
107 | * | ||
108 | * PARAMETERS: return_desc - The return value | ||
109 | * walk_state - Current State | ||
110 | * add_reference - True if a reference should be added to the | ||
111 | * return object | ||
112 | * | ||
113 | * RETURN: TRUE if implicit return enabled, FALSE otherwise | ||
114 | * | ||
115 | * DESCRIPTION: Implements the optional "implicit return". We save the result | ||
116 | * of every ASL operator and control method invocation in case the | ||
117 | * parent method exit. Before storing a new return value, we | ||
118 | * delete the previous return value. | ||
119 | * | ||
120 | ******************************************************************************/ | ||
121 | |||
122 | u8 | ||
123 | acpi_ds_do_implicit_return ( | ||
124 | union acpi_operand_object *return_desc, | ||
125 | struct acpi_walk_state *walk_state, | ||
126 | u8 add_reference) | ||
127 | { | ||
128 | ACPI_FUNCTION_NAME ("ds_do_implicit_return"); | ||
129 | |||
130 | |||
131 | /* | ||
132 | * Slack must be enabled for this feature, and we must | ||
133 | * have a valid return object | ||
134 | */ | ||
135 | if ((!acpi_gbl_enable_interpreter_slack) || | ||
136 | (!return_desc)) { | ||
137 | return (FALSE); | ||
138 | } | ||
139 | |||
140 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
141 | "Result %p will be implicitly returned; Prev=%p\n", | ||
142 | return_desc, | ||
143 | walk_state->implicit_return_obj)); | ||
144 | |||
145 | /* | ||
146 | * Delete any "stale" implicit return value first. However, in | ||
147 | * complex statements, the implicit return value can be | ||
148 | * bubbled up several levels, so we don't clear the value if it | ||
149 | * is the same as the return_desc. | ||
150 | */ | ||
151 | if (walk_state->implicit_return_obj) { | ||
152 | if (walk_state->implicit_return_obj == return_desc) { | ||
153 | return (TRUE); | ||
154 | } | ||
155 | acpi_ds_clear_implicit_return (walk_state); | ||
156 | } | ||
157 | |||
158 | /* Save the implicit return value, add a reference if requested */ | ||
159 | |||
160 | walk_state->implicit_return_obj = return_desc; | ||
161 | if (add_reference) { | ||
162 | acpi_ut_add_reference (return_desc); | ||
163 | } | ||
164 | |||
165 | return (TRUE); | ||
166 | } | ||
167 | |||
168 | |||
169 | /******************************************************************************* | ||
170 | * | ||
171 | * FUNCTION: acpi_ds_is_result_used | ||
172 | * | ||
173 | * PARAMETERS: Op - Current Op | ||
174 | * walk_state - Current State | ||
175 | * | ||
176 | * RETURN: TRUE if result is used, FALSE otherwise | ||
177 | * | ||
178 | * DESCRIPTION: Check if a result object will be used by the parent | ||
179 | * | ||
180 | ******************************************************************************/ | ||
181 | |||
182 | u8 | ||
183 | acpi_ds_is_result_used ( | ||
184 | union acpi_parse_object *op, | ||
185 | struct acpi_walk_state *walk_state) | ||
186 | { | ||
187 | const struct acpi_opcode_info *parent_info; | ||
188 | |||
189 | ACPI_FUNCTION_TRACE_PTR ("ds_is_result_used", op); | ||
190 | |||
191 | |||
192 | /* Must have both an Op and a Result Object */ | ||
193 | |||
194 | if (!op) { | ||
195 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n")); | ||
196 | return_VALUE (TRUE); | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * We know that this operator is not a | ||
201 | * Return() operator (would not come here.) The following code is the | ||
202 | * optional support for a so-called "implicit return". Some AML code | ||
203 | * assumes that the last value of the method is "implicitly" returned | ||
204 | * to the caller. Just save the last result as the return value. | ||
205 | * NOTE: this is optional because the ASL language does not actually | ||
206 | * support this behavior. | ||
207 | */ | ||
208 | acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); | ||
209 | |||
210 | /* | ||
211 | * Now determine if the parent will use the result | ||
212 | * | ||
213 | * If there is no parent, or the parent is a scope_op, we are executing | ||
214 | * at the method level. An executing method typically has no parent, | ||
215 | * since each method is parsed separately. A method invoked externally | ||
216 | * via execute_control_method has a scope_op as the parent. | ||
217 | */ | ||
218 | if ((!op->common.parent) || | ||
219 | (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { | ||
220 | /* No parent, the return value cannot possibly be used */ | ||
221 | |||
222 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n", | ||
223 | acpi_ps_get_opcode_name (op->common.aml_opcode))); | ||
224 | return_VALUE (FALSE); | ||
225 | } | ||
226 | |||
227 | /* Get info on the parent. The root_op is AML_SCOPE */ | ||
228 | |||
229 | parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); | ||
230 | if (parent_info->class == AML_CLASS_UNKNOWN) { | ||
231 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); | ||
232 | return_VALUE (FALSE); | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Decide what to do with the result based on the parent. If | ||
237 | * the parent opcode will not use the result, delete the object. | ||
238 | * Otherwise leave it as is, it will be deleted when it is used | ||
239 | * as an operand later. | ||
240 | */ | ||
241 | switch (parent_info->class) { | ||
242 | case AML_CLASS_CONTROL: | ||
243 | |||
244 | switch (op->common.parent->common.aml_opcode) { | ||
245 | case AML_RETURN_OP: | ||
246 | |||
247 | /* Never delete the return value associated with a return opcode */ | ||
248 | |||
249 | goto result_used; | ||
250 | |||
251 | case AML_IF_OP: | ||
252 | case AML_WHILE_OP: | ||
253 | |||
254 | /* | ||
255 | * If we are executing the predicate AND this is the predicate op, | ||
256 | * we will use the return value | ||
257 | */ | ||
258 | if ((walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING) && | ||
259 | (walk_state->control_state->control.predicate_op == op)) { | ||
260 | goto result_used; | ||
261 | } | ||
262 | break; | ||
263 | |||
264 | default: | ||
265 | /* Ignore other control opcodes */ | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | /* The general control opcode returns no result */ | ||
270 | |||
271 | goto result_not_used; | ||
272 | |||
273 | |||
274 | case AML_CLASS_CREATE: | ||
275 | |||
276 | /* | ||
277 | * These opcodes allow term_arg(s) as operands and therefore | ||
278 | * the operands can be method calls. The result is used. | ||
279 | */ | ||
280 | goto result_used; | ||
281 | |||
282 | |||
283 | case AML_CLASS_NAMED_OBJECT: | ||
284 | |||
285 | if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || | ||
286 | (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || | ||
287 | (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || | ||
288 | (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || | ||
289 | (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || | ||
290 | (op->common.parent->common.aml_opcode == AML_INT_EVAL_SUBTREE_OP)) { | ||
291 | /* | ||
292 | * These opcodes allow term_arg(s) as operands and therefore | ||
293 | * the operands can be method calls. The result is used. | ||
294 | */ | ||
295 | goto result_used; | ||
296 | } | ||
297 | |||
298 | goto result_not_used; | ||
299 | |||
300 | |||
301 | default: | ||
302 | |||
303 | /* | ||
304 | * In all other cases. the parent will actually use the return | ||
305 | * object, so keep it. | ||
306 | */ | ||
307 | goto result_used; | ||
308 | } | ||
309 | |||
310 | |||
311 | result_used: | ||
312 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", | ||
313 | acpi_ps_get_opcode_name (op->common.aml_opcode), | ||
314 | acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); | ||
315 | |||
316 | return_VALUE (TRUE); | ||
317 | |||
318 | |||
319 | result_not_used: | ||
320 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", | ||
321 | acpi_ps_get_opcode_name (op->common.aml_opcode), | ||
322 | acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); | ||
323 | |||
324 | return_VALUE (FALSE); | ||
325 | } | ||
326 | |||
327 | |||
328 | /******************************************************************************* | ||
329 | * | ||
330 | * FUNCTION: acpi_ds_delete_result_if_not_used | ||
331 | * | ||
332 | * PARAMETERS: Op - Current parse Op | ||
333 | * result_obj - Result of the operation | ||
334 | * walk_state - Current state | ||
335 | * | ||
336 | * RETURN: Status | ||
337 | * | ||
338 | * DESCRIPTION: Used after interpretation of an opcode. If there is an internal | ||
339 | * result descriptor, check if the parent opcode will actually use | ||
340 | * this result. If not, delete the result now so that it will | ||
341 | * not become orphaned. | ||
342 | * | ||
343 | ******************************************************************************/ | ||
344 | |||
345 | void | ||
346 | acpi_ds_delete_result_if_not_used ( | ||
347 | union acpi_parse_object *op, | ||
348 | union acpi_operand_object *result_obj, | ||
349 | struct acpi_walk_state *walk_state) | ||
350 | { | ||
351 | union acpi_operand_object *obj_desc; | ||
352 | acpi_status status; | ||
353 | |||
354 | |||
355 | ACPI_FUNCTION_TRACE_PTR ("ds_delete_result_if_not_used", result_obj); | ||
356 | |||
357 | |||
358 | if (!op) { | ||
359 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n")); | ||
360 | return_VOID; | ||
361 | } | ||
362 | |||
363 | if (!result_obj) { | ||
364 | return_VOID; | ||
365 | } | ||
366 | |||
367 | if (!acpi_ds_is_result_used (op, walk_state)) { | ||
368 | /* Must pop the result stack (obj_desc should be equal to result_obj) */ | ||
369 | |||
370 | status = acpi_ds_result_pop (&obj_desc, walk_state); | ||
371 | if (ACPI_SUCCESS (status)) { | ||
372 | acpi_ut_remove_reference (result_obj); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | return_VOID; | ||
377 | } | ||
378 | |||
379 | |||
380 | /******************************************************************************* | ||
381 | * | ||
382 | * FUNCTION: acpi_ds_resolve_operands | ||
383 | * | ||
384 | * PARAMETERS: walk_state - Current walk state with operands on stack | ||
385 | * | ||
386 | * RETURN: Status | ||
387 | * | ||
388 | * DESCRIPTION: Resolve all operands to their values. Used to prepare | ||
389 | * arguments to a control method invocation (a call from one | ||
390 | * method to another.) | ||
391 | * | ||
392 | ******************************************************************************/ | ||
393 | |||
394 | acpi_status | ||
395 | acpi_ds_resolve_operands ( | ||
396 | struct acpi_walk_state *walk_state) | ||
397 | { | ||
398 | u32 i; | ||
399 | acpi_status status = AE_OK; | ||
400 | |||
401 | |||
402 | ACPI_FUNCTION_TRACE_PTR ("ds_resolve_operands", walk_state); | ||
403 | |||
404 | |||
405 | /* | ||
406 | * Attempt to resolve each of the valid operands | ||
407 | * Method arguments are passed by reference, not by value. This means | ||
408 | * that the actual objects are passed, not copies of the objects. | ||
409 | */ | ||
410 | for (i = 0; i < walk_state->num_operands; i++) { | ||
411 | status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); | ||
412 | if (ACPI_FAILURE (status)) { | ||
413 | break; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | return_ACPI_STATUS (status); | ||
418 | } | ||
419 | |||
420 | |||
421 | /******************************************************************************* | ||
422 | * | ||
423 | * FUNCTION: acpi_ds_clear_operands | ||
424 | * | ||
425 | * PARAMETERS: walk_state - Current walk state with operands on stack | ||
426 | * | ||
427 | * RETURN: None | ||
428 | * | ||
429 | * DESCRIPTION: Clear all operands on the current walk state operand stack. | ||
430 | * | ||
431 | ******************************************************************************/ | ||
432 | |||
433 | void | ||
434 | acpi_ds_clear_operands ( | ||
435 | struct acpi_walk_state *walk_state) | ||
436 | { | ||
437 | u32 i; | ||
438 | |||
439 | |||
440 | ACPI_FUNCTION_TRACE_PTR ("ds_clear_operands", walk_state); | ||
441 | |||
442 | |||
443 | /* Remove a reference on each operand on the stack */ | ||
444 | |||
445 | for (i = 0; i < walk_state->num_operands; i++) { | ||
446 | /* | ||
447 | * Remove a reference to all operands, including both | ||
448 | * "Arguments" and "Targets". | ||
449 | */ | ||
450 | acpi_ut_remove_reference (walk_state->operands[i]); | ||
451 | walk_state->operands[i] = NULL; | ||
452 | } | ||
453 | |||
454 | walk_state->num_operands = 0; | ||
455 | return_VOID; | ||
456 | } | ||
457 | #endif | ||
458 | |||
459 | |||
460 | /******************************************************************************* | ||
461 | * | ||
462 | * FUNCTION: acpi_ds_create_operand | ||
463 | * | ||
464 | * PARAMETERS: walk_state - Current walk state | ||
465 | * Arg - Parse object for the argument | ||
466 | * arg_index - Which argument (zero based) | ||
467 | * | ||
468 | * RETURN: Status | ||
469 | * | ||
470 | * DESCRIPTION: Translate a parse tree object that is an argument to an AML | ||
471 | * opcode to the equivalent interpreter object. This may include | ||
472 | * looking up a name or entering a new name into the internal | ||
473 | * namespace. | ||
474 | * | ||
475 | ******************************************************************************/ | ||
476 | |||
477 | acpi_status | ||
478 | acpi_ds_create_operand ( | ||
479 | struct acpi_walk_state *walk_state, | ||
480 | union acpi_parse_object *arg, | ||
481 | u32 arg_index) | ||
482 | { | ||
483 | acpi_status status = AE_OK; | ||
484 | char *name_string; | ||
485 | u32 name_length; | ||
486 | union acpi_operand_object *obj_desc; | ||
487 | union acpi_parse_object *parent_op; | ||
488 | u16 opcode; | ||
489 | acpi_interpreter_mode interpreter_mode; | ||
490 | const struct acpi_opcode_info *op_info; | ||
491 | |||
492 | |||
493 | ACPI_FUNCTION_TRACE_PTR ("ds_create_operand", arg); | ||
494 | |||
495 | |||
496 | /* A valid name must be looked up in the namespace */ | ||
497 | |||
498 | if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && | ||
499 | (arg->common.value.string)) { | ||
500 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg)); | ||
501 | |||
502 | /* Get the entire name string from the AML stream */ | ||
503 | |||
504 | status = acpi_ex_get_name_string (ACPI_TYPE_ANY, arg->common.value.buffer, | ||
505 | &name_string, &name_length); | ||
506 | |||
507 | if (ACPI_FAILURE (status)) { | ||
508 | return_ACPI_STATUS (status); | ||
509 | } | ||
510 | |||
511 | /* All prefixes have been handled, and the name is in name_string */ | ||
512 | |||
513 | /* | ||
514 | * Special handling for buffer_field declarations. This is a deferred | ||
515 | * opcode that unfortunately defines the field name as the last | ||
516 | * parameter instead of the first. We get here when we are performing | ||
517 | * the deferred execution, so the actual name of the field is already | ||
518 | * in the namespace. We don't want to attempt to look it up again | ||
519 | * because we may be executing in a different scope than where the | ||
520 | * actual opcode exists. | ||
521 | */ | ||
522 | if ((walk_state->deferred_node) && | ||
523 | (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) && | ||
524 | (arg_index != 0)) { | ||
525 | obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node); | ||
526 | status = AE_OK; | ||
527 | } | ||
528 | else /* All other opcodes */ { | ||
529 | /* | ||
530 | * Differentiate between a namespace "create" operation | ||
531 | * versus a "lookup" operation (IMODE_LOAD_PASS2 vs. | ||
532 | * IMODE_EXECUTE) in order to support the creation of | ||
533 | * namespace objects during the execution of control methods. | ||
534 | */ | ||
535 | parent_op = arg->common.parent; | ||
536 | op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode); | ||
537 | if ((op_info->flags & AML_NSNODE) && | ||
538 | (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) && | ||
539 | (parent_op->common.aml_opcode != AML_REGION_OP) && | ||
540 | (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) { | ||
541 | /* Enter name into namespace if not found */ | ||
542 | |||
543 | interpreter_mode = ACPI_IMODE_LOAD_PASS2; | ||
544 | } | ||
545 | else { | ||
546 | /* Return a failure if name not found */ | ||
547 | |||
548 | interpreter_mode = ACPI_IMODE_EXECUTE; | ||
549 | } | ||
550 | |||
551 | status = acpi_ns_lookup (walk_state->scope_info, name_string, | ||
552 | ACPI_TYPE_ANY, interpreter_mode, | ||
553 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, | ||
554 | walk_state, | ||
555 | ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &obj_desc)); | ||
556 | /* | ||
557 | * The only case where we pass through (ignore) a NOT_FOUND | ||
558 | * error is for the cond_ref_of opcode. | ||
559 | */ | ||
560 | if (status == AE_NOT_FOUND) { | ||
561 | if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) { | ||
562 | /* | ||
563 | * For the Conditional Reference op, it's OK if | ||
564 | * the name is not found; We just need a way to | ||
565 | * indicate this to the interpreter, set the | ||
566 | * object to the root | ||
567 | */ | ||
568 | obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node); | ||
569 | status = AE_OK; | ||
570 | } | ||
571 | else { | ||
572 | /* | ||
573 | * We just plain didn't find it -- which is a | ||
574 | * very serious error at this point | ||
575 | */ | ||
576 | status = AE_AML_NAME_NOT_FOUND; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | if (ACPI_FAILURE (status)) { | ||
581 | ACPI_REPORT_NSERROR (name_string, status); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /* Free the namestring created above */ | ||
586 | |||
587 | ACPI_MEM_FREE (name_string); | ||
588 | |||
589 | /* Check status from the lookup */ | ||
590 | |||
591 | if (ACPI_FAILURE (status)) { | ||
592 | return_ACPI_STATUS (status); | ||
593 | } | ||
594 | |||
595 | /* Put the resulting object onto the current object stack */ | ||
596 | |||
597 | status = acpi_ds_obj_stack_push (obj_desc, walk_state); | ||
598 | if (ACPI_FAILURE (status)) { | ||
599 | return_ACPI_STATUS (status); | ||
600 | } | ||
601 | ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); | ||
602 | } | ||
603 | else { | ||
604 | /* Check for null name case */ | ||
605 | |||
606 | if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) { | ||
607 | /* | ||
608 | * If the name is null, this means that this is an | ||
609 | * optional result parameter that was not specified | ||
610 | * in the original ASL. Create a Zero Constant for a | ||
611 | * placeholder. (Store to a constant is a Noop.) | ||
612 | */ | ||
613 | opcode = AML_ZERO_OP; /* Has no arguments! */ | ||
614 | |||
615 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg)); | ||
616 | } | ||
617 | else { | ||
618 | opcode = arg->common.aml_opcode; | ||
619 | } | ||
620 | |||
621 | /* Get the object type of the argument */ | ||
622 | |||
623 | op_info = acpi_ps_get_opcode_info (opcode); | ||
624 | if (op_info->object_type == ACPI_TYPE_INVALID) { | ||
625 | return_ACPI_STATUS (AE_NOT_IMPLEMENTED); | ||
626 | } | ||
627 | |||
628 | if (op_info->flags & AML_HAS_RETVAL) { | ||
629 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
630 | "Argument previously created, already stacked \n")); | ||
631 | |||
632 | ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object ( | ||
633 | walk_state->operands [walk_state->num_operands - 1], walk_state)); | ||
634 | |||
635 | /* | ||
636 | * Use value that was already previously returned | ||
637 | * by the evaluation of this argument | ||
638 | */ | ||
639 | status = acpi_ds_result_pop_from_bottom (&obj_desc, walk_state); | ||
640 | if (ACPI_FAILURE (status)) { | ||
641 | /* | ||
642 | * Only error is underflow, and this indicates | ||
643 | * a missing or null operand! | ||
644 | */ | ||
645 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n", | ||
646 | acpi_format_exception (status))); | ||
647 | return_ACPI_STATUS (status); | ||
648 | } | ||
649 | } | ||
650 | else { | ||
651 | /* Create an ACPI_INTERNAL_OBJECT for the argument */ | ||
652 | |||
653 | obj_desc = acpi_ut_create_internal_object (op_info->object_type); | ||
654 | if (!obj_desc) { | ||
655 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
656 | } | ||
657 | |||
658 | /* Initialize the new object */ | ||
659 | |||
660 | status = acpi_ds_init_object_from_op (walk_state, arg, | ||
661 | opcode, &obj_desc); | ||
662 | if (ACPI_FAILURE (status)) { | ||
663 | acpi_ut_delete_object_desc (obj_desc); | ||
664 | return_ACPI_STATUS (status); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | /* Put the operand object on the object stack */ | ||
669 | |||
670 | status = acpi_ds_obj_stack_push (obj_desc, walk_state); | ||
671 | if (ACPI_FAILURE (status)) { | ||
672 | return_ACPI_STATUS (status); | ||
673 | } | ||
674 | |||
675 | ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); | ||
676 | } | ||
677 | |||
678 | return_ACPI_STATUS (AE_OK); | ||
679 | } | ||
680 | |||
681 | |||
682 | /******************************************************************************* | ||
683 | * | ||
684 | * FUNCTION: acpi_ds_create_operands | ||
685 | * | ||
686 | * PARAMETERS: walk_state - Current state | ||
687 | * first_arg - First argument of a parser argument tree | ||
688 | * | ||
689 | * RETURN: Status | ||
690 | * | ||
691 | * DESCRIPTION: Convert an operator's arguments from a parse tree format to | ||
692 | * namespace objects and place those argument object on the object | ||
693 | * stack in preparation for evaluation by the interpreter. | ||
694 | * | ||
695 | ******************************************************************************/ | ||
696 | |||
697 | acpi_status | ||
698 | acpi_ds_create_operands ( | ||
699 | struct acpi_walk_state *walk_state, | ||
700 | union acpi_parse_object *first_arg) | ||
701 | { | ||
702 | acpi_status status = AE_OK; | ||
703 | union acpi_parse_object *arg; | ||
704 | u32 arg_count = 0; | ||
705 | |||
706 | |||
707 | ACPI_FUNCTION_TRACE_PTR ("ds_create_operands", first_arg); | ||
708 | |||
709 | |||
710 | /* For all arguments in the list... */ | ||
711 | |||
712 | arg = first_arg; | ||
713 | while (arg) { | ||
714 | status = acpi_ds_create_operand (walk_state, arg, arg_count); | ||
715 | if (ACPI_FAILURE (status)) { | ||
716 | goto cleanup; | ||
717 | } | ||
718 | |||
719 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Arg #%d (%p) done, Arg1=%p\n", | ||
720 | arg_count, arg, first_arg)); | ||
721 | |||
722 | /* Move on to next argument, if any */ | ||
723 | |||
724 | arg = arg->common.next; | ||
725 | arg_count++; | ||
726 | } | ||
727 | |||
728 | return_ACPI_STATUS (status); | ||
729 | |||
730 | |||
731 | cleanup: | ||
732 | /* | ||
733 | * We must undo everything done above; meaning that we must | ||
734 | * pop everything off of the operand stack and delete those | ||
735 | * objects | ||
736 | */ | ||
737 | (void) acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state); | ||
738 | |||
739 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While creating Arg %d - %s\n", | ||
740 | (arg_count + 1), acpi_format_exception (status))); | ||
741 | return_ACPI_STATUS (status); | ||
742 | } | ||
743 | |||
744 | |||
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c new file mode 100644 index 000000000000..2071a0d2bbbb --- /dev/null +++ b/drivers/acpi/dispatcher/dswexec.c | |||
@@ -0,0 +1,751 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dswexec - Dispatcher method execution callbacks; | ||
4 | * dispatch to interpreter. | ||
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/acparser.h> | ||
48 | #include <acpi/amlcode.h> | ||
49 | #include <acpi/acdispat.h> | ||
50 | #include <acpi/acinterp.h> | ||
51 | #include <acpi/acnamesp.h> | ||
52 | #include <acpi/acdebug.h> | ||
53 | #include <acpi/acdisasm.h> | ||
54 | |||
55 | |||
56 | #define _COMPONENT ACPI_DISPATCHER | ||
57 | ACPI_MODULE_NAME ("dswexec") | ||
58 | |||
59 | /* | ||
60 | * Dispatch table for opcode classes | ||
61 | */ | ||
62 | static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { | ||
63 | acpi_ex_opcode_0A_0T_1R, | ||
64 | acpi_ex_opcode_1A_0T_0R, | ||
65 | acpi_ex_opcode_1A_0T_1R, | ||
66 | acpi_ex_opcode_1A_1T_0R, | ||
67 | acpi_ex_opcode_1A_1T_1R, | ||
68 | acpi_ex_opcode_2A_0T_0R, | ||
69 | acpi_ex_opcode_2A_0T_1R, | ||
70 | acpi_ex_opcode_2A_1T_1R, | ||
71 | acpi_ex_opcode_2A_2T_1R, | ||
72 | acpi_ex_opcode_3A_0T_0R, | ||
73 | acpi_ex_opcode_3A_1T_1R, | ||
74 | acpi_ex_opcode_6A_0T_1R}; | ||
75 | |||
76 | /***************************************************************************** | ||
77 | * | ||
78 | * FUNCTION: acpi_ds_get_predicate_value | ||
79 | * | ||
80 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
81 | * | ||
82 | * RETURN: Status | ||
83 | * | ||
84 | * DESCRIPTION: Get the result of a predicate evaluation | ||
85 | * | ||
86 | ****************************************************************************/ | ||
87 | |||
88 | acpi_status | ||
89 | acpi_ds_get_predicate_value ( | ||
90 | struct acpi_walk_state *walk_state, | ||
91 | union acpi_operand_object *result_obj) { | ||
92 | acpi_status status = AE_OK; | ||
93 | union acpi_operand_object *obj_desc; | ||
94 | union acpi_operand_object *local_obj_desc = NULL; | ||
95 | |||
96 | |||
97 | ACPI_FUNCTION_TRACE_PTR ("ds_get_predicate_value", walk_state); | ||
98 | |||
99 | |||
100 | walk_state->control_state->common.state = 0; | ||
101 | |||
102 | if (result_obj) { | ||
103 | status = acpi_ds_result_pop (&obj_desc, walk_state); | ||
104 | if (ACPI_FAILURE (status)) { | ||
105 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
106 | "Could not get result from predicate evaluation, %s\n", | ||
107 | acpi_format_exception (status))); | ||
108 | |||
109 | return_ACPI_STATUS (status); | ||
110 | } | ||
111 | } | ||
112 | else { | ||
113 | status = acpi_ds_create_operand (walk_state, walk_state->op, 0); | ||
114 | if (ACPI_FAILURE (status)) { | ||
115 | return_ACPI_STATUS (status); | ||
116 | } | ||
117 | |||
118 | status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state); | ||
119 | if (ACPI_FAILURE (status)) { | ||
120 | return_ACPI_STATUS (status); | ||
121 | } | ||
122 | |||
123 | obj_desc = walk_state->operands [0]; | ||
124 | } | ||
125 | |||
126 | if (!obj_desc) { | ||
127 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n", | ||
128 | obj_desc, walk_state)); | ||
129 | |||
130 | return_ACPI_STATUS (AE_AML_NO_OPERAND); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Result of predicate evaluation must be an Integer | ||
135 | * object. Implicitly convert the argument if necessary. | ||
136 | */ | ||
137 | status = acpi_ex_convert_to_integer (obj_desc, &local_obj_desc, 16); | ||
138 | if (ACPI_FAILURE (status)) { | ||
139 | goto cleanup; | ||
140 | } | ||
141 | |||
142 | if (ACPI_GET_OBJECT_TYPE (local_obj_desc) != ACPI_TYPE_INTEGER) { | ||
143 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
144 | "Bad predicate (not an integer) obj_desc=%p State=%p Type=%X\n", | ||
145 | obj_desc, walk_state, ACPI_GET_OBJECT_TYPE (obj_desc))); | ||
146 | |||
147 | status = AE_AML_OPERAND_TYPE; | ||
148 | goto cleanup; | ||
149 | } | ||
150 | |||
151 | /* Truncate the predicate to 32-bits if necessary */ | ||
152 | |||
153 | acpi_ex_truncate_for32bit_table (local_obj_desc); | ||
154 | |||
155 | /* | ||
156 | * Save the result of the predicate evaluation on | ||
157 | * the control stack | ||
158 | */ | ||
159 | if (local_obj_desc->integer.value) { | ||
160 | walk_state->control_state->common.value = TRUE; | ||
161 | } | ||
162 | else { | ||
163 | /* | ||
164 | * Predicate is FALSE, we will just toss the | ||
165 | * rest of the package | ||
166 | */ | ||
167 | walk_state->control_state->common.value = FALSE; | ||
168 | status = AE_CTRL_FALSE; | ||
169 | } | ||
170 | |||
171 | |||
172 | cleanup: | ||
173 | |||
174 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", | ||
175 | walk_state->control_state->common.value, walk_state->op)); | ||
176 | |||
177 | /* Break to debugger to display result */ | ||
178 | |||
179 | ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (local_obj_desc, walk_state)); | ||
180 | |||
181 | /* | ||
182 | * Delete the predicate result object (we know that | ||
183 | * we don't need it anymore) | ||
184 | */ | ||
185 | if (local_obj_desc != obj_desc) { | ||
186 | acpi_ut_remove_reference (local_obj_desc); | ||
187 | } | ||
188 | acpi_ut_remove_reference (obj_desc); | ||
189 | |||
190 | walk_state->control_state->common.state = ACPI_CONTROL_NORMAL; | ||
191 | return_ACPI_STATUS (status); | ||
192 | } | ||
193 | |||
194 | |||
195 | /***************************************************************************** | ||
196 | * | ||
197 | * FUNCTION: acpi_ds_exec_begin_op | ||
198 | * | ||
199 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
200 | * out_op - Return op if a new one is created | ||
201 | * | ||
202 | * RETURN: Status | ||
203 | * | ||
204 | * DESCRIPTION: Descending callback used during the execution of control | ||
205 | * methods. This is where most operators and operands are | ||
206 | * dispatched to the interpreter. | ||
207 | * | ||
208 | ****************************************************************************/ | ||
209 | |||
210 | acpi_status | ||
211 | acpi_ds_exec_begin_op ( | ||
212 | struct acpi_walk_state *walk_state, | ||
213 | union acpi_parse_object **out_op) | ||
214 | { | ||
215 | union acpi_parse_object *op; | ||
216 | acpi_status status = AE_OK; | ||
217 | u32 opcode_class; | ||
218 | |||
219 | |||
220 | ACPI_FUNCTION_TRACE_PTR ("ds_exec_begin_op", walk_state); | ||
221 | |||
222 | |||
223 | op = walk_state->op; | ||
224 | if (!op) { | ||
225 | status = acpi_ds_load2_begin_op (walk_state, out_op); | ||
226 | if (ACPI_FAILURE (status)) { | ||
227 | return_ACPI_STATUS (status); | ||
228 | } | ||
229 | |||
230 | op = *out_op; | ||
231 | walk_state->op = op; | ||
232 | walk_state->opcode = op->common.aml_opcode; | ||
233 | walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); | ||
234 | |||
235 | if (acpi_ns_opens_scope (walk_state->op_info->object_type)) { | ||
236 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", | ||
237 | acpi_ut_get_type_name (walk_state->op_info->object_type), op)); | ||
238 | |||
239 | status = acpi_ds_scope_stack_pop (walk_state); | ||
240 | if (ACPI_FAILURE (status)) { | ||
241 | return_ACPI_STATUS (status); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if (op == walk_state->origin) { | ||
247 | if (out_op) { | ||
248 | *out_op = op; | ||
249 | } | ||
250 | |||
251 | return_ACPI_STATUS (AE_OK); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * If the previous opcode was a conditional, this opcode | ||
256 | * must be the beginning of the associated predicate. | ||
257 | * Save this knowledge in the current scope descriptor | ||
258 | */ | ||
259 | if ((walk_state->control_state) && | ||
260 | (walk_state->control_state->common.state == | ||
261 | ACPI_CONTROL_CONDITIONAL_EXECUTING)) { | ||
262 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Exec predicate Op=%p State=%p\n", | ||
263 | op, walk_state)); | ||
264 | |||
265 | walk_state->control_state->common.state = ACPI_CONTROL_PREDICATE_EXECUTING; | ||
266 | |||
267 | /* Save start of predicate */ | ||
268 | |||
269 | walk_state->control_state->control.predicate_op = op; | ||
270 | } | ||
271 | |||
272 | |||
273 | opcode_class = walk_state->op_info->class; | ||
274 | |||
275 | /* We want to send namepaths to the load code */ | ||
276 | |||
277 | if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { | ||
278 | opcode_class = AML_CLASS_NAMED_OBJECT; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Handle the opcode based upon the opcode type | ||
283 | */ | ||
284 | switch (opcode_class) { | ||
285 | case AML_CLASS_CONTROL: | ||
286 | |||
287 | status = acpi_ds_result_stack_push (walk_state); | ||
288 | if (ACPI_FAILURE (status)) { | ||
289 | return_ACPI_STATUS (status); | ||
290 | } | ||
291 | |||
292 | status = acpi_ds_exec_begin_control_op (walk_state, op); | ||
293 | break; | ||
294 | |||
295 | |||
296 | case AML_CLASS_NAMED_OBJECT: | ||
297 | |||
298 | if (walk_state->walk_type == ACPI_WALK_METHOD) { | ||
299 | /* | ||
300 | * Found a named object declaration during method | ||
301 | * execution; we must enter this object into the | ||
302 | * namespace. The created object is temporary and | ||
303 | * will be deleted upon completion of the execution | ||
304 | * of this method. | ||
305 | */ | ||
306 | status = acpi_ds_load2_begin_op (walk_state, NULL); | ||
307 | } | ||
308 | |||
309 | if (op->common.aml_opcode == AML_REGION_OP) { | ||
310 | status = acpi_ds_result_stack_push (walk_state); | ||
311 | } | ||
312 | break; | ||
313 | |||
314 | |||
315 | case AML_CLASS_EXECUTE: | ||
316 | case AML_CLASS_CREATE: | ||
317 | |||
318 | /* | ||
319 | * Most operators with arguments. | ||
320 | * Start a new result/operand state | ||
321 | */ | ||
322 | status = acpi_ds_result_stack_push (walk_state); | ||
323 | break; | ||
324 | |||
325 | |||
326 | default: | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | /* Nothing to do here during method execution */ | ||
331 | |||
332 | return_ACPI_STATUS (status); | ||
333 | } | ||
334 | |||
335 | |||
336 | /***************************************************************************** | ||
337 | * | ||
338 | * FUNCTION: acpi_ds_exec_end_op | ||
339 | * | ||
340 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
341 | * Op - Op that has been just been completed in the | ||
342 | * walk; Arguments have now been evaluated. | ||
343 | * | ||
344 | * RETURN: Status | ||
345 | * | ||
346 | * DESCRIPTION: Ascending callback used during the execution of control | ||
347 | * methods. The only thing we really need to do here is to | ||
348 | * notice the beginning of IF, ELSE, and WHILE blocks. | ||
349 | * | ||
350 | ****************************************************************************/ | ||
351 | |||
352 | acpi_status | ||
353 | acpi_ds_exec_end_op ( | ||
354 | struct acpi_walk_state *walk_state) | ||
355 | { | ||
356 | union acpi_parse_object *op; | ||
357 | acpi_status status = AE_OK; | ||
358 | u32 op_type; | ||
359 | u32 op_class; | ||
360 | union acpi_parse_object *next_op; | ||
361 | union acpi_parse_object *first_arg; | ||
362 | |||
363 | |||
364 | ACPI_FUNCTION_TRACE_PTR ("ds_exec_end_op", walk_state); | ||
365 | |||
366 | |||
367 | op = walk_state->op; | ||
368 | op_type = walk_state->op_info->type; | ||
369 | op_class = walk_state->op_info->class; | ||
370 | |||
371 | if (op_class == AML_CLASS_UNKNOWN) { | ||
372 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", op->common.aml_opcode)); | ||
373 | return_ACPI_STATUS (AE_NOT_IMPLEMENTED); | ||
374 | } | ||
375 | |||
376 | first_arg = op->common.value.arg; | ||
377 | |||
378 | /* Init the walk state */ | ||
379 | |||
380 | walk_state->num_operands = 0; | ||
381 | walk_state->return_desc = NULL; | ||
382 | walk_state->result_obj = NULL; | ||
383 | |||
384 | /* Call debugger for single step support (DEBUG build only) */ | ||
385 | |||
386 | ACPI_DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, op_class)); | ||
387 | ACPI_DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return_ACPI_STATUS (status);}); | ||
388 | |||
389 | /* Decode the Opcode Class */ | ||
390 | |||
391 | switch (op_class) { | ||
392 | case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */ | ||
393 | break; | ||
394 | |||
395 | |||
396 | case AML_CLASS_EXECUTE: /* most operators with arguments */ | ||
397 | |||
398 | /* Build resolved operand stack */ | ||
399 | |||
400 | status = acpi_ds_create_operands (walk_state, first_arg); | ||
401 | if (ACPI_FAILURE (status)) { | ||
402 | goto cleanup; | ||
403 | } | ||
404 | |||
405 | /* Done with this result state (Now that operand stack is built) */ | ||
406 | |||
407 | status = acpi_ds_result_stack_pop (walk_state); | ||
408 | if (ACPI_FAILURE (status)) { | ||
409 | goto cleanup; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * All opcodes require operand resolution, with the only exceptions | ||
414 | * being the object_type and size_of operators. | ||
415 | */ | ||
416 | if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) { | ||
417 | /* Resolve all operands */ | ||
418 | |||
419 | status = acpi_ex_resolve_operands (walk_state->opcode, | ||
420 | &(walk_state->operands [walk_state->num_operands -1]), | ||
421 | walk_state); | ||
422 | if (ACPI_SUCCESS (status)) { | ||
423 | ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, | ||
424 | acpi_ps_get_opcode_name (walk_state->opcode), | ||
425 | walk_state->num_operands, "after ex_resolve_operands"); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | if (ACPI_SUCCESS (status)) { | ||
430 | /* | ||
431 | * Dispatch the request to the appropriate interpreter handler | ||
432 | * routine. There is one routine per opcode "type" based upon the | ||
433 | * number of opcode arguments and return type. | ||
434 | */ | ||
435 | status = acpi_gbl_op_type_dispatch[op_type] (walk_state); | ||
436 | } | ||
437 | else { | ||
438 | /* | ||
439 | * Treat constructs of the form "Store(local_x,local_x)" as noops when the | ||
440 | * Local is uninitialized. | ||
441 | */ | ||
442 | if ((status == AE_AML_UNINITIALIZED_LOCAL) && | ||
443 | (walk_state->opcode == AML_STORE_OP) && | ||
444 | (walk_state->operands[0]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && | ||
445 | (walk_state->operands[1]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && | ||
446 | (walk_state->operands[0]->reference.opcode == | ||
447 | walk_state->operands[1]->reference.opcode) && | ||
448 | (walk_state->operands[0]->reference.offset == | ||
449 | walk_state->operands[1]->reference.offset)) { | ||
450 | status = AE_OK; | ||
451 | } | ||
452 | else { | ||
453 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
454 | "[%s]: Could not resolve operands, %s\n", | ||
455 | acpi_ps_get_opcode_name (walk_state->opcode), | ||
456 | acpi_format_exception (status))); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | /* Always delete the argument objects and clear the operand stack */ | ||
461 | |||
462 | acpi_ds_clear_operands (walk_state); | ||
463 | |||
464 | /* | ||
465 | * If a result object was returned from above, push it on the | ||
466 | * current result stack | ||
467 | */ | ||
468 | if (ACPI_SUCCESS (status) && | ||
469 | walk_state->result_obj) { | ||
470 | status = acpi_ds_result_push (walk_state->result_obj, walk_state); | ||
471 | } | ||
472 | |||
473 | break; | ||
474 | |||
475 | |||
476 | default: | ||
477 | |||
478 | switch (op_type) { | ||
479 | case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */ | ||
480 | |||
481 | /* 1 Operand, 0 external_result, 0 internal_result */ | ||
482 | |||
483 | status = acpi_ds_exec_end_control_op (walk_state, op); | ||
484 | |||
485 | /* Make sure to properly pop the result stack */ | ||
486 | |||
487 | if (ACPI_SUCCESS (status)) { | ||
488 | status = acpi_ds_result_stack_pop (walk_state); | ||
489 | } | ||
490 | else if (status == AE_CTRL_PENDING) { | ||
491 | status = acpi_ds_result_stack_pop (walk_state); | ||
492 | if (ACPI_SUCCESS (status)) { | ||
493 | status = AE_CTRL_PENDING; | ||
494 | } | ||
495 | } | ||
496 | break; | ||
497 | |||
498 | |||
499 | case AML_TYPE_METHOD_CALL: | ||
500 | |||
501 | /* | ||
502 | * If the method is referenced from within a package | ||
503 | * declaration, it is not a invocation of the method, just | ||
504 | * a reference to it. | ||
505 | */ | ||
506 | if ((op->asl.parent) && | ||
507 | ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) || | ||
508 | (op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) { | ||
509 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op)); | ||
510 | op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object; | ||
511 | acpi_ut_add_reference (op->asl.value.arg->asl.node->object); | ||
512 | return_ACPI_STATUS (AE_OK); | ||
513 | } | ||
514 | |||
515 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method invocation, Op=%p\n", op)); | ||
516 | |||
517 | /* | ||
518 | * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains | ||
519 | * the method Node pointer | ||
520 | */ | ||
521 | /* next_op points to the op that holds the method name */ | ||
522 | |||
523 | next_op = first_arg; | ||
524 | |||
525 | /* next_op points to first argument op */ | ||
526 | |||
527 | next_op = next_op->common.next; | ||
528 | |||
529 | /* | ||
530 | * Get the method's arguments and put them on the operand stack | ||
531 | */ | ||
532 | status = acpi_ds_create_operands (walk_state, next_op); | ||
533 | if (ACPI_FAILURE (status)) { | ||
534 | break; | ||
535 | } | ||
536 | |||
537 | /* | ||
538 | * Since the operands will be passed to another control method, | ||
539 | * we must resolve all local references here (Local variables, | ||
540 | * arguments to *this* method, etc.) | ||
541 | */ | ||
542 | status = acpi_ds_resolve_operands (walk_state); | ||
543 | if (ACPI_FAILURE (status)) { | ||
544 | /* On error, clear all resolved operands */ | ||
545 | |||
546 | acpi_ds_clear_operands (walk_state); | ||
547 | break; | ||
548 | } | ||
549 | |||
550 | /* | ||
551 | * Tell the walk loop to preempt this running method and | ||
552 | * execute the new method | ||
553 | */ | ||
554 | status = AE_CTRL_TRANSFER; | ||
555 | |||
556 | /* | ||
557 | * Return now; we don't want to disturb anything, | ||
558 | * especially the operand count! | ||
559 | */ | ||
560 | return_ACPI_STATUS (status); | ||
561 | |||
562 | |||
563 | case AML_TYPE_CREATE_FIELD: | ||
564 | |||
565 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
566 | "Executing create_field Buffer/Index Op=%p\n", op)); | ||
567 | |||
568 | status = acpi_ds_load2_end_op (walk_state); | ||
569 | if (ACPI_FAILURE (status)) { | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | status = acpi_ds_eval_buffer_field_operands (walk_state, op); | ||
574 | break; | ||
575 | |||
576 | |||
577 | case AML_TYPE_CREATE_OBJECT: | ||
578 | |||
579 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
580 | "Executing create_object (Buffer/Package) Op=%p\n", op)); | ||
581 | |||
582 | switch (op->common.parent->common.aml_opcode) { | ||
583 | case AML_NAME_OP: | ||
584 | |||
585 | /* | ||
586 | * Put the Node on the object stack (Contains the ACPI Name of | ||
587 | * this object) | ||
588 | */ | ||
589 | walk_state->operands[0] = (void *) op->common.parent->common.node; | ||
590 | walk_state->num_operands = 1; | ||
591 | |||
592 | status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent); | ||
593 | if (ACPI_FAILURE (status)) { | ||
594 | break; | ||
595 | } | ||
596 | |||
597 | /* Fall through */ | ||
598 | /*lint -fallthrough */ | ||
599 | |||
600 | case AML_INT_EVAL_SUBTREE_OP: | ||
601 | |||
602 | status = acpi_ds_eval_data_object_operands (walk_state, op, | ||
603 | acpi_ns_get_attached_object (op->common.parent->common.node)); | ||
604 | break; | ||
605 | |||
606 | default: | ||
607 | |||
608 | status = acpi_ds_eval_data_object_operands (walk_state, op, NULL); | ||
609 | break; | ||
610 | } | ||
611 | |||
612 | /* Done with this result state (Now that operand stack is built) */ | ||
613 | |||
614 | status = acpi_ds_result_stack_pop (walk_state); | ||
615 | if (ACPI_FAILURE (status)) { | ||
616 | goto cleanup; | ||
617 | } | ||
618 | |||
619 | /* | ||
620 | * If a result object was returned from above, push it on the | ||
621 | * current result stack | ||
622 | */ | ||
623 | if (ACPI_SUCCESS (status) && | ||
624 | walk_state->result_obj) { | ||
625 | status = acpi_ds_result_push (walk_state->result_obj, walk_state); | ||
626 | } | ||
627 | break; | ||
628 | |||
629 | |||
630 | case AML_TYPE_NAMED_FIELD: | ||
631 | case AML_TYPE_NAMED_COMPLEX: | ||
632 | case AML_TYPE_NAMED_SIMPLE: | ||
633 | case AML_TYPE_NAMED_NO_OBJ: | ||
634 | |||
635 | status = acpi_ds_load2_end_op (walk_state); | ||
636 | if (ACPI_FAILURE (status)) { | ||
637 | break; | ||
638 | } | ||
639 | |||
640 | if (op->common.aml_opcode == AML_REGION_OP) { | ||
641 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
642 | "Executing op_region Address/Length Op=%p\n", op)); | ||
643 | |||
644 | status = acpi_ds_eval_region_operands (walk_state, op); | ||
645 | if (ACPI_FAILURE (status)) { | ||
646 | break; | ||
647 | } | ||
648 | |||
649 | status = acpi_ds_result_stack_pop (walk_state); | ||
650 | } | ||
651 | |||
652 | break; | ||
653 | |||
654 | |||
655 | case AML_TYPE_UNDEFINED: | ||
656 | |||
657 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op)); | ||
658 | return_ACPI_STATUS (AE_NOT_IMPLEMENTED); | ||
659 | |||
660 | |||
661 | case AML_TYPE_BOGUS: | ||
662 | |||
663 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
664 | "Internal opcode=%X type Op=%p\n", | ||
665 | walk_state->opcode, op)); | ||
666 | break; | ||
667 | |||
668 | |||
669 | default: | ||
670 | |||
671 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
672 | "Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p\n", | ||
673 | op_class, op_type, op->common.aml_opcode, op)); | ||
674 | |||
675 | status = AE_NOT_IMPLEMENTED; | ||
676 | break; | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * ACPI 2.0 support for 64-bit integers: Truncate numeric | ||
682 | * result value if we are executing from a 32-bit ACPI table | ||
683 | */ | ||
684 | acpi_ex_truncate_for32bit_table (walk_state->result_obj); | ||
685 | |||
686 | /* | ||
687 | * Check if we just completed the evaluation of a | ||
688 | * conditional predicate | ||
689 | */ | ||
690 | |||
691 | if ((ACPI_SUCCESS (status)) && | ||
692 | (walk_state->control_state) && | ||
693 | (walk_state->control_state->common.state == | ||
694 | ACPI_CONTROL_PREDICATE_EXECUTING) && | ||
695 | (walk_state->control_state->control.predicate_op == op)) { | ||
696 | status = acpi_ds_get_predicate_value (walk_state, walk_state->result_obj); | ||
697 | walk_state->result_obj = NULL; | ||
698 | } | ||
699 | |||
700 | |||
701 | cleanup: | ||
702 | |||
703 | /* Invoke exception handler on error */ | ||
704 | |||
705 | if (ACPI_FAILURE (status) && | ||
706 | acpi_gbl_exception_handler && | ||
707 | !(status & AE_CODE_CONTROL)) { | ||
708 | acpi_ex_exit_interpreter (); | ||
709 | status = acpi_gbl_exception_handler (status, | ||
710 | walk_state->method_node->name.integer, walk_state->opcode, | ||
711 | walk_state->aml_offset, NULL); | ||
712 | acpi_ex_enter_interpreter (); | ||
713 | } | ||
714 | |||
715 | if (walk_state->result_obj) { | ||
716 | /* Break to debugger to display result */ | ||
717 | |||
718 | ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); | ||
719 | |||
720 | /* | ||
721 | * Delete the result op if and only if: | ||
722 | * Parent will not use the result -- such as any | ||
723 | * non-nested type2 op in a method (parent will be method) | ||
724 | */ | ||
725 | acpi_ds_delete_result_if_not_used (op, walk_state->result_obj, walk_state); | ||
726 | } | ||
727 | |||
728 | #ifdef _UNDER_DEVELOPMENT | ||
729 | |||
730 | if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) { | ||
731 | acpi_db_method_end (walk_state); | ||
732 | } | ||
733 | #endif | ||
734 | |||
735 | /* Always clear the object stack */ | ||
736 | |||
737 | walk_state->num_operands = 0; | ||
738 | |||
739 | #ifdef ACPI_DISASSEMBLER | ||
740 | |||
741 | /* On error, display method locals/args */ | ||
742 | |||
743 | if (ACPI_FAILURE (status)) { | ||
744 | acpi_dm_dump_method_info (status, walk_state, op); | ||
745 | } | ||
746 | #endif | ||
747 | |||
748 | return_ACPI_STATUS (status); | ||
749 | } | ||
750 | |||
751 | |||
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c new file mode 100644 index 000000000000..06d758679588 --- /dev/null +++ b/drivers/acpi/dispatcher/dswload.c | |||
@@ -0,0 +1,976 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dswload - Dispatcher namespace load callbacks | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acparser.h> | ||
47 | #include <acpi/amlcode.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | #include <acpi/acnamesp.h> | ||
51 | #include <acpi/acevents.h> | ||
52 | |||
53 | #ifdef _ACPI_ASL_COMPILER | ||
54 | #include <acpi/acdisasm.h> | ||
55 | #endif | ||
56 | |||
57 | #define _COMPONENT ACPI_DISPATCHER | ||
58 | ACPI_MODULE_NAME ("dswload") | ||
59 | |||
60 | |||
61 | /******************************************************************************* | ||
62 | * | ||
63 | * FUNCTION: acpi_ds_init_callbacks | ||
64 | * | ||
65 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
66 | * pass_number - 1, 2, or 3 | ||
67 | * | ||
68 | * RETURN: Status | ||
69 | * | ||
70 | * DESCRIPTION: Init walk state callbacks | ||
71 | * | ||
72 | ******************************************************************************/ | ||
73 | |||
74 | acpi_status | ||
75 | acpi_ds_init_callbacks ( | ||
76 | struct acpi_walk_state *walk_state, | ||
77 | u32 pass_number) | ||
78 | { | ||
79 | |||
80 | switch (pass_number) { | ||
81 | case 1: | ||
82 | walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; | ||
83 | walk_state->descending_callback = acpi_ds_load1_begin_op; | ||
84 | walk_state->ascending_callback = acpi_ds_load1_end_op; | ||
85 | break; | ||
86 | |||
87 | case 2: | ||
88 | walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; | ||
89 | walk_state->descending_callback = acpi_ds_load2_begin_op; | ||
90 | walk_state->ascending_callback = acpi_ds_load2_end_op; | ||
91 | break; | ||
92 | |||
93 | case 3: | ||
94 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
95 | walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; | ||
96 | walk_state->descending_callback = acpi_ds_exec_begin_op; | ||
97 | walk_state->ascending_callback = acpi_ds_exec_end_op; | ||
98 | #endif | ||
99 | break; | ||
100 | |||
101 | default: | ||
102 | return (AE_BAD_PARAMETER); | ||
103 | } | ||
104 | |||
105 | return (AE_OK); | ||
106 | } | ||
107 | |||
108 | |||
109 | /******************************************************************************* | ||
110 | * | ||
111 | * FUNCTION: acpi_ds_load1_begin_op | ||
112 | * | ||
113 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
114 | * Op - Op that has been just been reached in the | ||
115 | * walk; Arguments have not been evaluated yet. | ||
116 | * | ||
117 | * RETURN: Status | ||
118 | * | ||
119 | * DESCRIPTION: Descending callback used during the loading of ACPI tables. | ||
120 | * | ||
121 | ******************************************************************************/ | ||
122 | |||
123 | acpi_status | ||
124 | acpi_ds_load1_begin_op ( | ||
125 | struct acpi_walk_state *walk_state, | ||
126 | union acpi_parse_object **out_op) | ||
127 | { | ||
128 | union acpi_parse_object *op; | ||
129 | struct acpi_namespace_node *node; | ||
130 | acpi_status status; | ||
131 | acpi_object_type object_type; | ||
132 | char *path; | ||
133 | u32 flags; | ||
134 | |||
135 | |||
136 | ACPI_FUNCTION_NAME ("ds_load1_begin_op"); | ||
137 | |||
138 | |||
139 | op = walk_state->op; | ||
140 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); | ||
141 | |||
142 | /* We are only interested in opcodes that have an associated name */ | ||
143 | |||
144 | if (op) { | ||
145 | if (!(walk_state->op_info->flags & AML_NAMED)) { | ||
146 | #if 0 | ||
147 | if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || | ||
148 | (walk_state->op_info->class == AML_CLASS_CONTROL)) { | ||
149 | acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name); | ||
150 | *out_op = op; | ||
151 | return (AE_CTRL_SKIP); | ||
152 | } | ||
153 | #endif | ||
154 | *out_op = op; | ||
155 | return (AE_OK); | ||
156 | } | ||
157 | |||
158 | /* Check if this object has already been installed in the namespace */ | ||
159 | |||
160 | if (op->common.node) { | ||
161 | *out_op = op; | ||
162 | return (AE_OK); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | path = acpi_ps_get_next_namestring (&walk_state->parser_state); | ||
167 | |||
168 | /* Map the raw opcode into an internal object type */ | ||
169 | |||
170 | object_type = walk_state->op_info->object_type; | ||
171 | |||
172 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
173 | "State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type))); | ||
174 | |||
175 | switch (walk_state->opcode) { | ||
176 | case AML_SCOPE_OP: | ||
177 | |||
178 | /* | ||
179 | * The target name of the Scope() operator must exist at this point so | ||
180 | * that we can actually open the scope to enter new names underneath it. | ||
181 | * Allow search-to-root for single namesegs. | ||
182 | */ | ||
183 | status = acpi_ns_lookup (walk_state->scope_info, path, object_type, | ||
184 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); | ||
185 | #ifdef _ACPI_ASL_COMPILER | ||
186 | if (status == AE_NOT_FOUND) { | ||
187 | /* | ||
188 | * Table disassembly: | ||
189 | * Target of Scope() not found. Generate an External for it, and | ||
190 | * insert the name into the namespace. | ||
191 | */ | ||
192 | acpi_dm_add_to_external_list (path); | ||
193 | status = acpi_ns_lookup (walk_state->scope_info, path, object_type, | ||
194 | ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); | ||
195 | } | ||
196 | #endif | ||
197 | if (ACPI_FAILURE (status)) { | ||
198 | ACPI_REPORT_NSERROR (path, status); | ||
199 | return (status); | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Check to make sure that the target is | ||
204 | * one of the opcodes that actually opens a scope | ||
205 | */ | ||
206 | switch (node->type) { | ||
207 | case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ | ||
208 | case ACPI_TYPE_DEVICE: | ||
209 | case ACPI_TYPE_POWER: | ||
210 | case ACPI_TYPE_PROCESSOR: | ||
211 | case ACPI_TYPE_THERMAL: | ||
212 | |||
213 | /* These are acceptable types */ | ||
214 | break; | ||
215 | |||
216 | case ACPI_TYPE_INTEGER: | ||
217 | case ACPI_TYPE_STRING: | ||
218 | case ACPI_TYPE_BUFFER: | ||
219 | |||
220 | /* | ||
221 | * These types we will allow, but we will change the type. This | ||
222 | * enables some existing code of the form: | ||
223 | * | ||
224 | * Name (DEB, 0) | ||
225 | * Scope (DEB) { ... } | ||
226 | * | ||
227 | * Note: silently change the type here. On the second pass, we will report a warning | ||
228 | */ | ||
229 | |||
230 | ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", | ||
231 | path, acpi_ut_get_type_name (node->type))); | ||
232 | |||
233 | node->type = ACPI_TYPE_ANY; | ||
234 | walk_state->scope_info->common.value = ACPI_TYPE_ANY; | ||
235 | break; | ||
236 | |||
237 | default: | ||
238 | |||
239 | /* All other types are an error */ | ||
240 | |||
241 | ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", | ||
242 | acpi_ut_get_type_name (node->type), path)); | ||
243 | |||
244 | return (AE_AML_OPERAND_TYPE); | ||
245 | } | ||
246 | break; | ||
247 | |||
248 | |||
249 | default: | ||
250 | |||
251 | /* | ||
252 | * For all other named opcodes, we will enter the name into the namespace. | ||
253 | * | ||
254 | * Setup the search flags. | ||
255 | * Since we are entering a name into the namespace, we do not want to | ||
256 | * enable the search-to-root upsearch. | ||
257 | * | ||
258 | * There are only two conditions where it is acceptable that the name | ||
259 | * already exists: | ||
260 | * 1) the Scope() operator can reopen a scoping object that was | ||
261 | * previously defined (Scope, Method, Device, etc.) | ||
262 | * 2) Whenever we are parsing a deferred opcode (op_region, Buffer, | ||
263 | * buffer_field, or Package), the name of the object is already | ||
264 | * in the namespace. | ||
265 | */ | ||
266 | if (walk_state->deferred_node) { | ||
267 | /* This name is already in the namespace, get the node */ | ||
268 | |||
269 | node = walk_state->deferred_node; | ||
270 | status = AE_OK; | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | flags = ACPI_NS_NO_UPSEARCH; | ||
275 | if ((walk_state->opcode != AML_SCOPE_OP) && | ||
276 | (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { | ||
277 | flags |= ACPI_NS_ERROR_IF_FOUND; | ||
278 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n", | ||
279 | acpi_ut_get_type_name (object_type))); | ||
280 | } | ||
281 | else { | ||
282 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", | ||
283 | acpi_ut_get_type_name (object_type))); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Enter the named type into the internal namespace. We enter the name | ||
288 | * as we go downward in the parse tree. Any necessary subobjects that involve | ||
289 | * arguments to the opcode must be created as we go back up the parse tree later. | ||
290 | */ | ||
291 | status = acpi_ns_lookup (walk_state->scope_info, path, object_type, | ||
292 | ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node)); | ||
293 | if (ACPI_FAILURE (status)) { | ||
294 | ACPI_REPORT_NSERROR (path, status); | ||
295 | return (status); | ||
296 | } | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | |||
301 | /* Common exit */ | ||
302 | |||
303 | if (!op) { | ||
304 | /* Create a new op */ | ||
305 | |||
306 | op = acpi_ps_alloc_op (walk_state->opcode); | ||
307 | if (!op) { | ||
308 | return (AE_NO_MEMORY); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /* Initialize */ | ||
313 | |||
314 | op->named.name = node->name.integer; | ||
315 | |||
316 | #if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) | ||
317 | op->named.path = (u8 *) path; | ||
318 | #endif | ||
319 | |||
320 | |||
321 | /* | ||
322 | * Put the Node in the "op" object that the parser uses, so we | ||
323 | * can get it again quickly when this scope is closed | ||
324 | */ | ||
325 | op->common.node = node; | ||
326 | acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op); | ||
327 | |||
328 | *out_op = op; | ||
329 | return (status); | ||
330 | } | ||
331 | |||
332 | |||
333 | /******************************************************************************* | ||
334 | * | ||
335 | * FUNCTION: acpi_ds_load1_end_op | ||
336 | * | ||
337 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
338 | * Op - Op that has been just been completed in the | ||
339 | * walk; Arguments have now been evaluated. | ||
340 | * | ||
341 | * RETURN: Status | ||
342 | * | ||
343 | * DESCRIPTION: Ascending callback used during the loading of the namespace, | ||
344 | * both control methods and everything else. | ||
345 | * | ||
346 | ******************************************************************************/ | ||
347 | |||
348 | acpi_status | ||
349 | acpi_ds_load1_end_op ( | ||
350 | struct acpi_walk_state *walk_state) | ||
351 | { | ||
352 | union acpi_parse_object *op; | ||
353 | acpi_object_type object_type; | ||
354 | acpi_status status = AE_OK; | ||
355 | |||
356 | |||
357 | ACPI_FUNCTION_NAME ("ds_load1_end_op"); | ||
358 | |||
359 | |||
360 | op = walk_state->op; | ||
361 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); | ||
362 | |||
363 | /* We are only interested in opcodes that have an associated name */ | ||
364 | |||
365 | if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) { | ||
366 | return (AE_OK); | ||
367 | } | ||
368 | |||
369 | /* Get the object type to determine if we should pop the scope */ | ||
370 | |||
371 | object_type = walk_state->op_info->object_type; | ||
372 | |||
373 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
374 | if (walk_state->op_info->flags & AML_FIELD) { | ||
375 | if (walk_state->opcode == AML_FIELD_OP || | ||
376 | walk_state->opcode == AML_BANK_FIELD_OP || | ||
377 | walk_state->opcode == AML_INDEX_FIELD_OP) { | ||
378 | status = acpi_ds_init_field_objects (op, walk_state); | ||
379 | } | ||
380 | return (status); | ||
381 | } | ||
382 | |||
383 | |||
384 | if (op->common.aml_opcode == AML_REGION_OP) { | ||
385 | status = acpi_ex_create_region (op->named.data, op->named.length, | ||
386 | (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state); | ||
387 | if (ACPI_FAILURE (status)) { | ||
388 | return (status); | ||
389 | } | ||
390 | } | ||
391 | #endif | ||
392 | |||
393 | if (op->common.aml_opcode == AML_NAME_OP) { | ||
394 | /* For Name opcode, get the object type from the argument */ | ||
395 | |||
396 | if (op->common.value.arg) { | ||
397 | object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type; | ||
398 | op->common.node->type = (u8) object_type; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | if (op->common.aml_opcode == AML_METHOD_OP) { | ||
403 | /* | ||
404 | * method_op pkg_length name_string method_flags term_list | ||
405 | * | ||
406 | * Note: We must create the method node/object pair as soon as we | ||
407 | * see the method declaration. This allows later pass1 parsing | ||
408 | * of invocations of the method (need to know the number of | ||
409 | * arguments.) | ||
410 | */ | ||
411 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
412 | "LOADING-Method: State=%p Op=%p named_obj=%p\n", | ||
413 | walk_state, op, op->named.node)); | ||
414 | |||
415 | if (!acpi_ns_get_attached_object (op->named.node)) { | ||
416 | walk_state->operands[0] = (void *) op->named.node; | ||
417 | walk_state->num_operands = 1; | ||
418 | |||
419 | status = acpi_ds_create_operands (walk_state, op->common.value.arg); | ||
420 | if (ACPI_SUCCESS (status)) { | ||
421 | status = acpi_ex_create_method (op->named.data, | ||
422 | op->named.length, walk_state); | ||
423 | } | ||
424 | walk_state->operands[0] = NULL; | ||
425 | walk_state->num_operands = 0; | ||
426 | |||
427 | if (ACPI_FAILURE (status)) { | ||
428 | return (status); | ||
429 | } | ||
430 | } | ||
431 | } | ||
432 | |||
433 | /* Pop the scope stack */ | ||
434 | |||
435 | if (acpi_ns_opens_scope (object_type)) { | ||
436 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", | ||
437 | acpi_ut_get_type_name (object_type), op)); | ||
438 | |||
439 | status = acpi_ds_scope_stack_pop (walk_state); | ||
440 | } | ||
441 | |||
442 | return (status); | ||
443 | } | ||
444 | |||
445 | |||
446 | /******************************************************************************* | ||
447 | * | ||
448 | * FUNCTION: acpi_ds_load2_begin_op | ||
449 | * | ||
450 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
451 | * Op - Op that has been just been reached in the | ||
452 | * walk; Arguments have not been evaluated yet. | ||
453 | * | ||
454 | * RETURN: Status | ||
455 | * | ||
456 | * DESCRIPTION: Descending callback used during the loading of ACPI tables. | ||
457 | * | ||
458 | ******************************************************************************/ | ||
459 | |||
460 | acpi_status | ||
461 | acpi_ds_load2_begin_op ( | ||
462 | struct acpi_walk_state *walk_state, | ||
463 | union acpi_parse_object **out_op) | ||
464 | { | ||
465 | union acpi_parse_object *op; | ||
466 | struct acpi_namespace_node *node; | ||
467 | acpi_status status; | ||
468 | acpi_object_type object_type; | ||
469 | char *buffer_ptr; | ||
470 | |||
471 | |||
472 | ACPI_FUNCTION_TRACE ("ds_load2_begin_op"); | ||
473 | |||
474 | |||
475 | op = walk_state->op; | ||
476 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); | ||
477 | |||
478 | if (op) { | ||
479 | /* We only care about Namespace opcodes here */ | ||
480 | |||
481 | if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || | ||
482 | (!(walk_state->op_info->flags & AML_NAMED))) { | ||
483 | return_ACPI_STATUS (AE_OK); | ||
484 | } | ||
485 | |||
486 | /* | ||
487 | * Get the name we are going to enter or lookup in the namespace | ||
488 | */ | ||
489 | if (walk_state->opcode == AML_INT_NAMEPATH_OP) { | ||
490 | /* For Namepath op, get the path string */ | ||
491 | |||
492 | buffer_ptr = op->common.value.string; | ||
493 | if (!buffer_ptr) { | ||
494 | /* No name, just exit */ | ||
495 | |||
496 | return_ACPI_STATUS (AE_OK); | ||
497 | } | ||
498 | } | ||
499 | else { | ||
500 | /* Get name from the op */ | ||
501 | |||
502 | buffer_ptr = (char *) &op->named.name; | ||
503 | } | ||
504 | } | ||
505 | else { | ||
506 | /* Get the namestring from the raw AML */ | ||
507 | |||
508 | buffer_ptr = acpi_ps_get_next_namestring (&walk_state->parser_state); | ||
509 | } | ||
510 | |||
511 | /* Map the opcode into an internal object type */ | ||
512 | |||
513 | object_type = walk_state->op_info->object_type; | ||
514 | |||
515 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
516 | "State=%p Op=%p Type=%X\n", walk_state, op, object_type)); | ||
517 | |||
518 | |||
519 | switch (walk_state->opcode) { | ||
520 | case AML_FIELD_OP: | ||
521 | case AML_BANK_FIELD_OP: | ||
522 | case AML_INDEX_FIELD_OP: | ||
523 | |||
524 | node = NULL; | ||
525 | status = AE_OK; | ||
526 | break; | ||
527 | |||
528 | case AML_INT_NAMEPATH_OP: | ||
529 | |||
530 | /* | ||
531 | * The name_path is an object reference to an existing object. Don't enter the | ||
532 | * name into the namespace, but look it up for use later | ||
533 | */ | ||
534 | status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, | ||
535 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); | ||
536 | break; | ||
537 | |||
538 | case AML_SCOPE_OP: | ||
539 | |||
540 | /* | ||
541 | * The Path is an object reference to an existing object. Don't enter the | ||
542 | * name into the namespace, but look it up for use later | ||
543 | */ | ||
544 | status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, | ||
545 | ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); | ||
546 | if (ACPI_FAILURE (status)) { | ||
547 | #ifdef _ACPI_ASL_COMPILER | ||
548 | if (status == AE_NOT_FOUND) { | ||
549 | status = AE_OK; | ||
550 | } | ||
551 | else { | ||
552 | ACPI_REPORT_NSERROR (buffer_ptr, status); | ||
553 | } | ||
554 | #else | ||
555 | ACPI_REPORT_NSERROR (buffer_ptr, status); | ||
556 | #endif | ||
557 | return_ACPI_STATUS (status); | ||
558 | } | ||
559 | /* | ||
560 | * We must check to make sure that the target is | ||
561 | * one of the opcodes that actually opens a scope | ||
562 | */ | ||
563 | switch (node->type) { | ||
564 | case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ | ||
565 | case ACPI_TYPE_DEVICE: | ||
566 | case ACPI_TYPE_POWER: | ||
567 | case ACPI_TYPE_PROCESSOR: | ||
568 | case ACPI_TYPE_THERMAL: | ||
569 | |||
570 | /* These are acceptable types */ | ||
571 | break; | ||
572 | |||
573 | case ACPI_TYPE_INTEGER: | ||
574 | case ACPI_TYPE_STRING: | ||
575 | case ACPI_TYPE_BUFFER: | ||
576 | |||
577 | /* | ||
578 | * These types we will allow, but we will change the type. This | ||
579 | * enables some existing code of the form: | ||
580 | * | ||
581 | * Name (DEB, 0) | ||
582 | * Scope (DEB) { ... } | ||
583 | */ | ||
584 | |||
585 | ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", | ||
586 | buffer_ptr, acpi_ut_get_type_name (node->type))); | ||
587 | |||
588 | node->type = ACPI_TYPE_ANY; | ||
589 | walk_state->scope_info->common.value = ACPI_TYPE_ANY; | ||
590 | break; | ||
591 | |||
592 | default: | ||
593 | |||
594 | /* All other types are an error */ | ||
595 | |||
596 | ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", | ||
597 | acpi_ut_get_type_name (node->type), buffer_ptr)); | ||
598 | |||
599 | return (AE_AML_OPERAND_TYPE); | ||
600 | } | ||
601 | break; | ||
602 | |||
603 | default: | ||
604 | |||
605 | /* All other opcodes */ | ||
606 | |||
607 | if (op && op->common.node) { | ||
608 | /* This op/node was previously entered into the namespace */ | ||
609 | |||
610 | node = op->common.node; | ||
611 | |||
612 | if (acpi_ns_opens_scope (object_type)) { | ||
613 | status = acpi_ds_scope_stack_push (node, object_type, walk_state); | ||
614 | if (ACPI_FAILURE (status)) { | ||
615 | return_ACPI_STATUS (status); | ||
616 | } | ||
617 | |||
618 | } | ||
619 | return_ACPI_STATUS (AE_OK); | ||
620 | } | ||
621 | |||
622 | /* | ||
623 | * Enter the named type into the internal namespace. We enter the name | ||
624 | * as we go downward in the parse tree. Any necessary subobjects that involve | ||
625 | * arguments to the opcode must be created as we go back up the parse tree later. | ||
626 | * | ||
627 | * Note: Name may already exist if we are executing a deferred opcode. | ||
628 | */ | ||
629 | if (walk_state->deferred_node) { | ||
630 | /* This name is already in the namespace, get the node */ | ||
631 | |||
632 | node = walk_state->deferred_node; | ||
633 | status = AE_OK; | ||
634 | break; | ||
635 | } | ||
636 | |||
637 | status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, | ||
638 | ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | if (ACPI_FAILURE (status)) { | ||
643 | ACPI_REPORT_NSERROR (buffer_ptr, status); | ||
644 | return_ACPI_STATUS (status); | ||
645 | } | ||
646 | |||
647 | |||
648 | if (!op) { | ||
649 | /* Create a new op */ | ||
650 | |||
651 | op = acpi_ps_alloc_op (walk_state->opcode); | ||
652 | if (!op) { | ||
653 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
654 | } | ||
655 | |||
656 | /* Initialize the new op */ | ||
657 | |||
658 | if (node) { | ||
659 | op->named.name = node->name.integer; | ||
660 | } | ||
661 | if (out_op) { | ||
662 | *out_op = op; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * Put the Node in the "op" object that the parser uses, so we | ||
668 | * can get it again quickly when this scope is closed | ||
669 | */ | ||
670 | op->common.node = node; | ||
671 | |||
672 | return_ACPI_STATUS (status); | ||
673 | } | ||
674 | |||
675 | |||
676 | /******************************************************************************* | ||
677 | * | ||
678 | * FUNCTION: acpi_ds_load2_end_op | ||
679 | * | ||
680 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
681 | * Op - Op that has been just been completed in the | ||
682 | * walk; Arguments have now been evaluated. | ||
683 | * | ||
684 | * RETURN: Status | ||
685 | * | ||
686 | * DESCRIPTION: Ascending callback used during the loading of the namespace, | ||
687 | * both control methods and everything else. | ||
688 | * | ||
689 | ******************************************************************************/ | ||
690 | |||
691 | acpi_status | ||
692 | acpi_ds_load2_end_op ( | ||
693 | struct acpi_walk_state *walk_state) | ||
694 | { | ||
695 | union acpi_parse_object *op; | ||
696 | acpi_status status = AE_OK; | ||
697 | acpi_object_type object_type; | ||
698 | struct acpi_namespace_node *node; | ||
699 | union acpi_parse_object *arg; | ||
700 | struct acpi_namespace_node *new_node; | ||
701 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
702 | u32 i; | ||
703 | #endif | ||
704 | |||
705 | |||
706 | ACPI_FUNCTION_TRACE ("ds_load2_end_op"); | ||
707 | |||
708 | op = walk_state->op; | ||
709 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", | ||
710 | walk_state->op_info->name, op, walk_state)); | ||
711 | |||
712 | /* Only interested in opcodes that have namespace objects */ | ||
713 | |||
714 | if (!(walk_state->op_info->flags & AML_NSOBJECT)) { | ||
715 | return_ACPI_STATUS (AE_OK); | ||
716 | } | ||
717 | |||
718 | if (op->common.aml_opcode == AML_SCOPE_OP) { | ||
719 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
720 | "Ending scope Op=%p State=%p\n", op, walk_state)); | ||
721 | } | ||
722 | |||
723 | |||
724 | object_type = walk_state->op_info->object_type; | ||
725 | |||
726 | /* | ||
727 | * Get the Node/name from the earlier lookup | ||
728 | * (It was saved in the *op structure) | ||
729 | */ | ||
730 | node = op->common.node; | ||
731 | |||
732 | /* | ||
733 | * Put the Node on the object stack (Contains the ACPI Name of | ||
734 | * this object) | ||
735 | */ | ||
736 | walk_state->operands[0] = (void *) node; | ||
737 | walk_state->num_operands = 1; | ||
738 | |||
739 | /* Pop the scope stack */ | ||
740 | |||
741 | if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { | ||
742 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", | ||
743 | acpi_ut_get_type_name (object_type), op)); | ||
744 | |||
745 | status = acpi_ds_scope_stack_pop (walk_state); | ||
746 | if (ACPI_FAILURE (status)) { | ||
747 | goto cleanup; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * Named operations are as follows: | ||
753 | * | ||
754 | * AML_ALIAS | ||
755 | * AML_BANKFIELD | ||
756 | * AML_CREATEBITFIELD | ||
757 | * AML_CREATEBYTEFIELD | ||
758 | * AML_CREATEDWORDFIELD | ||
759 | * AML_CREATEFIELD | ||
760 | * AML_CREATEQWORDFIELD | ||
761 | * AML_CREATEWORDFIELD | ||
762 | * AML_DATA_REGION | ||
763 | * AML_DEVICE | ||
764 | * AML_EVENT | ||
765 | * AML_FIELD | ||
766 | * AML_INDEXFIELD | ||
767 | * AML_METHOD | ||
768 | * AML_METHODCALL | ||
769 | * AML_MUTEX | ||
770 | * AML_NAME | ||
771 | * AML_NAMEDFIELD | ||
772 | * AML_OPREGION | ||
773 | * AML_POWERRES | ||
774 | * AML_PROCESSOR | ||
775 | * AML_SCOPE | ||
776 | * AML_THERMALZONE | ||
777 | */ | ||
778 | |||
779 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
780 | "Create-Load [%s] State=%p Op=%p named_obj=%p\n", | ||
781 | acpi_ps_get_opcode_name (op->common.aml_opcode), walk_state, op, node)); | ||
782 | |||
783 | /* Decode the opcode */ | ||
784 | |||
785 | arg = op->common.value.arg; | ||
786 | |||
787 | switch (walk_state->op_info->type) { | ||
788 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
789 | |||
790 | case AML_TYPE_CREATE_FIELD: | ||
791 | |||
792 | /* | ||
793 | * Create the field object, but the field buffer and index must | ||
794 | * be evaluated later during the execution phase | ||
795 | */ | ||
796 | status = acpi_ds_create_buffer_field (op, walk_state); | ||
797 | break; | ||
798 | |||
799 | |||
800 | case AML_TYPE_NAMED_FIELD: | ||
801 | |||
802 | switch (op->common.aml_opcode) { | ||
803 | case AML_INDEX_FIELD_OP: | ||
804 | |||
805 | status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node, | ||
806 | walk_state); | ||
807 | break; | ||
808 | |||
809 | case AML_BANK_FIELD_OP: | ||
810 | |||
811 | status = acpi_ds_create_bank_field (op, arg->common.node, walk_state); | ||
812 | break; | ||
813 | |||
814 | case AML_FIELD_OP: | ||
815 | |||
816 | status = acpi_ds_create_field (op, arg->common.node, walk_state); | ||
817 | break; | ||
818 | |||
819 | default: | ||
820 | /* All NAMED_FIELD opcodes must be handled above */ | ||
821 | break; | ||
822 | } | ||
823 | break; | ||
824 | |||
825 | |||
826 | case AML_TYPE_NAMED_SIMPLE: | ||
827 | |||
828 | status = acpi_ds_create_operands (walk_state, arg); | ||
829 | if (ACPI_FAILURE (status)) { | ||
830 | goto cleanup; | ||
831 | } | ||
832 | |||
833 | switch (op->common.aml_opcode) { | ||
834 | case AML_PROCESSOR_OP: | ||
835 | |||
836 | status = acpi_ex_create_processor (walk_state); | ||
837 | break; | ||
838 | |||
839 | case AML_POWER_RES_OP: | ||
840 | |||
841 | status = acpi_ex_create_power_resource (walk_state); | ||
842 | break; | ||
843 | |||
844 | case AML_MUTEX_OP: | ||
845 | |||
846 | status = acpi_ex_create_mutex (walk_state); | ||
847 | break; | ||
848 | |||
849 | case AML_EVENT_OP: | ||
850 | |||
851 | status = acpi_ex_create_event (walk_state); | ||
852 | break; | ||
853 | |||
854 | case AML_DATA_REGION_OP: | ||
855 | |||
856 | status = acpi_ex_create_table_region (walk_state); | ||
857 | break; | ||
858 | |||
859 | case AML_ALIAS_OP: | ||
860 | |||
861 | status = acpi_ex_create_alias (walk_state); | ||
862 | break; | ||
863 | |||
864 | default: | ||
865 | /* Unknown opcode */ | ||
866 | |||
867 | status = AE_OK; | ||
868 | goto cleanup; | ||
869 | } | ||
870 | |||
871 | /* Delete operands */ | ||
872 | |||
873 | for (i = 1; i < walk_state->num_operands; i++) { | ||
874 | acpi_ut_remove_reference (walk_state->operands[i]); | ||
875 | walk_state->operands[i] = NULL; | ||
876 | } | ||
877 | |||
878 | break; | ||
879 | #endif /* ACPI_NO_METHOD_EXECUTION */ | ||
880 | |||
881 | case AML_TYPE_NAMED_COMPLEX: | ||
882 | |||
883 | switch (op->common.aml_opcode) { | ||
884 | #ifndef ACPI_NO_METHOD_EXECUTION | ||
885 | case AML_REGION_OP: | ||
886 | /* | ||
887 | * The op_region is not fully parsed at this time. Only valid argument is the space_id. | ||
888 | * (We must save the address of the AML of the address and length operands) | ||
889 | */ | ||
890 | /* | ||
891 | * If we have a valid region, initialize it | ||
892 | * Namespace is NOT locked at this point. | ||
893 | */ | ||
894 | status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE); | ||
895 | if (ACPI_FAILURE (status)) { | ||
896 | /* | ||
897 | * If AE_NOT_EXIST is returned, it is not fatal | ||
898 | * because many regions get created before a handler | ||
899 | * is installed for said region. | ||
900 | */ | ||
901 | if (AE_NOT_EXIST == status) { | ||
902 | status = AE_OK; | ||
903 | } | ||
904 | } | ||
905 | break; | ||
906 | |||
907 | |||
908 | case AML_NAME_OP: | ||
909 | |||
910 | status = acpi_ds_create_node (walk_state, node, op); | ||
911 | break; | ||
912 | #endif /* ACPI_NO_METHOD_EXECUTION */ | ||
913 | |||
914 | |||
915 | default: | ||
916 | /* All NAMED_COMPLEX opcodes must be handled above */ | ||
917 | /* Note: Method objects were already created in Pass 1 */ | ||
918 | break; | ||
919 | } | ||
920 | break; | ||
921 | |||
922 | |||
923 | case AML_CLASS_INTERNAL: | ||
924 | |||
925 | /* case AML_INT_NAMEPATH_OP: */ | ||
926 | break; | ||
927 | |||
928 | |||
929 | case AML_CLASS_METHOD_CALL: | ||
930 | |||
931 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, | ||
932 | "RESOLVING-method_call: State=%p Op=%p named_obj=%p\n", | ||
933 | walk_state, op, node)); | ||
934 | |||
935 | /* | ||
936 | * Lookup the method name and save the Node | ||
937 | */ | ||
938 | status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, | ||
939 | ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2, | ||
940 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, | ||
941 | walk_state, &(new_node)); | ||
942 | if (ACPI_SUCCESS (status)) { | ||
943 | /* | ||
944 | * Make sure that what we found is indeed a method | ||
945 | * We didn't search for a method on purpose, to see if the name would resolve | ||
946 | */ | ||
947 | if (new_node->type != ACPI_TYPE_METHOD) { | ||
948 | status = AE_AML_OPERAND_TYPE; | ||
949 | } | ||
950 | |||
951 | /* We could put the returned object (Node) on the object stack for later, but | ||
952 | * for now, we will put it in the "op" object that the parser uses, so we | ||
953 | * can get it again at the end of this scope | ||
954 | */ | ||
955 | op->common.node = new_node; | ||
956 | } | ||
957 | else { | ||
958 | ACPI_REPORT_NSERROR (arg->common.value.string, status); | ||
959 | } | ||
960 | break; | ||
961 | |||
962 | |||
963 | default: | ||
964 | break; | ||
965 | } | ||
966 | |||
967 | cleanup: | ||
968 | |||
969 | /* Remove the Node pushed at the very beginning */ | ||
970 | |||
971 | walk_state->operands[0] = NULL; | ||
972 | walk_state->num_operands = 0; | ||
973 | return_ACPI_STATUS (status); | ||
974 | } | ||
975 | |||
976 | |||
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c new file mode 100644 index 000000000000..65f456151e25 --- /dev/null +++ b/drivers/acpi/dispatcher/dswscope.c | |||
@@ -0,0 +1,229 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dswscope - Scope stack manipulation | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acdispat.h> | ||
47 | |||
48 | |||
49 | #define _COMPONENT ACPI_DISPATCHER | ||
50 | ACPI_MODULE_NAME ("dswscope") | ||
51 | |||
52 | |||
53 | #define STACK_POP(head) head | ||
54 | |||
55 | |||
56 | /**************************************************************************** | ||
57 | * | ||
58 | * FUNCTION: acpi_ds_scope_stack_clear | ||
59 | * | ||
60 | * PARAMETERS: None | ||
61 | * | ||
62 | * DESCRIPTION: Pop (and free) everything on the scope stack except the | ||
63 | * root scope object (which remains at the stack top.) | ||
64 | * | ||
65 | ***************************************************************************/ | ||
66 | |||
67 | void | ||
68 | acpi_ds_scope_stack_clear ( | ||
69 | struct acpi_walk_state *walk_state) | ||
70 | { | ||
71 | union acpi_generic_state *scope_info; | ||
72 | |||
73 | ACPI_FUNCTION_NAME ("ds_scope_stack_clear"); | ||
74 | |||
75 | |||
76 | while (walk_state->scope_info) { | ||
77 | /* Pop a scope off the stack */ | ||
78 | |||
79 | scope_info = walk_state->scope_info; | ||
80 | walk_state->scope_info = scope_info->scope.next; | ||
81 | |||
82 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
83 | "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value))); | ||
84 | acpi_ut_delete_generic_state (scope_info); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | |||
89 | /**************************************************************************** | ||
90 | * | ||
91 | * FUNCTION: acpi_ds_scope_stack_push | ||
92 | * | ||
93 | * PARAMETERS: *Node, - Name to be made current | ||
94 | * Type, - Type of frame being pushed | ||
95 | * | ||
96 | * DESCRIPTION: Push the current scope on the scope stack, and make the | ||
97 | * passed Node current. | ||
98 | * | ||
99 | ***************************************************************************/ | ||
100 | |||
101 | acpi_status | ||
102 | acpi_ds_scope_stack_push ( | ||
103 | struct acpi_namespace_node *node, | ||
104 | acpi_object_type type, | ||
105 | struct acpi_walk_state *walk_state) | ||
106 | { | ||
107 | union acpi_generic_state *scope_info; | ||
108 | union acpi_generic_state *old_scope_info; | ||
109 | |||
110 | |||
111 | ACPI_FUNCTION_TRACE ("ds_scope_stack_push"); | ||
112 | |||
113 | |||
114 | if (!node) { | ||
115 | /* Invalid scope */ | ||
116 | |||
117 | ACPI_REPORT_ERROR (("ds_scope_stack_push: null scope passed\n")); | ||
118 | return_ACPI_STATUS (AE_BAD_PARAMETER); | ||
119 | } | ||
120 | |||
121 | /* Make sure object type is valid */ | ||
122 | |||
123 | if (!acpi_ut_valid_object_type (type)) { | ||
124 | ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type)); | ||
125 | } | ||
126 | |||
127 | /* Allocate a new scope object */ | ||
128 | |||
129 | scope_info = acpi_ut_create_generic_state (); | ||
130 | if (!scope_info) { | ||
131 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
132 | } | ||
133 | |||
134 | /* Init new scope object */ | ||
135 | |||
136 | scope_info->common.data_type = ACPI_DESC_TYPE_STATE_WSCOPE; | ||
137 | scope_info->scope.node = node; | ||
138 | scope_info->common.value = (u16) type; | ||
139 | |||
140 | walk_state->scope_depth++; | ||
141 | |||
142 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
143 | "[%.2d] Pushed scope ", (u32) walk_state->scope_depth)); | ||
144 | |||
145 | old_scope_info = walk_state->scope_info; | ||
146 | if (old_scope_info) { | ||
147 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, | ||
148 | "[%4.4s] (%s)", | ||
149 | acpi_ut_get_node_name (old_scope_info->scope.node), | ||
150 | acpi_ut_get_type_name (old_scope_info->common.value))); | ||
151 | } | ||
152 | else { | ||
153 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, | ||
154 | "[\\___] (%s)", "ROOT")); | ||
155 | } | ||
156 | |||
157 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, | ||
158 | ", New scope -> [%4.4s] (%s)\n", | ||
159 | acpi_ut_get_node_name (scope_info->scope.node), | ||
160 | acpi_ut_get_type_name (scope_info->common.value))); | ||
161 | |||
162 | /* Push new scope object onto stack */ | ||
163 | |||
164 | acpi_ut_push_generic_state (&walk_state->scope_info, scope_info); | ||
165 | return_ACPI_STATUS (AE_OK); | ||
166 | } | ||
167 | |||
168 | |||
169 | /**************************************************************************** | ||
170 | * | ||
171 | * FUNCTION: acpi_ds_scope_stack_pop | ||
172 | * | ||
173 | * PARAMETERS: Type - The type of frame to be found | ||
174 | * | ||
175 | * DESCRIPTION: Pop the scope stack until a frame of the requested type | ||
176 | * is found. | ||
177 | * | ||
178 | * RETURN: Count of frames popped. If no frame of the requested type | ||
179 | * was found, the count is returned as a negative number and | ||
180 | * the scope stack is emptied (which sets the current scope | ||
181 | * to the root). If the scope stack was empty at entry, the | ||
182 | * function is a no-op and returns 0. | ||
183 | * | ||
184 | ***************************************************************************/ | ||
185 | |||
186 | acpi_status | ||
187 | acpi_ds_scope_stack_pop ( | ||
188 | struct acpi_walk_state *walk_state) | ||
189 | { | ||
190 | union acpi_generic_state *scope_info; | ||
191 | union acpi_generic_state *new_scope_info; | ||
192 | |||
193 | |||
194 | ACPI_FUNCTION_TRACE ("ds_scope_stack_pop"); | ||
195 | |||
196 | |||
197 | /* | ||
198 | * Pop scope info object off the stack. | ||
199 | */ | ||
200 | scope_info = acpi_ut_pop_generic_state (&walk_state->scope_info); | ||
201 | if (!scope_info) { | ||
202 | return_ACPI_STATUS (AE_STACK_UNDERFLOW); | ||
203 | } | ||
204 | |||
205 | walk_state->scope_depth--; | ||
206 | |||
207 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
208 | "[%.2d] Popped scope [%4.4s] (%s), New scope -> ", | ||
209 | (u32) walk_state->scope_depth, | ||
210 | acpi_ut_get_node_name (scope_info->scope.node), | ||
211 | acpi_ut_get_type_name (scope_info->common.value))); | ||
212 | |||
213 | new_scope_info = walk_state->scope_info; | ||
214 | if (new_scope_info) { | ||
215 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, | ||
216 | "[%4.4s] (%s)\n", | ||
217 | acpi_ut_get_node_name (new_scope_info->scope.node), | ||
218 | acpi_ut_get_type_name (new_scope_info->common.value))); | ||
219 | } | ||
220 | else { | ||
221 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, | ||
222 | "[\\___] (ROOT)\n")); | ||
223 | } | ||
224 | |||
225 | acpi_ut_delete_generic_state (scope_info); | ||
226 | return_ACPI_STATUS (AE_OK); | ||
227 | } | ||
228 | |||
229 | |||
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c new file mode 100644 index 000000000000..e555b3fbd5e5 --- /dev/null +++ b/drivers/acpi/dispatcher/dswstate.c | |||
@@ -0,0 +1,1100 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: dswstate - Dispatcher parse tree walk management routines | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2005, 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 | |||
45 | #include <acpi/acpi.h> | ||
46 | #include <acpi/acparser.h> | ||
47 | #include <acpi/acdispat.h> | ||
48 | #include <acpi/acnamesp.h> | ||
49 | |||
50 | #define _COMPONENT ACPI_DISPATCHER | ||
51 | ACPI_MODULE_NAME ("dswstate") | ||
52 | |||
53 | |||
54 | #ifdef ACPI_FUTURE_USAGE | ||
55 | |||
56 | /******************************************************************************* | ||
57 | * | ||
58 | * FUNCTION: acpi_ds_result_insert | ||
59 | * | ||
60 | * PARAMETERS: Object - Object to push | ||
61 | * Index - Where to insert the object | ||
62 | * walk_state - Current Walk state | ||
63 | * | ||
64 | * RETURN: Status | ||
65 | * | ||
66 | * DESCRIPTION: Insert an object onto this walk's result stack | ||
67 | * | ||
68 | ******************************************************************************/ | ||
69 | |||
70 | acpi_status | ||
71 | acpi_ds_result_insert ( | ||
72 | void *object, | ||
73 | u32 index, | ||
74 | struct acpi_walk_state *walk_state) | ||
75 | { | ||
76 | union acpi_generic_state *state; | ||
77 | |||
78 | |||
79 | ACPI_FUNCTION_NAME ("ds_result_insert"); | ||
80 | |||
81 | |||
82 | state = walk_state->results; | ||
83 | if (!state) { | ||
84 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", | ||
85 | walk_state)); | ||
86 | return (AE_NOT_EXIST); | ||
87 | } | ||
88 | |||
89 | if (index >= ACPI_OBJ_NUM_OPERANDS) { | ||
90 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
91 | "Index out of range: %X Obj=%p State=%p Num=%X\n", | ||
92 | index, object, walk_state, state->results.num_results)); | ||
93 | return (AE_BAD_PARAMETER); | ||
94 | } | ||
95 | |||
96 | if (!object) { | ||
97 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
98 | "Null Object! Index=%X Obj=%p State=%p Num=%X\n", | ||
99 | index, object, walk_state, state->results.num_results)); | ||
100 | return (AE_BAD_PARAMETER); | ||
101 | } | ||
102 | |||
103 | state->results.obj_desc [index] = object; | ||
104 | state->results.num_results++; | ||
105 | |||
106 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
107 | "Obj=%p [%s] State=%p Num=%X Cur=%X\n", | ||
108 | object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", | ||
109 | walk_state, state->results.num_results, walk_state->current_result)); | ||
110 | |||
111 | return (AE_OK); | ||
112 | } | ||
113 | |||
114 | |||
115 | /******************************************************************************* | ||
116 | * | ||
117 | * FUNCTION: acpi_ds_result_remove | ||
118 | * | ||
119 | * PARAMETERS: Object - Where to return the popped object | ||
120 | * Index - Where to extract the object | ||
121 | * walk_state - Current Walk state | ||
122 | * | ||
123 | * RETURN: Status | ||
124 | * | ||
125 | * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In | ||
126 | * other words, this is a FIFO. | ||
127 | * | ||
128 | ******************************************************************************/ | ||
129 | |||
130 | acpi_status | ||
131 | acpi_ds_result_remove ( | ||
132 | union acpi_operand_object **object, | ||
133 | u32 index, | ||
134 | struct acpi_walk_state *walk_state) | ||
135 | { | ||
136 | union acpi_generic_state *state; | ||
137 | |||
138 | |||
139 | ACPI_FUNCTION_NAME ("ds_result_remove"); | ||
140 | |||
141 | |||
142 | state = walk_state->results; | ||
143 | if (!state) { | ||
144 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", | ||
145 | walk_state)); | ||
146 | return (AE_NOT_EXIST); | ||
147 | } | ||
148 | |||
149 | if (index >= ACPI_OBJ_MAX_OPERAND) { | ||
150 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
151 | "Index out of range: %X State=%p Num=%X\n", | ||
152 | index, walk_state, state->results.num_results)); | ||
153 | } | ||
154 | |||
155 | /* Check for a valid result object */ | ||
156 | |||
157 | if (!state->results.obj_desc [index]) { | ||
158 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
159 | "Null operand! State=%p #Ops=%X, Index=%X\n", | ||
160 | walk_state, state->results.num_results, index)); | ||
161 | return (AE_AML_NO_RETURN_VALUE); | ||
162 | } | ||
163 | |||
164 | /* Remove the object */ | ||
165 | |||
166 | state->results.num_results--; | ||
167 | |||
168 | *object = state->results.obj_desc [index]; | ||
169 | state->results.obj_desc [index] = NULL; | ||
170 | |||
171 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
172 | "Obj=%p [%s] Index=%X State=%p Num=%X\n", | ||
173 | *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", | ||
174 | index, walk_state, state->results.num_results)); | ||
175 | |||
176 | return (AE_OK); | ||
177 | } | ||
178 | |||
179 | #endif /* ACPI_FUTURE_USAGE */ | ||
180 | |||
181 | |||
182 | /******************************************************************************* | ||
183 | * | ||
184 | * FUNCTION: acpi_ds_result_pop | ||
185 | * | ||
186 | * PARAMETERS: Object - Where to return the popped object | ||
187 | * walk_state - Current Walk state | ||
188 | * | ||
189 | * RETURN: Status | ||
190 | * | ||
191 | * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In | ||
192 | * other words, this is a FIFO. | ||
193 | * | ||
194 | ******************************************************************************/ | ||
195 | |||
196 | acpi_status | ||
197 | acpi_ds_result_pop ( | ||
198 | union acpi_operand_object **object, | ||
199 | struct acpi_walk_state *walk_state) | ||
200 | { | ||
201 | acpi_native_uint index; | ||
202 | union acpi_generic_state *state; | ||
203 | |||
204 | |||
205 | ACPI_FUNCTION_NAME ("ds_result_pop"); | ||
206 | |||
207 | |||
208 | state = walk_state->results; | ||
209 | if (!state) { | ||
210 | return (AE_OK); | ||
211 | } | ||
212 | |||
213 | if (!state->results.num_results) { | ||
214 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Result stack is empty! State=%p\n", | ||
215 | walk_state)); | ||
216 | return (AE_AML_NO_RETURN_VALUE); | ||
217 | } | ||
218 | |||
219 | /* Remove top element */ | ||
220 | |||
221 | state->results.num_results--; | ||
222 | |||
223 | for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) { | ||
224 | /* Check for a valid result object */ | ||
225 | |||
226 | if (state->results.obj_desc [index -1]) { | ||
227 | *object = state->results.obj_desc [index -1]; | ||
228 | state->results.obj_desc [index -1] = NULL; | ||
229 | |||
230 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n", | ||
231 | *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", | ||
232 | (u32) index -1, walk_state, state->results.num_results)); | ||
233 | |||
234 | return (AE_OK); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); | ||
239 | return (AE_AML_NO_RETURN_VALUE); | ||
240 | } | ||
241 | |||
242 | |||
243 | /******************************************************************************* | ||
244 | * | ||
245 | * FUNCTION: acpi_ds_result_pop_from_bottom | ||
246 | * | ||
247 | * PARAMETERS: Object - Where to return the popped object | ||
248 | * walk_state - Current Walk state | ||
249 | * | ||
250 | * RETURN: Status | ||
251 | * | ||
252 | * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In | ||
253 | * other words, this is a FIFO. | ||
254 | * | ||
255 | ******************************************************************************/ | ||
256 | |||
257 | acpi_status | ||
258 | acpi_ds_result_pop_from_bottom ( | ||
259 | union acpi_operand_object **object, | ||
260 | struct acpi_walk_state *walk_state) | ||
261 | { | ||
262 | acpi_native_uint index; | ||
263 | union acpi_generic_state *state; | ||
264 | |||
265 | |||
266 | ACPI_FUNCTION_NAME ("ds_result_pop_from_bottom"); | ||
267 | |||
268 | |||
269 | state = walk_state->results; | ||
270 | if (!state) { | ||
271 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
272 | "Warning: No result object pushed! State=%p\n", walk_state)); | ||
273 | return (AE_NOT_EXIST); | ||
274 | } | ||
275 | |||
276 | if (!state->results.num_results) { | ||
277 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); | ||
278 | return (AE_AML_NO_RETURN_VALUE); | ||
279 | } | ||
280 | |||
281 | /* Remove Bottom element */ | ||
282 | |||
283 | *object = state->results.obj_desc [0]; | ||
284 | |||
285 | /* Push entire stack down one element */ | ||
286 | |||
287 | for (index = 0; index < state->results.num_results; index++) { | ||
288 | state->results.obj_desc [index] = state->results.obj_desc [index + 1]; | ||
289 | } | ||
290 | |||
291 | state->results.num_results--; | ||
292 | |||
293 | /* Check for a valid result object */ | ||
294 | |||
295 | if (!*object) { | ||
296 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n", | ||
297 | walk_state, state->results.num_results, (u32) index)); | ||
298 | return (AE_AML_NO_RETURN_VALUE); | ||
299 | } | ||
300 | |||
301 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s], Results=%p State=%p\n", | ||
302 | *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", | ||
303 | state, walk_state)); | ||
304 | |||
305 | return (AE_OK); | ||
306 | } | ||
307 | |||
308 | |||
309 | /******************************************************************************* | ||
310 | * | ||
311 | * FUNCTION: acpi_ds_result_push | ||
312 | * | ||
313 | * PARAMETERS: Object - Where to return the popped object | ||
314 | * walk_state - Current Walk state | ||
315 | * | ||
316 | * RETURN: Status | ||
317 | * | ||
318 | * DESCRIPTION: Push an object onto the current result stack | ||
319 | * | ||
320 | ******************************************************************************/ | ||
321 | |||
322 | acpi_status | ||
323 | acpi_ds_result_push ( | ||
324 | union acpi_operand_object *object, | ||
325 | struct acpi_walk_state *walk_state) | ||
326 | { | ||
327 | union acpi_generic_state *state; | ||
328 | |||
329 | |||
330 | ACPI_FUNCTION_NAME ("ds_result_push"); | ||
331 | |||
332 | |||
333 | state = walk_state->results; | ||
334 | if (!state) { | ||
335 | ACPI_REPORT_ERROR (("No result stack frame during push\n")); | ||
336 | return (AE_AML_INTERNAL); | ||
337 | } | ||
338 | |||
339 | if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) { | ||
340 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
341 | "Result stack overflow: Obj=%p State=%p Num=%X\n", | ||
342 | object, walk_state, state->results.num_results)); | ||
343 | return (AE_STACK_OVERFLOW); | ||
344 | } | ||
345 | |||
346 | if (!object) { | ||
347 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n", | ||
348 | object, walk_state, state->results.num_results)); | ||
349 | return (AE_BAD_PARAMETER); | ||
350 | } | ||
351 | |||
352 | state->results.obj_desc [state->results.num_results] = object; | ||
353 | state->results.num_results++; | ||
354 | |||
355 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n", | ||
356 | object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", | ||
357 | walk_state, state->results.num_results, walk_state->current_result)); | ||
358 | |||
359 | return (AE_OK); | ||
360 | } | ||
361 | |||
362 | |||
363 | /******************************************************************************* | ||
364 | * | ||
365 | * FUNCTION: acpi_ds_result_stack_push | ||
366 | * | ||
367 | * PARAMETERS: walk_state - Current Walk state | ||
368 | * | ||
369 | * RETURN: Status | ||
370 | * | ||
371 | * DESCRIPTION: Push an object onto the walk_state result stack. | ||
372 | * | ||
373 | ******************************************************************************/ | ||
374 | |||
375 | acpi_status | ||
376 | acpi_ds_result_stack_push ( | ||
377 | struct acpi_walk_state *walk_state) | ||
378 | { | ||
379 | union acpi_generic_state *state; | ||
380 | |||
381 | ACPI_FUNCTION_NAME ("ds_result_stack_push"); | ||
382 | |||
383 | |||
384 | state = acpi_ut_create_generic_state (); | ||
385 | if (!state) { | ||
386 | return (AE_NO_MEMORY); | ||
387 | } | ||
388 | |||
389 | state->common.data_type = ACPI_DESC_TYPE_STATE_RESULT; | ||
390 | acpi_ut_push_generic_state (&walk_state->results, state); | ||
391 | |||
392 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Results=%p State=%p\n", | ||
393 | state, walk_state)); | ||
394 | |||
395 | return (AE_OK); | ||
396 | } | ||
397 | |||
398 | |||
399 | /******************************************************************************* | ||
400 | * | ||
401 | * FUNCTION: acpi_ds_result_stack_pop | ||
402 | * | ||
403 | * PARAMETERS: walk_state - Current Walk state | ||
404 | * | ||
405 | * RETURN: Status | ||
406 | * | ||
407 | * DESCRIPTION: Pop an object off of the walk_state result stack. | ||
408 | * | ||
409 | ******************************************************************************/ | ||
410 | |||
411 | acpi_status | ||
412 | acpi_ds_result_stack_pop ( | ||
413 | struct acpi_walk_state *walk_state) | ||
414 | { | ||
415 | union acpi_generic_state *state; | ||
416 | |||
417 | ACPI_FUNCTION_NAME ("ds_result_stack_pop"); | ||
418 | |||
419 | |||
420 | /* Check for stack underflow */ | ||
421 | |||
422 | if (walk_state->results == NULL) { | ||
423 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Underflow - State=%p\n", | ||
424 | walk_state)); | ||
425 | return (AE_AML_NO_OPERAND); | ||
426 | } | ||
427 | |||
428 | state = acpi_ut_pop_generic_state (&walk_state->results); | ||
429 | |||
430 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, | ||
431 | "Result=%p remaining_results=%X State=%p\n", | ||
432 | state, state->results.num_results, walk_state)); | ||
433 | |||
434 | acpi_ut_delete_generic_state (state); | ||
435 | |||
436 | return (AE_OK); | ||
437 | } | ||
438 | |||
439 | |||
440 | /******************************************************************************* | ||
441 | * | ||
442 | * FUNCTION: acpi_ds_obj_stack_delete_all | ||
443 | * | ||
444 | * PARAMETERS: walk_state - Current Walk state | ||
445 | * | ||
446 | * RETURN: Status | ||
447 | * | ||
448 | * DESCRIPTION: Clear the object stack by deleting all objects that are on it. | ||
449 | * Should be used with great care, if at all! | ||
450 | * | ||
451 | ******************************************************************************/ | ||
452 | #ifdef ACPI_FUTURE_USAGE | ||
453 | acpi_status | ||
454 | acpi_ds_obj_stack_delete_all ( | ||
455 | struct acpi_walk_state *walk_state) | ||
456 | { | ||
457 | u32 i; | ||
458 | |||
459 | |||
460 | ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); | ||
461 | |||
462 | |||
463 | /* The stack size is configurable, but fixed */ | ||
464 | |||
465 | for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { | ||
466 | if (walk_state->operands[i]) { | ||
467 | acpi_ut_remove_reference (walk_state->operands[i]); | ||
468 | walk_state->operands[i] = NULL; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return_ACPI_STATUS (AE_OK); | ||
473 | } | ||
474 | #endif /* ACPI_FUTURE_USAGE */ | ||
475 | |||
476 | |||
477 | /******************************************************************************* | ||
478 | * | ||
479 | * FUNCTION: acpi_ds_obj_stack_push | ||
480 | * | ||
481 | * PARAMETERS: Object - Object to push | ||
482 | * walk_state - Current Walk state | ||
483 | * | ||
484 | * RETURN: Status | ||
485 | * | ||
486 | * DESCRIPTION: Push an object onto this walk's object/operand stack | ||
487 | * | ||
488 | ******************************************************************************/ | ||
489 | |||
490 | acpi_status | ||
491 | acpi_ds_obj_stack_push ( | ||
492 | void *object, | ||
493 | struct acpi_walk_state *walk_state) | ||
494 | { | ||
495 | ACPI_FUNCTION_NAME ("ds_obj_stack_push"); | ||
496 | |||
497 | |||
498 | /* Check for stack overflow */ | ||
499 | |||
500 | if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) { | ||
501 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
502 | "overflow! Obj=%p State=%p #Ops=%X\n", | ||
503 | object, walk_state, walk_state->num_operands)); | ||
504 | return (AE_STACK_OVERFLOW); | ||
505 | } | ||
506 | |||
507 | /* Put the object onto the stack */ | ||
508 | |||
509 | walk_state->operands [walk_state->num_operands] = object; | ||
510 | walk_state->num_operands++; | ||
511 | |||
512 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", | ||
513 | object, acpi_ut_get_object_type_name ((union acpi_operand_object *) object), | ||
514 | walk_state, walk_state->num_operands)); | ||
515 | |||
516 | return (AE_OK); | ||
517 | } | ||
518 | |||
519 | |||
520 | #if 0 | ||
521 | /******************************************************************************* | ||
522 | * | ||
523 | * FUNCTION: acpi_ds_obj_stack_pop_object | ||
524 | * | ||
525 | * PARAMETERS: pop_count - Number of objects/entries to pop | ||
526 | * walk_state - Current Walk state | ||
527 | * | ||
528 | * RETURN: Status | ||
529 | * | ||
530 | * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT | ||
531 | * deleted by this routine. | ||
532 | * | ||
533 | ******************************************************************************/ | ||
534 | |||
535 | acpi_status | ||
536 | acpi_ds_obj_stack_pop_object ( | ||
537 | union acpi_operand_object **object, | ||
538 | struct acpi_walk_state *walk_state) | ||
539 | { | ||
540 | ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); | ||
541 | |||
542 | |||
543 | /* Check for stack underflow */ | ||
544 | |||
545 | if (walk_state->num_operands == 0) { | ||
546 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
547 | "Missing operand/stack empty! State=%p #Ops=%X\n", | ||
548 | walk_state, walk_state->num_operands)); | ||
549 | *object = NULL; | ||
550 | return (AE_AML_NO_OPERAND); | ||
551 | } | ||
552 | |||
553 | /* Pop the stack */ | ||
554 | |||
555 | walk_state->num_operands--; | ||
556 | |||
557 | /* Check for a valid operand */ | ||
558 | |||
559 | if (!walk_state->operands [walk_state->num_operands]) { | ||
560 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
561 | "Null operand! State=%p #Ops=%X\n", | ||
562 | walk_state, walk_state->num_operands)); | ||
563 | *object = NULL; | ||
564 | return (AE_AML_NO_OPERAND); | ||
565 | } | ||
566 | |||
567 | /* Get operand and set stack entry to null */ | ||
568 | |||
569 | *object = walk_state->operands [walk_state->num_operands]; | ||
570 | walk_state->operands [walk_state->num_operands] = NULL; | ||
571 | |||
572 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", | ||
573 | *object, acpi_ut_get_object_type_name (*object), | ||
574 | walk_state, walk_state->num_operands)); | ||
575 | |||
576 | return (AE_OK); | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | |||
581 | /******************************************************************************* | ||
582 | * | ||
583 | * FUNCTION: acpi_ds_obj_stack_pop | ||
584 | * | ||
585 | * PARAMETERS: pop_count - Number of objects/entries to pop | ||
586 | * walk_state - Current Walk state | ||
587 | * | ||
588 | * RETURN: Status | ||
589 | * | ||
590 | * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT | ||
591 | * deleted by this routine. | ||
592 | * | ||
593 | ******************************************************************************/ | ||
594 | |||
595 | acpi_status | ||
596 | acpi_ds_obj_stack_pop ( | ||
597 | u32 pop_count, | ||
598 | struct acpi_walk_state *walk_state) | ||
599 | { | ||
600 | u32 i; | ||
601 | |||
602 | ACPI_FUNCTION_NAME ("ds_obj_stack_pop"); | ||
603 | |||
604 | |||
605 | for (i = 0; i < pop_count; i++) { | ||
606 | /* Check for stack underflow */ | ||
607 | |||
608 | if (walk_state->num_operands == 0) { | ||
609 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
610 | "Underflow! Count=%X State=%p #Ops=%X\n", | ||
611 | pop_count, walk_state, walk_state->num_operands)); | ||
612 | return (AE_STACK_UNDERFLOW); | ||
613 | } | ||
614 | |||
615 | /* Just set the stack entry to null */ | ||
616 | |||
617 | walk_state->num_operands--; | ||
618 | walk_state->operands [walk_state->num_operands] = NULL; | ||
619 | } | ||
620 | |||
621 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", | ||
622 | pop_count, walk_state, walk_state->num_operands)); | ||
623 | |||
624 | return (AE_OK); | ||
625 | } | ||
626 | |||
627 | |||
628 | /******************************************************************************* | ||
629 | * | ||
630 | * FUNCTION: acpi_ds_obj_stack_pop_and_delete | ||
631 | * | ||
632 | * PARAMETERS: pop_count - Number of objects/entries to pop | ||
633 | * walk_state - Current Walk state | ||
634 | * | ||
635 | * RETURN: Status | ||
636 | * | ||
637 | * DESCRIPTION: Pop this walk's object stack and delete each object that is | ||
638 | * popped off. | ||
639 | * | ||
640 | ******************************************************************************/ | ||
641 | |||
642 | acpi_status | ||
643 | acpi_ds_obj_stack_pop_and_delete ( | ||
644 | u32 pop_count, | ||
645 | struct acpi_walk_state *walk_state) | ||
646 | { | ||
647 | u32 i; | ||
648 | union acpi_operand_object *obj_desc; | ||
649 | |||
650 | |||
651 | ACPI_FUNCTION_NAME ("ds_obj_stack_pop_and_delete"); | ||
652 | |||
653 | |||
654 | for (i = 0; i < pop_count; i++) { | ||
655 | /* Check for stack underflow */ | ||
656 | |||
657 | if (walk_state->num_operands == 0) { | ||
658 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | ||
659 | "Underflow! Count=%X State=%p #Ops=%X\n", | ||
660 | pop_count, walk_state, walk_state->num_operands)); | ||
661 | return (AE_STACK_UNDERFLOW); | ||
662 | } | ||
663 | |||
664 | /* Pop the stack and delete an object if present in this stack entry */ | ||
665 | |||
666 | walk_state->num_operands--; | ||
667 | obj_desc = walk_state->operands [walk_state->num_operands]; | ||
668 | if (obj_desc) { | ||
669 | acpi_ut_remove_reference (walk_state->operands [walk_state->num_operands]); | ||
670 | walk_state->operands [walk_state->num_operands] = NULL; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", | ||
675 | pop_count, walk_state, walk_state->num_operands)); | ||
676 | |||
677 | return (AE_OK); | ||
678 | } | ||
679 | |||
680 | |||
681 | /******************************************************************************* | ||
682 | * | ||
683 | * FUNCTION: acpi_ds_obj_stack_get_value | ||
684 | * | ||
685 | * PARAMETERS: Index - Stack index whose value is desired. Based | ||
686 | * on the top of the stack (index=0 == top) | ||
687 | * walk_state - Current Walk state | ||
688 | * | ||
689 | * RETURN: Status | ||
690 | * | ||
691 | * DESCRIPTION: Retrieve an object from this walk's object stack. Index must | ||
692 | * be within the range of the current stack pointer. | ||
693 | * | ||
694 | ******************************************************************************/ | ||
695 | #ifdef ACPI_FUTURE_USAGE | ||
696 | void * | ||
697 | acpi_ds_obj_stack_get_value ( | ||
698 | u32 index, | ||
699 | struct acpi_walk_state *walk_state) | ||
700 | { | ||
701 | |||
702 | ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); | ||
703 | |||
704 | |||
705 | /* Can't do it if the stack is empty */ | ||
706 | |||
707 | if (walk_state->num_operands == 0) { | ||
708 | return_PTR (NULL); | ||
709 | } | ||
710 | |||
711 | /* or if the index is past the top of the stack */ | ||
712 | |||
713 | if (index > (walk_state->num_operands - (u32) 1)) { | ||
714 | return_PTR (NULL); | ||
715 | } | ||
716 | |||
717 | return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - | ||
718 | index]); | ||
719 | } | ||
720 | #endif /* ACPI_FUTURE_USAGE */ | ||
721 | |||
722 | |||
723 | /******************************************************************************* | ||
724 | * | ||
725 | * FUNCTION: acpi_ds_get_current_walk_state | ||
726 | * | ||
727 | * PARAMETERS: Thread - Get current active state for this Thread | ||
728 | * | ||
729 | * RETURN: Pointer to the current walk state | ||
730 | * | ||
731 | * DESCRIPTION: Get the walk state that is at the head of the list (the "current" | ||
732 | * walk state.) | ||
733 | * | ||
734 | ******************************************************************************/ | ||
735 | |||
736 | struct acpi_walk_state * | ||
737 | acpi_ds_get_current_walk_state ( | ||
738 | struct acpi_thread_state *thread) | ||
739 | |||
740 | { | ||
741 | ACPI_FUNCTION_NAME ("ds_get_current_walk_state"); | ||
742 | |||
743 | |||
744 | if (!thread) { | ||
745 | return (NULL); | ||
746 | } | ||
747 | |||
748 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Current walk_state %p\n", | ||
749 | thread->walk_state_list)); | ||
750 | |||
751 | return (thread->walk_state_list); | ||
752 | } | ||
753 | |||
754 | |||
755 | /******************************************************************************* | ||
756 | * | ||
757 | * FUNCTION: acpi_ds_push_walk_state | ||
758 | * | ||
759 | * PARAMETERS: walk_state - State to push | ||
760 | * walk_list - The list that owns the walk stack | ||
761 | * | ||
762 | * RETURN: None | ||
763 | * | ||
764 | * DESCRIPTION: Place the walk_state at the head of the state list. | ||
765 | * | ||
766 | ******************************************************************************/ | ||
767 | |||
768 | void | ||
769 | acpi_ds_push_walk_state ( | ||
770 | struct acpi_walk_state *walk_state, | ||
771 | struct acpi_thread_state *thread) | ||
772 | { | ||
773 | ACPI_FUNCTION_TRACE ("ds_push_walk_state"); | ||
774 | |||
775 | |||
776 | walk_state->next = thread->walk_state_list; | ||
777 | thread->walk_state_list = walk_state; | ||
778 | |||
779 | return_VOID; | ||
780 | } | ||
781 | |||
782 | |||
783 | /******************************************************************************* | ||
784 | * | ||
785 | * FUNCTION: acpi_ds_pop_walk_state | ||
786 | * | ||
787 | * PARAMETERS: walk_list - The list that owns the walk stack | ||
788 | * | ||
789 | * RETURN: A walk_state object popped from the stack | ||
790 | * | ||
791 | * DESCRIPTION: Remove and return the walkstate object that is at the head of | ||
792 | * the walk stack for the given walk list. NULL indicates that | ||
793 | * the list is empty. | ||
794 | * | ||
795 | ******************************************************************************/ | ||
796 | |||
797 | struct acpi_walk_state * | ||
798 | acpi_ds_pop_walk_state ( | ||
799 | struct acpi_thread_state *thread) | ||
800 | { | ||
801 | struct acpi_walk_state *walk_state; | ||
802 | |||
803 | |||
804 | ACPI_FUNCTION_TRACE ("ds_pop_walk_state"); | ||
805 | |||
806 | |||
807 | walk_state = thread->walk_state_list; | ||
808 | |||
809 | if (walk_state) { | ||
810 | /* Next walk state becomes the current walk state */ | ||
811 | |||
812 | thread->walk_state_list = walk_state->next; | ||
813 | |||
814 | /* | ||
815 | * Don't clear the NEXT field, this serves as an indicator | ||
816 | * that there is a parent WALK STATE | ||
817 | * NO: walk_state->Next = NULL; | ||
818 | */ | ||
819 | } | ||
820 | |||
821 | return_PTR (walk_state); | ||
822 | } | ||
823 | |||
824 | |||
825 | /******************************************************************************* | ||
826 | * | ||
827 | * FUNCTION: acpi_ds_create_walk_state | ||
828 | * | ||
829 | * PARAMETERS: Origin - Starting point for this walk | ||
830 | * Thread - Current thread state | ||
831 | * | ||
832 | * RETURN: Pointer to the new walk state. | ||
833 | * | ||
834 | * DESCRIPTION: Allocate and initialize a new walk state. The current walk | ||
835 | * state is set to this new state. | ||
836 | * | ||
837 | ******************************************************************************/ | ||
838 | |||
839 | struct acpi_walk_state * | ||
840 | acpi_ds_create_walk_state ( | ||
841 | acpi_owner_id owner_id, | ||
842 | union acpi_parse_object *origin, | ||
843 | union acpi_operand_object *mth_desc, | ||
844 | struct acpi_thread_state *thread) | ||
845 | { | ||
846 | struct acpi_walk_state *walk_state; | ||
847 | acpi_status status; | ||
848 | |||
849 | |||
850 | ACPI_FUNCTION_TRACE ("ds_create_walk_state"); | ||
851 | |||
852 | |||
853 | walk_state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_WALK); | ||
854 | if (!walk_state) { | ||
855 | return_PTR (NULL); | ||
856 | } | ||
857 | |||
858 | walk_state->data_type = ACPI_DESC_TYPE_WALK; | ||
859 | walk_state->owner_id = owner_id; | ||
860 | walk_state->origin = origin; | ||
861 | walk_state->method_desc = mth_desc; | ||
862 | walk_state->thread = thread; | ||
863 | |||
864 | walk_state->parser_state.start_op = origin; | ||
865 | |||
866 | /* Init the method args/local */ | ||
867 | |||
868 | #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) | ||
869 | acpi_ds_method_data_init (walk_state); | ||
870 | #endif | ||
871 | |||
872 | /* Create an initial result stack entry */ | ||
873 | |||
874 | status = acpi_ds_result_stack_push (walk_state); | ||
875 | if (ACPI_FAILURE (status)) { | ||
876 | acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state); | ||
877 | return_PTR (NULL); | ||
878 | } | ||
879 | |||
880 | /* Put the new state at the head of the walk list */ | ||
881 | |||
882 | if (thread) { | ||
883 | acpi_ds_push_walk_state (walk_state, thread); | ||
884 | } | ||
885 | |||
886 | return_PTR (walk_state); | ||
887 | } | ||
888 | |||
889 | |||
890 | /******************************************************************************* | ||
891 | * | ||
892 | * FUNCTION: acpi_ds_init_aml_walk | ||
893 | * | ||
894 | * PARAMETERS: walk_state - New state to be initialized | ||
895 | * Op - Current parse op | ||
896 | * method_node - Control method NS node, if any | ||
897 | * aml_start - Start of AML | ||
898 | * aml_length - Length of AML | ||
899 | * Params - Method args, if any | ||
900 | * return_obj_desc - Where to store a return object, if any | ||
901 | * pass_number - 1, 2, or 3 | ||
902 | * | ||
903 | * RETURN: Status | ||
904 | * | ||
905 | * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk | ||
906 | * | ||
907 | ******************************************************************************/ | ||
908 | |||
909 | acpi_status | ||
910 | acpi_ds_init_aml_walk ( | ||
911 | struct acpi_walk_state *walk_state, | ||
912 | union acpi_parse_object *op, | ||
913 | struct acpi_namespace_node *method_node, | ||
914 | u8 *aml_start, | ||
915 | u32 aml_length, | ||
916 | struct acpi_parameter_info *info, | ||
917 | u32 pass_number) | ||
918 | { | ||
919 | acpi_status status; | ||
920 | struct acpi_parse_state *parser_state = &walk_state->parser_state; | ||
921 | union acpi_parse_object *extra_op; | ||
922 | |||
923 | |||
924 | ACPI_FUNCTION_TRACE ("ds_init_aml_walk"); | ||
925 | |||
926 | |||
927 | walk_state->parser_state.aml = | ||
928 | walk_state->parser_state.aml_start = aml_start; | ||
929 | walk_state->parser_state.aml_end = | ||
930 | walk_state->parser_state.pkg_end = aml_start + aml_length; | ||
931 | |||
932 | /* The next_op of the next_walk will be the beginning of the method */ | ||
933 | |||
934 | walk_state->next_op = NULL; | ||
935 | |||
936 | if (info) { | ||
937 | if (info->parameter_type == ACPI_PARAM_GPE) { | ||
938 | walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info, | ||
939 | info->parameters); | ||
940 | } | ||
941 | else { | ||
942 | walk_state->params = info->parameters; | ||
943 | walk_state->caller_return_desc = &info->return_object; | ||
944 | } | ||
945 | } | ||
946 | |||
947 | status = acpi_ps_init_scope (&walk_state->parser_state, op); | ||
948 | if (ACPI_FAILURE (status)) { | ||
949 | return_ACPI_STATUS (status); | ||
950 | } | ||
951 | |||
952 | if (method_node) { | ||
953 | walk_state->parser_state.start_node = method_node; | ||
954 | walk_state->walk_type = ACPI_WALK_METHOD; | ||
955 | walk_state->method_node = method_node; | ||
956 | walk_state->method_desc = acpi_ns_get_attached_object (method_node); | ||
957 | |||
958 | /* Push start scope on scope stack and make it current */ | ||
959 | |||
960 | status = acpi_ds_scope_stack_push (method_node, ACPI_TYPE_METHOD, walk_state); | ||
961 | if (ACPI_FAILURE (status)) { | ||
962 | return_ACPI_STATUS (status); | ||
963 | } | ||
964 | |||
965 | /* Init the method arguments */ | ||
966 | |||
967 | status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); | ||
968 | if (ACPI_FAILURE (status)) { | ||
969 | return_ACPI_STATUS (status); | ||
970 | } | ||
971 | } | ||
972 | else { | ||
973 | /* | ||
974 | * Setup the current scope. | ||
975 | * Find a Named Op that has a namespace node associated with it. | ||
976 | * search upwards from this Op. Current scope is the first | ||
977 | * Op with a namespace node. | ||
978 | */ | ||
979 | extra_op = parser_state->start_op; | ||
980 | while (extra_op && !extra_op->common.node) { | ||
981 | extra_op = extra_op->common.parent; | ||
982 | } | ||
983 | |||
984 | if (!extra_op) { | ||
985 | parser_state->start_node = NULL; | ||
986 | } | ||
987 | else { | ||
988 | parser_state->start_node = extra_op->common.node; | ||
989 | } | ||
990 | |||
991 | if (parser_state->start_node) { | ||
992 | /* Push start scope on scope stack and make it current */ | ||
993 | |||
994 | status = acpi_ds_scope_stack_push (parser_state->start_node, | ||
995 | parser_state->start_node->type, walk_state); | ||
996 | if (ACPI_FAILURE (status)) { | ||
997 | return_ACPI_STATUS (status); | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | |||
1002 | status = acpi_ds_init_callbacks (walk_state, pass_number); | ||
1003 | return_ACPI_STATUS (status); | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | /******************************************************************************* | ||
1008 | * | ||
1009 | * FUNCTION: acpi_ds_delete_walk_state | ||
1010 | * | ||
1011 | * PARAMETERS: walk_state - State to delete | ||
1012 | * | ||
1013 | * RETURN: Status | ||
1014 | * | ||
1015 | * DESCRIPTION: Delete a walk state including all internal data structures | ||
1016 | * | ||
1017 | ******************************************************************************/ | ||
1018 | |||
1019 | void | ||
1020 | acpi_ds_delete_walk_state ( | ||
1021 | struct acpi_walk_state *walk_state) | ||
1022 | { | ||
1023 | union acpi_generic_state *state; | ||
1024 | |||
1025 | |||
1026 | ACPI_FUNCTION_TRACE_PTR ("ds_delete_walk_state", walk_state); | ||
1027 | |||
1028 | |||
1029 | if (!walk_state) { | ||
1030 | return; | ||
1031 | } | ||
1032 | |||
1033 | if (walk_state->data_type != ACPI_DESC_TYPE_WALK) { | ||
1034 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state)); | ||
1035 | return; | ||
1036 | } | ||
1037 | |||
1038 | if (walk_state->parser_state.scope) { | ||
1039 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state)); | ||
1040 | } | ||
1041 | |||
1042 | /* Always must free any linked control states */ | ||
1043 | |||
1044 | while (walk_state->control_state) { | ||
1045 | state = walk_state->control_state; | ||
1046 | walk_state->control_state = state->common.next; | ||
1047 | |||
1048 | acpi_ut_delete_generic_state (state); | ||
1049 | } | ||
1050 | |||
1051 | /* Always must free any linked parse states */ | ||
1052 | |||
1053 | while (walk_state->scope_info) { | ||
1054 | state = walk_state->scope_info; | ||
1055 | walk_state->scope_info = state->common.next; | ||
1056 | |||
1057 | acpi_ut_delete_generic_state (state); | ||
1058 | } | ||
1059 | |||
1060 | /* Always must free any stacked result states */ | ||
1061 | |||
1062 | while (walk_state->results) { | ||
1063 | state = walk_state->results; | ||
1064 | walk_state->results = state->common.next; | ||
1065 | |||
1066 | acpi_ut_delete_generic_state (state); | ||
1067 | } | ||
1068 | |||
1069 | acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state); | ||
1070 | return_VOID; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | #ifdef ACPI_ENABLE_OBJECT_CACHE | ||
1075 | /****************************************************************************** | ||
1076 | * | ||
1077 | * FUNCTION: acpi_ds_delete_walk_state_cache | ||
1078 | * | ||
1079 | * PARAMETERS: None | ||
1080 | * | ||
1081 | * RETURN: Status | ||
1082 | * | ||
1083 | * DESCRIPTION: Purge the global state object cache. Used during subsystem | ||
1084 | * termination. | ||
1085 | * | ||
1086 | ******************************************************************************/ | ||
1087 | |||
1088 | void | ||
1089 | acpi_ds_delete_walk_state_cache ( | ||
1090 | void) | ||
1091 | { | ||
1092 | ACPI_FUNCTION_TRACE ("ds_delete_walk_state_cache"); | ||
1093 | |||
1094 | |||
1095 | acpi_ut_delete_generic_cache (ACPI_MEM_LIST_WALK); | ||
1096 | return_VOID; | ||
1097 | } | ||
1098 | #endif | ||
1099 | |||
1100 | |||