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