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