a7ac010c13cb5760548dd51b00acca9b4fa75f09
[reactos.git] / reactos / drivers / bus / acpi / executer / ammutex.c
1
2 /******************************************************************************
3 *
4 * Module Name: ammutex - ASL Mutex Acquire/Release functions
5 * $Revision: 1.1 $
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 static 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