update for HEAD-2003091401
[reactos.git] / drivers / bus / acpi / dispatcher / dswstate.c
1 /******************************************************************************
2  *
3  * Module Name: dswstate - Dispatcher parse tree walk management routines
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 "amlcode.h"
29 #include "acparser.h"
30 #include "acdispat.h"
31 #include "acnamesp.h"
32 #include "acinterp.h"
33
34 #define _COMPONENT          ACPI_DISPATCHER
35          MODULE_NAME         ("dswstate")
36
37
38 /*******************************************************************************
39  *
40  * FUNCTION:    Acpi_ds_result_insert
41  *
42  * PARAMETERS:  Object              - Object to push
43  *              Walk_state          - Current Walk state
44  *
45  * RETURN:      Status
46  *
47  * DESCRIPTION: Push an object onto this walk's result stack
48  *
49  ******************************************************************************/
50
51 ACPI_STATUS
52 acpi_ds_result_insert (
53         void                    *object,
54         u32                     index,
55         ACPI_WALK_STATE         *walk_state)
56 {
57         ACPI_GENERIC_STATE      *state;
58
59
60         state = walk_state->results;
61         if (!state) {
62                 return (AE_NOT_EXIST);
63         }
64
65         if (index >= OBJ_NUM_OPERANDS) {
66                 return (AE_BAD_PARAMETER);
67         }
68
69         if (!object) {
70                 return (AE_BAD_PARAMETER);
71         }
72
73         state->results.obj_desc [index] = object;
74         state->results.num_results++;
75
76         return (AE_OK);
77 }
78
79
80 /*******************************************************************************
81  *
82  * FUNCTION:    Acpi_ds_result_remove
83  *
84  * PARAMETERS:  Object              - Where to return the popped object
85  *              Walk_state          - Current Walk state
86  *
87  * RETURN:      Status
88  *
89  * DESCRIPTION: Pop an object off the bottom of this walk's result stack.  In
90  *              other words, this is a FIFO.
91  *
92  ******************************************************************************/
93
94 ACPI_STATUS
95 acpi_ds_result_remove (
96         ACPI_OPERAND_OBJECT     **object,
97         u32                     index,
98         ACPI_WALK_STATE         *walk_state)
99 {
100         ACPI_GENERIC_STATE      *state;
101
102
103         state = walk_state->results;
104         if (!state) {
105                 return (AE_NOT_EXIST);
106         }
107
108
109
110         /* Check for a valid result object */
111
112         if (!state->results.obj_desc [index]) {
113                 return (AE_AML_NO_RETURN_VALUE);
114         }
115
116         /* Remove the object */
117
118         state->results.num_results--;
119
120         *object = state->results.obj_desc [index];
121         state->results.obj_desc [index] = NULL;
122
123         return (AE_OK);
124 }
125
126
127 /*******************************************************************************
128  *
129  * FUNCTION:    Acpi_ds_result_pop
130  *
131  * PARAMETERS:  Object              - Where to return the popped object
132  *              Walk_state          - Current Walk state
133  *
134  * RETURN:      Status
135  *
136  * DESCRIPTION: Pop an object off the bottom of this walk's result stack.  In
137  *              other words, this is a FIFO.
138  *
139  ******************************************************************************/
140
141 ACPI_STATUS
142 acpi_ds_result_pop (
143         ACPI_OPERAND_OBJECT     **object,
144         ACPI_WALK_STATE         *walk_state)
145 {
146         u32                     index;
147         ACPI_GENERIC_STATE      *state;
148
149
150         state = walk_state->results;
151         if (!state) {
152                 return (AE_OK);
153         }
154
155
156         if (!state->results.num_results) {
157                 return (AE_AML_NO_RETURN_VALUE);
158         }
159
160         /* Remove top element */
161
162         state->results.num_results--;
163
164         for (index = OBJ_NUM_OPERANDS; index; index--) {
165                 /* Check for a valid result object */
166
167                 if (state->results.obj_desc [index -1]) {
168                         *object = state->results.obj_desc [index -1];
169                         state->results.obj_desc [index -1] = NULL;
170
171                         return (AE_OK);
172                 }
173         }
174
175
176         return (AE_AML_NO_RETURN_VALUE);
177 }
178
179 /*******************************************************************************
180  *
181  * FUNCTION:    Acpi_ds_result_pop_from_bottom
182  *
183  * PARAMETERS:  Object              - Where to return the popped object
184  *              Walk_state          - Current Walk state
185  *
186  * RETURN:      Status
187  *
188  * DESCRIPTION: Pop an object off the bottom of this walk's result stack.  In
189  *              other words, this is a FIFO.
190  *
191  ******************************************************************************/
192
193 ACPI_STATUS
194 acpi_ds_result_pop_from_bottom (
195         ACPI_OPERAND_OBJECT     **object,
196         ACPI_WALK_STATE         *walk_state)
197 {
198         u32                     index;
199         ACPI_GENERIC_STATE      *state;
200
201
202         state = walk_state->results;
203         if (!state) {
204                 return (AE_NOT_EXIST);
205         }
206
207
208         if (!state->results.num_results) {
209                 return (AE_AML_NO_RETURN_VALUE);
210         }
211
212         /* Remove Bottom element */
213
214         *object = state->results.obj_desc [0];
215
216
217         /* Push entire stack down one element */
218
219         for (index = 0; index < state->results.num_results; index++) {
220                 state->results.obj_desc [index] = state->results.obj_desc [index + 1];
221         }
222
223         state->results.num_results--;
224
225         /* Check for a valid result object */
226
227         if (!*object) {
228                 return (AE_AML_NO_RETURN_VALUE);
229         }
230
231
232         return (AE_OK);
233 }
234
235
236 /*******************************************************************************
237  *
238  * FUNCTION:    Acpi_ds_result_push
239  *
240  * PARAMETERS:  Object              - Where to return the popped object
241  *              Walk_state          - Current Walk state
242  *
243  * RETURN:      Status
244  *
245  * DESCRIPTION: Push an object onto the current result stack
246  *
247  ******************************************************************************/
248
249 ACPI_STATUS
250 acpi_ds_result_push (
251         ACPI_OPERAND_OBJECT     *object,
252         ACPI_WALK_STATE         *walk_state)
253 {
254         ACPI_GENERIC_STATE      *state;
255
256
257         state = walk_state->results;
258         if (!state) {
259                 return (AE_AML_INTERNAL);
260         }
261
262         if (state->results.num_results == OBJ_NUM_OPERANDS) {
263                 return (AE_STACK_OVERFLOW);
264         }
265
266         if (!object) {
267                 return (AE_BAD_PARAMETER);
268         }
269
270
271         state->results.obj_desc [state->results.num_results] = object;
272         state->results.num_results++;
273
274         return (AE_OK);
275 }
276
277
278 /*******************************************************************************
279  *
280  * FUNCTION:    Acpi_ds_result_stack_push
281  *
282  * PARAMETERS:  Object              - Object to push
283  *              Walk_state          - Current Walk state
284  *
285  * RETURN:      Status
286  *
287  * DESCRIPTION:
288  *
289  ******************************************************************************/
290
291 ACPI_STATUS
292 acpi_ds_result_stack_push (
293         ACPI_WALK_STATE         *walk_state)
294 {
295         ACPI_GENERIC_STATE      *state;
296
297
298         state = acpi_cm_create_generic_state ();
299         if (!state) {
300                 return (AE_NO_MEMORY);
301         }
302
303         acpi_cm_push_generic_state (&walk_state->results, state);
304
305         return (AE_OK);
306 }
307
308
309 /*******************************************************************************
310  *
311  * FUNCTION:    Acpi_ds_result_stack_pop
312  *
313  * PARAMETERS:  Walk_state          - Current Walk state
314  *
315  * RETURN:      Status
316  *
317  * DESCRIPTION:
318  *
319  ******************************************************************************/
320
321 ACPI_STATUS
322 acpi_ds_result_stack_pop (
323         ACPI_WALK_STATE         *walk_state)
324 {
325         ACPI_GENERIC_STATE      *state;
326
327
328         /* Check for stack underflow */
329
330         if (walk_state->results == NULL) {
331                 return (AE_AML_NO_OPERAND);
332         }
333
334
335         state = acpi_cm_pop_generic_state (&walk_state->results);
336
337         acpi_cm_delete_generic_state (state);
338
339         return (AE_OK);
340 }
341
342
343 /*******************************************************************************
344  *
345  * FUNCTION:    Acpi_ds_obj_stack_delete_all
346  *
347  * PARAMETERS:  Walk_state          - Current Walk state
348  *
349  * RETURN:      Status
350  *
351  * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
352  *              Should be used with great care, if at all!
353  *
354  ******************************************************************************/
355
356 ACPI_STATUS
357 acpi_ds_obj_stack_delete_all (
358         ACPI_WALK_STATE         *walk_state)
359 {
360         u32                     i;
361
362
363         /* The stack size is configurable, but fixed */
364
365         for (i = 0; i < OBJ_NUM_OPERANDS; i++) {
366                 if (walk_state->operands[i]) {
367                         acpi_cm_remove_reference (walk_state->operands[i]);
368                         walk_state->operands[i] = NULL;
369                 }
370         }
371
372         return (AE_OK);
373 }
374
375
376 /*******************************************************************************
377  *
378  * FUNCTION:    Acpi_ds_obj_stack_push
379  *
380  * PARAMETERS:  Object              - Object to push
381  *              Walk_state          - Current Walk state
382  *
383  * RETURN:      Status
384  *
385  * DESCRIPTION: Push an object onto this walk's object/operand stack
386  *
387  ******************************************************************************/
388
389 ACPI_STATUS
390 acpi_ds_obj_stack_push (
391         void                    *object,
392         ACPI_WALK_STATE         *walk_state)
393 {
394
395
396         /* Check for stack overflow */
397
398         if (walk_state->num_operands >= OBJ_NUM_OPERANDS) {
399                 return (AE_STACK_OVERFLOW);
400         }
401
402         /* Put the object onto the stack */
403
404         walk_state->operands [walk_state->num_operands] = object;
405         walk_state->num_operands++;
406
407         return (AE_OK);
408 }
409
410
411 /*******************************************************************************
412  *
413  * FUNCTION:    Acpi_ds_obj_stack_pop_object
414  *
415  * PARAMETERS:  Pop_count           - Number of objects/entries to pop
416  *              Walk_state          - Current Walk state
417  *
418  * RETURN:      Status
419  *
420  * DESCRIPTION: Pop this walk's object stack.  Objects on the stack are NOT
421  *              deleted by this routine.
422  *
423  ******************************************************************************/
424
425 ACPI_STATUS
426 acpi_ds_obj_stack_pop_object (
427         ACPI_OPERAND_OBJECT     **object,
428         ACPI_WALK_STATE         *walk_state)
429 {
430
431
432         /* Check for stack underflow */
433
434         if (walk_state->num_operands == 0) {
435                 return (AE_AML_NO_OPERAND);
436         }
437
438
439         /* Pop the stack */
440
441         walk_state->num_operands--;
442
443         /* Check for a valid operand */
444
445         if (!walk_state->operands [walk_state->num_operands]) {
446                 return (AE_AML_NO_OPERAND);
447         }
448
449         /* Get operand and set stack entry to null */
450
451         *object = walk_state->operands [walk_state->num_operands];
452         walk_state->operands [walk_state->num_operands] = NULL;
453
454         return (AE_OK);
455 }
456
457
458 /*******************************************************************************
459  *
460  * FUNCTION:    Acpi_ds_obj_stack_pop
461  *
462  * PARAMETERS:  Pop_count           - Number of objects/entries to pop
463  *              Walk_state          - Current Walk state
464  *
465  * RETURN:      Status
466  *
467  * DESCRIPTION: Pop this walk's object stack.  Objects on the stack are NOT
468  *              deleted by this routine.
469  *
470  ******************************************************************************/
471
472 ACPI_STATUS
473 acpi_ds_obj_stack_pop (
474         u32                     pop_count,
475         ACPI_WALK_STATE         *walk_state)
476 {
477         u32                     i;
478
479
480         for (i = 0; i < pop_count; i++) {
481                 /* Check for stack underflow */
482
483                 if (walk_state->num_operands == 0) {
484                         return (AE_STACK_UNDERFLOW);
485                 }
486
487                 /* Just set the stack entry to null */
488
489                 walk_state->num_operands--;
490                 walk_state->operands [walk_state->num_operands] = NULL;
491         }
492
493         return (AE_OK);
494 }
495
496
497 /*******************************************************************************
498  *
499  * FUNCTION:    Acpi_ds_obj_stack_pop_and_delete
500  *
501  * PARAMETERS:  Pop_count           - Number of objects/entries to pop
502  *              Walk_state          - Current Walk state
503  *
504  * RETURN:      Status
505  *
506  * DESCRIPTION: Pop this walk's object stack and delete each object that is
507  *              popped off.
508  *
509  ******************************************************************************/
510
511 ACPI_STATUS
512 acpi_ds_obj_stack_pop_and_delete (
513         u32                     pop_count,
514         ACPI_WALK_STATE         *walk_state)
515 {
516         u32                     i;
517         ACPI_OPERAND_OBJECT     *obj_desc;
518
519
520         for (i = 0; i < pop_count; i++) {
521                 /* Check for stack underflow */
522
523                 if (walk_state->num_operands == 0) {
524                         return (AE_STACK_UNDERFLOW);
525                 }
526
527                 /* Pop the stack and delete an object if present in this stack entry */
528
529                 walk_state->num_operands--;
530                 obj_desc = walk_state->operands [walk_state->num_operands];
531                 if (obj_desc) {
532                         acpi_cm_remove_reference (walk_state->operands [walk_state->num_operands]);
533                         walk_state->operands [walk_state->num_operands] = NULL;
534                 }
535         }
536
537         return (AE_OK);
538 }
539
540
541 /*******************************************************************************
542  *
543  * FUNCTION:    Acpi_ds_obj_stack_get_value
544  *
545  * PARAMETERS:  Index               - Stack index whose value is desired.  Based
546  *                                    on the top of the stack (index=0 == top)
547  *              Walk_state          - Current Walk state
548  *
549  * RETURN:      Status
550  *
551  * DESCRIPTION: Retrieve an object from this walk's object stack.  Index must
552  *              be within the range of the current stack pointer.
553  *
554  ******************************************************************************/
555
556 void *
557 acpi_ds_obj_stack_get_value (
558         u32                     index,
559         ACPI_WALK_STATE         *walk_state)
560 {
561
562
563         /* Can't do it if the stack is empty */
564
565         if (walk_state->num_operands == 0) {
566                 return (NULL);
567         }
568
569         /* or if the index is past the top of the stack */
570
571         if (index > (walk_state->num_operands - (u32) 1)) {
572                 return (NULL);
573         }
574
575
576         return (walk_state->operands[(NATIVE_UINT)(walk_state->num_operands - 1) -
577                           index]);
578 }
579
580
581 /*******************************************************************************
582  *
583  * FUNCTION:    Acpi_ds_get_current_walk_state
584  *
585  * PARAMETERS:  Walk_list       - Get current active state for this walk list
586  *
587  * RETURN:      Pointer to the current walk state
588  *
589  * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
590  *              walk state.
591  *
592  ******************************************************************************/
593
594 ACPI_WALK_STATE *
595 acpi_ds_get_current_walk_state (
596         ACPI_WALK_LIST          *walk_list)
597
598 {
599
600         if (!walk_list) {
601                 return (NULL);
602         }
603
604         return (walk_list->walk_state);
605 }
606
607
608 /*******************************************************************************
609  *
610  * FUNCTION:    Acpi_ds_push_walk_state
611  *
612  * PARAMETERS:  Walk_state      - State to push
613  *              Walk_list       - The list that owns the walk stack
614  *
615  * RETURN:      None
616  *
617  * DESCRIPTION: Place the Walk_state at the head of the state list.
618  *
619  ******************************************************************************/
620
621 static void
622 acpi_ds_push_walk_state (
623         ACPI_WALK_STATE         *walk_state,
624         ACPI_WALK_LIST          *walk_list)
625 {
626
627
628         walk_state->next    = walk_list->walk_state;
629         walk_list->walk_state = walk_state;
630
631         return;
632 }
633
634
635 /*******************************************************************************
636  *
637  * FUNCTION:    Acpi_ds_pop_walk_state
638  *
639  * PARAMETERS:  Walk_list       - The list that owns the walk stack
640  *
641  * RETURN:      A Walk_state object popped from the stack
642  *
643  * DESCRIPTION: Remove and return the walkstate object that is at the head of
644  *              the walk stack for the given walk list.  NULL indicates that
645  *              the list is empty.
646  *
647  ******************************************************************************/
648
649 ACPI_WALK_STATE *
650 acpi_ds_pop_walk_state (
651         ACPI_WALK_LIST          *walk_list)
652 {
653         ACPI_WALK_STATE         *walk_state;
654
655
656         walk_state = walk_list->walk_state;
657
658         if (walk_state) {
659                 /* Next walk state becomes the current walk state */
660
661                 walk_list->walk_state = walk_state->next;
662
663                 /*
664                  * Don't clear the NEXT field, this serves as an indicator
665                  * that there is a parent WALK STATE
666                  *     Walk_state->Next = NULL;
667                  */
668         }
669
670         return (walk_state);
671 }
672
673
674 /*******************************************************************************
675  *
676  * FUNCTION:    Acpi_ds_create_walk_state
677  *
678  * PARAMETERS:  Origin          - Starting point for this walk
679  *              Walk_list       - Owning walk list
680  *
681  * RETURN:      Pointer to the new walk state.
682  *
683  * DESCRIPTION: Allocate and initialize a new walk state.  The current walk state
684  *              is set to this new state.
685  *
686  ******************************************************************************/
687
688 ACPI_WALK_STATE *
689 acpi_ds_create_walk_state (
690         ACPI_OWNER_ID           owner_id,
691         ACPI_PARSE_OBJECT       *origin,
692         ACPI_OPERAND_OBJECT     *mth_desc,
693         ACPI_WALK_LIST          *walk_list)
694 {
695         ACPI_WALK_STATE         *walk_state;
696         ACPI_STATUS             status;
697
698
699         acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
700         acpi_gbl_walk_state_cache_requests++;
701
702         /* Check the cache first */
703
704         if (acpi_gbl_walk_state_cache) {
705                 /* There is an object available, use it */
706
707                 walk_state = acpi_gbl_walk_state_cache;
708                 acpi_gbl_walk_state_cache = walk_state->next;
709
710                 acpi_gbl_walk_state_cache_hits++;
711                 acpi_gbl_walk_state_cache_depth--;
712
713                 acpi_cm_release_mutex (ACPI_MTX_CACHES);
714         }
715
716         else {
717                 /* The cache is empty, create a new object */
718
719                 /* Avoid deadlock with Acpi_cm_callocate */
720
721                 acpi_cm_release_mutex (ACPI_MTX_CACHES);
722
723                 walk_state = acpi_cm_callocate (sizeof (ACPI_WALK_STATE));
724                 if (!walk_state) {
725                         return (NULL);
726                 }
727         }
728
729         walk_state->data_type       = ACPI_DESC_TYPE_WALK;
730         walk_state->owner_id        = owner_id;
731         walk_state->origin          = origin;
732         walk_state->method_desc     = mth_desc;
733         walk_state->walk_list       = walk_list;
734
735         /* Init the method args/local */
736
737 #ifndef _ACPI_ASL_COMPILER
738         acpi_ds_method_data_init (walk_state);
739 #endif
740
741         /* Create an initial result stack entry */
742
743         status = acpi_ds_result_stack_push (walk_state);
744         if (ACPI_FAILURE (status)) {
745                 return (NULL);
746         }
747
748
749         /* Put the new state at the head of the walk list */
750
751         acpi_ds_push_walk_state (walk_state, walk_list);
752
753         return (walk_state);
754 }
755
756
757 /*******************************************************************************
758  *
759  * FUNCTION:    Acpi_ds_delete_walk_state
760  *
761  * PARAMETERS:  Walk_state      - State to delete
762  *
763  * RETURN:      Status
764  *
765  * DESCRIPTION: Delete a walk state including all internal data structures
766  *
767  ******************************************************************************/
768
769 void
770 acpi_ds_delete_walk_state (
771         ACPI_WALK_STATE         *walk_state)
772 {
773         ACPI_GENERIC_STATE      *state;
774
775
776         if (!walk_state) {
777                 return;
778         }
779
780         if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
781                 return;
782         }
783
784
785         /* Always must free any linked control states */
786
787         while (walk_state->control_state) {
788                 state = walk_state->control_state;
789                 walk_state->control_state = state->common.next;
790
791                 acpi_cm_delete_generic_state (state);
792         }
793
794         /* Always must free any linked parse states */
795
796         while (walk_state->scope_info) {
797                 state = walk_state->scope_info;
798                 walk_state->scope_info = state->common.next;
799
800                 acpi_cm_delete_generic_state (state);
801         }
802
803         /* Always must free any stacked result states */
804
805         while (walk_state->results) {
806                 state = walk_state->results;
807                 walk_state->results = state->common.next;
808
809                 acpi_cm_delete_generic_state (state);
810         }
811
812
813         /* If walk cache is full, just free this wallkstate object */
814
815         if (acpi_gbl_walk_state_cache_depth >= MAX_WALK_CACHE_DEPTH) {
816                 acpi_cm_free (walk_state);
817         }
818
819         /* Otherwise put this object back into the cache */
820
821         else {
822                 acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
823
824                 /* Clear the state */
825
826                 MEMSET (walk_state, 0, sizeof (ACPI_WALK_STATE));
827                 walk_state->data_type = ACPI_DESC_TYPE_WALK;
828
829                 /* Put the object at the head of the global cache list */
830
831                 walk_state->next = acpi_gbl_walk_state_cache;
832                 acpi_gbl_walk_state_cache = walk_state;
833                 acpi_gbl_walk_state_cache_depth++;
834
835
836                 acpi_cm_release_mutex (ACPI_MTX_CACHES);
837         }
838
839         return;
840 }
841
842
843 /******************************************************************************
844  *
845  * FUNCTION:    Acpi_ds_delete_walk_state_cache
846  *
847  * PARAMETERS:  None
848  *
849  * RETURN:      Status
850  *
851  * DESCRIPTION: Purge the global state object cache.  Used during subsystem
852  *              termination.
853  *
854  ******************************************************************************/
855
856 void
857 acpi_ds_delete_walk_state_cache (
858         void)
859 {
860         ACPI_WALK_STATE         *next;
861
862
863         /* Traverse the global cache list */
864
865         while (acpi_gbl_walk_state_cache) {
866                 /* Delete one cached state object */
867
868                 next = acpi_gbl_walk_state_cache->next;
869                 acpi_cm_free (acpi_gbl_walk_state_cache);
870                 acpi_gbl_walk_state_cache = next;
871                 acpi_gbl_walk_state_cache_depth--;
872         }
873
874         return;
875 }
876
877