Merge trunk HEAD (r46369)
[reactos.git] / reactos / drivers / bus / acpi / dispatcher / dsmthdat.c
1 /*******************************************************************************
2 *
3 * Module Name: dsmthdat - control method arguments and local variables
4 * $Revision: 1.1 $
5 *
6 ******************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28
29 #define _COMPONENT ACPI_DISPATCHER
30 MODULE_NAME ("dsmthdat")
31
32
33 /*******************************************************************************
34 *
35 * FUNCTION: Acpi_ds_method_data_init
36 *
37 * PARAMETERS: Walk_state - Current walk state object
38 *
39 * RETURN: Status
40 *
41 * DESCRIPTION: Initialize the data structures that hold the method's arguments
42 * and locals. The data struct is an array of NTEs for each.
43 * This allows Ref_of and De_ref_of to work properly for these
44 * special data types.
45 *
46 ******************************************************************************/
47
48 ACPI_STATUS
49 acpi_ds_method_data_init (
50 ACPI_WALK_STATE *walk_state)
51 {
52 u32 i;
53
54
55 /*
56 * Walk_state fields are initialized to zero by the
57 * Acpi_cm_callocate().
58 *
59 * An Node is assigned to each argument and local so
60 * that Ref_of() can return a pointer to the Node.
61 */
62
63 /* Init the method arguments */
64
65 for (i = 0; i < MTH_NUM_ARGS; i++) {
66 MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name,
67 NAMEOF_ARG_NTE);
68 walk_state->arguments[i].name |= (i << 24);
69 walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED;
70 walk_state->arguments[i].type = ACPI_TYPE_ANY;
71 walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
72 }
73
74 /* Init the method locals */
75
76 for (i = 0; i < MTH_NUM_LOCALS; i++) {
77 MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name,
78 NAMEOF_LOCAL_NTE);
79
80 walk_state->local_variables[i].name |= (i << 24);
81 walk_state->local_variables[i].data_type = ACPI_DESC_TYPE_NAMED;
82 walk_state->local_variables[i].type = ACPI_TYPE_ANY;
83 walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
84 }
85
86 return (AE_OK);
87 }
88
89
90 /*******************************************************************************
91 *
92 * FUNCTION: Acpi_ds_method_data_delete_all
93 *
94 * PARAMETERS: Walk_state - Current walk state object
95 *
96 * RETURN: Status
97 *
98 * DESCRIPTION: Delete method locals and arguments. Arguments are only
99 * deleted if this method was called from another method.
100 *
101 ******************************************************************************/
102
103 ACPI_STATUS
104 acpi_ds_method_data_delete_all (
105 ACPI_WALK_STATE *walk_state)
106 {
107 u32 index;
108 ACPI_OPERAND_OBJECT *object;
109
110
111 /* Delete the locals */
112
113 for (index = 0; index < MTH_NUM_LOCALS; index++) {
114 object = walk_state->local_variables[index].object;
115 if (object) {
116 /* Remove first */
117
118 walk_state->local_variables[index].object = NULL;
119
120 /* Was given a ref when stored */
121
122 acpi_cm_remove_reference (object);
123 }
124 }
125
126
127 /* Delete the arguments */
128
129 for (index = 0; index < MTH_NUM_ARGS; index++) {
130 object = walk_state->arguments[index].object;
131 if (object) {
132 /* Remove first */
133
134 walk_state->arguments[index].object = NULL;
135
136 /* Was given a ref when stored */
137
138 acpi_cm_remove_reference (object);
139 }
140 }
141
142 return (AE_OK);
143 }
144
145
146 /*******************************************************************************
147 *
148 * FUNCTION: Acpi_ds_method_data_init_args
149 *
150 * PARAMETERS: *Params - Pointer to a parameter list for the method
151 * Max_param_count - The arg count for this method
152 * Walk_state - Current walk state object
153 *
154 * RETURN: Status
155 *
156 * DESCRIPTION: Initialize arguments for a method
157 *
158 ******************************************************************************/
159
160 ACPI_STATUS
161 acpi_ds_method_data_init_args (
162 ACPI_OPERAND_OBJECT **params,
163 u32 max_param_count,
164 ACPI_WALK_STATE *walk_state)
165 {
166 ACPI_STATUS status;
167 u32 mindex;
168 u32 pindex;
169
170
171 if (!params) {
172 return (AE_OK);
173 }
174
175 /* Copy passed parameters into the new method stack frame */
176
177 for (pindex = mindex = 0;
178 (mindex < MTH_NUM_ARGS) && (pindex < max_param_count);
179 mindex++) {
180 if (params[pindex]) {
181 /*
182 * A valid parameter.
183 * Set the current method argument to the
184 * Params[Pindex++] argument object descriptor
185 */
186 status = acpi_ds_store_object_to_local (AML_ARG_OP, mindex,
187 params[pindex], walk_state);
188 if (ACPI_FAILURE (status)) {
189 break;
190 }
191
192 pindex++;
193 }
194
195 else {
196 break;
197 }
198 }
199
200 return (AE_OK);
201 }
202
203
204 /*******************************************************************************
205 *
206 * FUNCTION: Acpi_ds_method_data_get_entry
207 *
208 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
209 * Index - Which local_var or argument to get
210 * Entry - Pointer to where a pointer to the stack
211 * entry is returned.
212 * Walk_state - Current walk state object
213 *
214 * RETURN: Status
215 *
216 * DESCRIPTION: Get the address of the object entry given by Opcode:Index
217 *
218 ******************************************************************************/
219
220 ACPI_STATUS
221 acpi_ds_method_data_get_entry (
222 u16 opcode,
223 u32 index,
224 ACPI_WALK_STATE *walk_state,
225 ACPI_OPERAND_OBJECT ***entry)
226 {
227
228
229 /*
230 * Get the requested object.
231 * The stack "Opcode" is either a Local_variable or an Argument
232 */
233
234 switch (opcode) {
235
236 case AML_LOCAL_OP:
237
238 if (index > MTH_MAX_LOCAL) {
239 return (AE_BAD_PARAMETER);
240 }
241
242 *entry = (ACPI_OPERAND_OBJECT **)
243 &walk_state->local_variables[index].object;
244 break;
245
246
247 case AML_ARG_OP:
248
249 if (index > MTH_MAX_ARG) {
250 return (AE_BAD_PARAMETER);
251 }
252
253 *entry = (ACPI_OPERAND_OBJECT **)
254 &walk_state->arguments[index].object;
255 break;
256
257
258 default:
259 return (AE_BAD_PARAMETER);
260 }
261
262
263 return (AE_OK);
264 }
265
266
267 /*******************************************************************************
268 *
269 * FUNCTION: Acpi_ds_method_data_set_entry
270 *
271 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
272 * Index - Which local_var or argument to get
273 * Object - Object to be inserted into the stack entry
274 * Walk_state - Current walk state object
275 *
276 * RETURN: Status
277 *
278 * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
279 *
280 ******************************************************************************/
281
282 ACPI_STATUS
283 acpi_ds_method_data_set_entry (
284 u16 opcode,
285 u32 index,
286 ACPI_OPERAND_OBJECT *object,
287 ACPI_WALK_STATE *walk_state)
288 {
289 ACPI_STATUS status;
290 ACPI_OPERAND_OBJECT **entry;
291
292
293 /* Get a pointer to the stack entry to set */
294
295 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
296 if (ACPI_FAILURE (status)) {
297 return (status);
298 }
299
300 /* Increment ref count so object can't be deleted while installed */
301
302 acpi_cm_add_reference (object);
303
304 /* Install the object into the stack entry */
305
306 *entry = object;
307
308 return (AE_OK);
309 }
310
311
312 /*******************************************************************************
313 *
314 * FUNCTION: Acpi_ds_method_data_get_type
315 *
316 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
317 * Index - Which local_var or argument whose type
318 * to get
319 * Walk_state - Current walk state object
320 *
321 * RETURN: Data type of selected Arg or Local
322 * Used only in Exec_monadic2()/Type_op.
323 *
324 ******************************************************************************/
325
326 OBJECT_TYPE_INTERNAL
327 acpi_ds_method_data_get_type (
328 u16 opcode,
329 u32 index,
330 ACPI_WALK_STATE *walk_state)
331 {
332 ACPI_STATUS status;
333 ACPI_OPERAND_OBJECT **entry;
334 ACPI_OPERAND_OBJECT *object;
335
336
337 /* Get a pointer to the requested stack entry */
338
339 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
340 if (ACPI_FAILURE (status)) {
341 return ((ACPI_TYPE_NOT_FOUND));
342 }
343
344 /* Get the object from the method stack */
345
346 object = *entry;
347
348 /* Get the object type */
349
350 if (!object) {
351 /* Any == 0 => "uninitialized" -- see spec 15.2.3.5.2.28 */
352 return (ACPI_TYPE_ANY);
353 }
354
355 return (object->common.type);
356 }
357
358
359 /*******************************************************************************
360 *
361 * FUNCTION: Acpi_ds_method_data_get_node
362 *
363 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
364 * Index - Which local_var or argument whose type
365 * to get
366 * Walk_state - Current walk state object
367 *
368 * RETURN: Get the Node associated with a local or arg.
369 *
370 ******************************************************************************/
371
372 ACPI_NAMESPACE_NODE *
373 acpi_ds_method_data_get_node (
374 u16 opcode,
375 u32 index,
376 ACPI_WALK_STATE *walk_state)
377 {
378 ACPI_NAMESPACE_NODE *node = NULL;
379
380
381 switch (opcode) {
382
383 case AML_LOCAL_OP:
384
385 if (index > MTH_MAX_LOCAL) {
386 return (node);
387 }
388
389 node = &walk_state->local_variables[index];
390 break;
391
392
393 case AML_ARG_OP:
394
395 if (index > MTH_MAX_ARG) {
396 return (node);
397 }
398
399 node = &walk_state->arguments[index];
400 break;
401
402
403 default:
404 break;
405 }
406
407
408 return (node);
409 }
410
411
412 /*******************************************************************************
413 *
414 * FUNCTION: Acpi_ds_method_data_get_value
415 *
416 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
417 * Index - Which local_var or argument to get
418 * Walk_state - Current walk state object
419 * *Dest_desc - Ptr to Descriptor into which selected Arg
420 * or Local value should be copied
421 *
422 * RETURN: Status
423 *
424 * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
425 * at the current top of the method stack.
426 * Used only in Acpi_aml_resolve_to_value().
427 *
428 ******************************************************************************/
429
430 ACPI_STATUS
431 acpi_ds_method_data_get_value (
432 u16 opcode,
433 u32 index,
434 ACPI_WALK_STATE *walk_state,
435 ACPI_OPERAND_OBJECT **dest_desc)
436 {
437 ACPI_STATUS status;
438 ACPI_OPERAND_OBJECT **entry;
439 ACPI_OPERAND_OBJECT *object;
440
441
442 /* Validate the object descriptor */
443
444 if (!dest_desc) {
445 return (AE_BAD_PARAMETER);
446 }
447
448
449 /* Get a pointer to the requested method stack entry */
450
451 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
452 if (ACPI_FAILURE (status)) {
453 return (status);
454 }
455
456 /* Get the object from the method stack */
457
458 object = *entry;
459
460
461 /* Examine the returned object, it must be valid. */
462
463 if (!object) {
464 /*
465 * Index points to uninitialized object stack value.
466 * This means that either 1) The expected argument was
467 * not passed to the method, or 2) A local variable
468 * was referenced by the method (via the ASL)
469 * before it was initialized. Either case is an error.
470 */
471
472 switch (opcode) {
473 case AML_ARG_OP:
474
475 return (AE_AML_UNINITIALIZED_ARG);
476 break;
477
478 case AML_LOCAL_OP:
479
480 return (AE_AML_UNINITIALIZED_LOCAL);
481 break;
482 }
483 }
484
485
486 /*
487 * Index points to initialized and valid object stack value.
488 * Return an additional reference to the object
489 */
490
491 *dest_desc = object;
492 acpi_cm_add_reference (object);
493
494 return (AE_OK);
495 }
496
497
498 /*******************************************************************************
499 *
500 * FUNCTION: Acpi_ds_method_data_delete_value
501 *
502 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
503 * Index - Which local_var or argument to delete
504 * Walk_state - Current walk state object
505 *
506 * RETURN: Status
507 *
508 * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts
509 * a null into the stack slot after the object is deleted.
510 *
511 ******************************************************************************/
512
513 ACPI_STATUS
514 acpi_ds_method_data_delete_value (
515 u16 opcode,
516 u32 index,
517 ACPI_WALK_STATE *walk_state)
518 {
519 ACPI_STATUS status;
520 ACPI_OPERAND_OBJECT **entry;
521 ACPI_OPERAND_OBJECT *object;
522
523
524 /* Get a pointer to the requested entry */
525
526 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
527 if (ACPI_FAILURE (status)) {
528 return (status);
529 }
530
531 /* Get the current entry in this slot k */
532
533 object = *entry;
534
535 /*
536 * Undefine the Arg or Local by setting its descriptor
537 * pointer to NULL. Locals/Args can contain both
538 * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
539 */
540 *entry = NULL;
541
542
543 if ((object) &&
544 (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) {
545 /*
546 * There is a valid object in this slot
547 * Decrement the reference count by one to balance the
548 * increment when the object was stored in the slot.
549 */
550 acpi_cm_remove_reference (object);
551 }
552
553
554 return (AE_OK);
555 }
556
557
558 /*******************************************************************************
559 *
560 * FUNCTION: Acpi_ds_store_object_to_local
561 *
562 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
563 * Index - Which local_var or argument to set
564 * Src_desc - Value to be stored
565 * Walk_state - Current walk state
566 *
567 * RETURN: Status
568 *
569 * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed
570 * as the new value for the Arg or Local and the reference count
571 * for Src_desc is incremented.
572 *
573 ******************************************************************************/
574
575 ACPI_STATUS
576 acpi_ds_store_object_to_local (
577 u16 opcode,
578 u32 index,
579 ACPI_OPERAND_OBJECT *src_desc,
580 ACPI_WALK_STATE *walk_state)
581 {
582 ACPI_STATUS status;
583 ACPI_OPERAND_OBJECT **entry;
584
585
586 /* Parameter validation */
587
588 if (!src_desc) {
589 return (AE_BAD_PARAMETER);
590 }
591
592
593 /* Get a pointer to the requested method stack entry */
594
595 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
596 if (ACPI_FAILURE (status)) {
597 goto cleanup;
598 }
599
600 if (*entry == src_desc) {
601 goto cleanup;
602 }
603
604
605 /*
606 * If there is an object already in this slot, we either
607 * have to delete it, or if this is an argument and there
608 * is an object reference stored there, we have to do
609 * an indirect store!
610 */
611
612 if (*entry) {
613 /*
614 * Check for an indirect store if an argument
615 * contains an object reference (stored as an Node).
616 * We don't allow this automatic dereferencing for
617 * locals, since a store to a local should overwrite
618 * anything there, including an object reference.
619 *
620 * If both Arg0 and Local0 contain Ref_of (Local4):
621 *
622 * Store (1, Arg0) - Causes indirect store to local4
623 * Store (1, Local0) - Stores 1 in local0, overwriting
624 * the reference to local4
625 * Store (1, De_refof (Local0)) - Causes indirect store to local4
626 *
627 * Weird, but true.
628 */
629
630 if ((opcode == AML_ARG_OP) &&
631 (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) {
632 /* Detach an existing object from the Node */
633
634 acpi_ns_detach_object ((ACPI_NAMESPACE_NODE *) *entry);
635
636 /*
637 * Store this object into the Node
638 * (do the indirect store)
639 */
640 status = acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) *entry, src_desc,
641 src_desc->common.type);
642 return (status);
643 }
644
645
646 #ifdef ACPI_ENABLE_IMPLICIT_CONVERSION
647 /*
648 * Perform "Implicit conversion" of the new object to the type of the
649 * existing object
650 */
651 status = acpi_aml_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state);
652 if (ACPI_FAILURE (status)) {
653 goto cleanup;
654 }
655 #endif
656
657 /*
658 * Delete the existing object
659 * before storing the new one
660 */
661 acpi_ds_method_data_delete_value (opcode, index, walk_state);
662 }
663
664
665 /*
666 * Install the Obj_stack descriptor (*Src_desc) into
667 * the descriptor for the Arg or Local.
668 * Install the new object in the stack entry
669 * (increments the object reference count by one)
670 */
671 status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state);
672 if (ACPI_FAILURE (status)) {
673 goto cleanup;
674 }
675
676 /* Normal exit */
677
678 return (AE_OK);
679
680
681 /* Error exit */
682
683 cleanup:
684
685 return (status);
686 }
687