:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / executer / ammutex.c
1
2 /******************************************************************************
3  *
4  * Module Name: ammutex - ASL Mutex Acquire/Release functions
5  *              $Revision$
6  *
7  *****************************************************************************/
8
9 /*
10  *  Copyright (C) 2000, 2001 R. Byron Moore
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27
28 #include "acpi.h"
29 #include "acinterp.h"
30 #include "acnamesp.h"
31 #include "achware.h"
32 #include "acevents.h"
33
34 #define _COMPONENT          ACPI_EXECUTER
35          MODULE_NAME         ("ammutex")
36
37
38 /*******************************************************************************
39  *
40  * FUNCTION:    Acpi_aml_unlink_mutex
41  *
42  * PARAMETERS:  *Obj_desc           - The mutex to be unlinked
43  *
44  * RETURN:      Status
45  *
46  * DESCRIPTION: Remove a mutex from the "Acquired_mutex" list
47  *
48  ******************************************************************************/
49
50 void
51 acpi_aml_unlink_mutex (
52         ACPI_OPERAND_OBJECT     *obj_desc)
53 {
54
55         if (obj_desc->mutex.next) {
56                 (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
57         }
58         if (obj_desc->mutex.prev) {
59                 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
60         }
61 }
62
63
64 /*******************************************************************************
65  *
66  * FUNCTION:    Acpi_aml_link_mutex
67  *
68  * PARAMETERS:  *Obj_desc           - The mutex to be linked
69  *              *List_head          - head of the "Acquired_mutex" list
70  *
71  * RETURN:      Status
72  *
73  * DESCRIPTION: Add a mutex to the "Acquired_mutex" list for this walk
74  *
75  ******************************************************************************/
76
77 void
78 acpi_aml_link_mutex (
79         ACPI_OPERAND_OBJECT     *obj_desc,
80         ACPI_OPERAND_OBJECT     *list_head)
81 {
82
83         /* This object will be the first object in the list */
84
85         obj_desc->mutex.prev = list_head;
86         obj_desc->mutex.next = list_head->mutex.next;
87
88         /* Update old first object to point back to this object */
89
90         if (list_head->mutex.next) {
91                 (list_head->mutex.next)->mutex.prev = obj_desc;
92         }
93
94         /* Update list head */
95
96         list_head->mutex.next = obj_desc;
97 }
98
99
100 /*******************************************************************************
101  *
102  * FUNCTION:    Acpi_aml_acquire_mutex
103  *
104  * PARAMETERS:  *Time_desc          - The 'time to delay' object descriptor
105  *              *Obj_desc           - The object descriptor for this op
106  *
107  * RETURN:      Status
108  *
109  * DESCRIPTION: Acquire an AML mutex
110  *
111  ******************************************************************************/
112
113 ACPI_STATUS
114 acpi_aml_acquire_mutex (
115         ACPI_OPERAND_OBJECT     *time_desc,
116         ACPI_OPERAND_OBJECT     *obj_desc,
117         ACPI_WALK_STATE         *walk_state)
118 {
119         ACPI_STATUS             status;
120
121
122         if (!obj_desc) {
123                 return (AE_BAD_PARAMETER);
124         }
125
126         /*
127          * Current Sync must be less than or equal to the sync level of the
128          * mutex.  This mechanism provides some deadlock prevention
129          */
130         if (walk_state->current_sync_level > obj_desc->mutex.sync_level) {
131                 return (AE_AML_MUTEX_ORDER);
132         }
133
134         /*
135          * If the mutex is already owned by this thread,
136          * just increment the acquisition depth
137          */
138         if (obj_desc->mutex.owner == walk_state) {
139                 obj_desc->mutex.acquisition_depth++;
140                 return (AE_OK);
141         }
142
143         /* Acquire the mutex, wait if necessary */
144
145         status = acpi_aml_system_acquire_mutex (time_desc, obj_desc);
146         if (ACPI_FAILURE (status)) {
147                 /* Includes failure from a timeout on Time_desc */
148
149                 return (status);
150         }
151
152         /* Have the mutex, update mutex and walk info */
153
154         obj_desc->mutex.owner = walk_state;
155         obj_desc->mutex.acquisition_depth = 1;
156         walk_state->current_sync_level = obj_desc->mutex.sync_level;
157
158         /* Link the mutex to the walk state for force-unlock at method exit */
159
160         acpi_aml_link_mutex (obj_desc, (ACPI_OPERAND_OBJECT *)
161                          &(walk_state->walk_list->acquired_mutex_list));
162
163         return (AE_OK);
164 }
165
166
167 /*******************************************************************************
168  *
169  * FUNCTION:    Acpi_aml_release_mutex
170  *
171  * PARAMETERS:  *Obj_desc           - The object descriptor for this op
172  *
173  * RETURN:      Status
174  *
175  * DESCRIPTION: Release a previously acquired Mutex.
176  *
177  ******************************************************************************/
178
179 ACPI_STATUS
180 acpi_aml_release_mutex (
181         ACPI_OPERAND_OBJECT     *obj_desc,
182         ACPI_WALK_STATE         *walk_state)
183 {
184         ACPI_STATUS             status;
185
186
187         if (!obj_desc) {
188                 return (AE_BAD_PARAMETER);
189         }
190
191         /*  The mutex must have been previously acquired in order to release it */
192
193         if (!obj_desc->mutex.owner) {
194                 return (AE_AML_MUTEX_NOT_ACQUIRED);
195         }
196
197         /* The Mutex is owned, but this thread must be the owner */
198
199         if (obj_desc->mutex.owner != walk_state) {
200                 return (AE_AML_NOT_OWNER);
201         }
202
203         /*
204          * The sync level of the mutex must be less than or
205          * equal to the current sync level
206          */
207         if (obj_desc->mutex.sync_level > walk_state->current_sync_level) {
208                 return (AE_AML_MUTEX_ORDER);
209         }
210
211         /*
212          * Match multiple Acquires with multiple Releases
213          */
214         obj_desc->mutex.acquisition_depth--;
215         if (obj_desc->mutex.acquisition_depth != 0) {
216                 /* Just decrement the depth and return */
217
218                 return (AE_OK);
219         }
220
221
222         /* Release the mutex */
223
224         status = acpi_aml_system_release_mutex (obj_desc);
225
226         /* Update the mutex and walk state */
227
228         obj_desc->mutex.owner = NULL;
229         walk_state->current_sync_level = obj_desc->mutex.sync_level;
230
231         /* Unlink the mutex from the owner's list */
232
233         acpi_aml_unlink_mutex (obj_desc);
234
235         return (AE_OK);
236 }
237
238
239 /*******************************************************************************
240  *
241  * FUNCTION:    Acpi_aml_release_all_mutexes
242  *
243  * PARAMETERS:  *Mutex_list           - Head of the mutex list
244  *
245  * RETURN:      Status
246  *
247  * DESCRIPTION: Release all mutexes in the list
248  *
249  ******************************************************************************/
250
251 ACPI_STATUS
252 acpi_aml_release_all_mutexes (
253         ACPI_OPERAND_OBJECT     *list_head)
254 {
255         ACPI_OPERAND_OBJECT     *next = list_head->mutex.next;
256         ACPI_OPERAND_OBJECT     *this;
257
258
259         /*
260          * Traverse the list of owned mutexes, releasing each one.
261          */
262         while (next) {
263                 this = next;
264                 next = this->mutex.next;
265
266                 /* Mark mutex un-owned */
267
268                 this->mutex.owner = NULL;
269                 this->mutex.prev = NULL;
270                 this->mutex.next = NULL;
271                 this->mutex.acquisition_depth = 0;
272
273                  /* Release the mutex */
274
275                 acpi_aml_system_release_mutex (this);
276         }
277
278         return (AE_OK);
279 }
280
281