Ported ACPI CA (from the nice guys at Intel) to ReactOS (ACPI bus driver).
[reactos.git] / reactos / drivers / bus / acpi / namespace / nseval.c
1 /*******************************************************************************
2 *
3 * Module Name: nseval - Object evaluation interfaces -- includes control
4 * method lookup and execution.
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 "amlcode.h"
30 #include "acparser.h"
31 #include "acinterp.h"
32 #include "acnamesp.h"
33
34
35 #define _COMPONENT ACPI_NAMESPACE
36 MODULE_NAME ("nseval")
37
38
39 /*******************************************************************************
40 *
41 * FUNCTION: Acpi_ns_evaluate_relative
42 *
43 * PARAMETERS: Handle - The relative containing object
44 * *Pathname - Name of method to execute, If NULL, the
45 * handle is the object to execute
46 * **Params - List of parameters to pass to the method,
47 * terminated by NULL. Params itself may be
48 * NULL if no parameters are being passed.
49 * *Return_object - Where to put method's return value (if
50 * any). If NULL, no value is returned.
51 *
52 * RETURN: Status
53 *
54 * DESCRIPTION: Find and execute the requested method using the handle as a
55 * scope
56 *
57 * MUTEX: Locks Namespace
58 *
59 ******************************************************************************/
60
61 ACPI_STATUS
62 acpi_ns_evaluate_relative (
63 ACPI_NAMESPACE_NODE *handle,
64 NATIVE_CHAR *pathname,
65 ACPI_OPERAND_OBJECT **params,
66 ACPI_OPERAND_OBJECT **return_object)
67 {
68 ACPI_NAMESPACE_NODE *prefix_node;
69 ACPI_STATUS status;
70 ACPI_NAMESPACE_NODE *node = NULL;
71 NATIVE_CHAR *internal_path = NULL;
72 ACPI_GENERIC_STATE scope_info;
73
74
75 /*
76 * Must have a valid object handle
77 */
78 if (!handle) {
79 return (AE_BAD_PARAMETER);
80 }
81
82 /* Build an internal name string for the method */
83
84 status = acpi_ns_internalize_name (pathname, &internal_path);
85 if (ACPI_FAILURE (status)) {
86 return (status);
87 }
88
89 /* Get the prefix handle and Node */
90
91 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
92
93 prefix_node = acpi_ns_convert_handle_to_entry (handle);
94 if (!prefix_node) {
95 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
96 status = AE_BAD_PARAMETER;
97 goto cleanup;
98 }
99
100 /* Lookup the name in the namespace */
101
102 scope_info.scope.node = prefix_node;
103 status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY,
104 IMODE_EXECUTE, NS_NO_UPSEARCH, NULL,
105 &node);
106
107 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
108
109 if (ACPI_FAILURE (status)) {
110 goto cleanup;
111 }
112
113 /*
114 * Now that we have a handle to the object, we can attempt
115 * to evaluate it.
116 */
117
118 status = acpi_ns_evaluate_by_handle (node, params, return_object);
119
120 cleanup:
121
122 /* Cleanup */
123
124 acpi_cm_free (internal_path);
125
126 return (status);
127 }
128
129
130 /*******************************************************************************
131 *
132 * FUNCTION: Acpi_ns_evaluate_by_name
133 *
134 * PARAMETERS: Pathname - Fully qualified pathname to the object
135 * *Return_object - Where to put method's return value (if
136 * any). If NULL, no value is returned.
137 * **Params - List of parameters to pass to the method,
138 * terminated by NULL. Params itself may be
139 * NULL if no parameters are being passed.
140 *
141 * RETURN: Status
142 *
143 * DESCRIPTION: Find and execute the requested method passing the given
144 * parameters
145 *
146 * MUTEX: Locks Namespace
147 *
148 ******************************************************************************/
149
150 ACPI_STATUS
151 acpi_ns_evaluate_by_name (
152 NATIVE_CHAR *pathname,
153 ACPI_OPERAND_OBJECT **params,
154 ACPI_OPERAND_OBJECT **return_object)
155 {
156 ACPI_STATUS status;
157 ACPI_NAMESPACE_NODE *node = NULL;
158 NATIVE_CHAR *internal_path = NULL;
159
160
161 /* Build an internal name string for the method */
162
163 status = acpi_ns_internalize_name (pathname, &internal_path);
164 if (ACPI_FAILURE (status)) {
165 return (status);
166 }
167
168 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
169
170 /* Lookup the name in the namespace */
171
172 status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY,
173 IMODE_EXECUTE, NS_NO_UPSEARCH, NULL,
174 &node);
175
176 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
177
178 if (ACPI_FAILURE (status)) {
179 goto cleanup;
180 }
181
182 /*
183 * Now that we have a handle to the object, we can attempt
184 * to evaluate it.
185 */
186
187 status = acpi_ns_evaluate_by_handle (node, params, return_object);
188
189
190 cleanup:
191
192 /* Cleanup */
193
194 if (internal_path) {
195 acpi_cm_free (internal_path);
196 }
197
198 return (status);
199 }
200
201
202 /*******************************************************************************
203 *
204 * FUNCTION: Acpi_ns_evaluate_by_handle
205 *
206 * PARAMETERS: Handle - Method Node to execute
207 * **Params - List of parameters to pass to the method,
208 * terminated by NULL. Params itself may be
209 * NULL if no parameters are being passed.
210 * *Return_object - Where to put method's return value (if
211 * any). If NULL, no value is returned.
212 *
213 * RETURN: Status
214 *
215 * DESCRIPTION: Execute the requested method passing the given parameters
216 *
217 * MUTEX: Locks Namespace
218 *
219 ******************************************************************************/
220
221 ACPI_STATUS
222 acpi_ns_evaluate_by_handle (
223 ACPI_NAMESPACE_NODE *handle,
224 ACPI_OPERAND_OBJECT **params,
225 ACPI_OPERAND_OBJECT **return_object)
226 {
227 ACPI_NAMESPACE_NODE *node;
228 ACPI_STATUS status;
229 ACPI_OPERAND_OBJECT *local_return_object;
230
231
232 /* Check if namespace has been initialized */
233
234 if (!acpi_gbl_root_node) {
235 return (AE_NO_NAMESPACE);
236 }
237
238 /* Parameter Validation */
239
240 if (!handle) {
241 return (AE_BAD_PARAMETER);
242 }
243
244 if (return_object) {
245 /* Initialize the return value to an invalid object */
246
247 *return_object = NULL;
248 }
249
250 /* Get the prefix handle and Node */
251
252 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
253
254 node = acpi_ns_convert_handle_to_entry (handle);
255 if (!node) {
256 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
257 return (AE_BAD_PARAMETER);
258 }
259
260
261 /*
262 * Two major cases here:
263 * 1) The object is an actual control method -- execute it.
264 * 2) The object is not a method -- just return it's current
265 * value
266 *
267 * In both cases, the namespace is unlocked by the
268 * Acpi_ns* procedure
269 */
270 if (acpi_ns_get_type (node) == ACPI_TYPE_METHOD) {
271 /*
272 * Case 1) We have an actual control method to execute
273 */
274 status = acpi_ns_execute_control_method (node, params,
275 &local_return_object);
276 }
277
278 else {
279 /*
280 * Case 2) Object is NOT a method, just return its
281 * current value
282 */
283 status = acpi_ns_get_object_value (node, &local_return_object);
284 }
285
286
287 /*
288 * Check if there is a return value on the stack that must
289 * be dealt with
290 */
291 if (status == AE_CTRL_RETURN_VALUE) {
292 /*
293 * If the Method returned a value and the caller
294 * provided a place to store a returned value, Copy
295 * the returned value to the object descriptor provided
296 * by the caller.
297 */
298 if (return_object) {
299 /*
300 * Valid return object, copy the pointer to
301 * the returned object
302 */
303 *return_object = local_return_object;
304 }
305
306
307 /* Map AE_RETURN_VALUE to AE_OK, we are done with it */
308
309 if (status == AE_CTRL_RETURN_VALUE) {
310 status = AE_OK;
311 }
312 }
313
314 /*
315 * Namespace was unlocked by the handling Acpi_ns* function,
316 * so we just return
317 */
318 return (status);
319 }
320
321
322 /*******************************************************************************
323 *
324 * FUNCTION: Acpi_ns_execute_control_method
325 *
326 * PARAMETERS: Method_node - The object/method
327 * **Params - List of parameters to pass to the method,
328 * terminated by NULL. Params itself may be
329 * NULL if no parameters are being passed.
330 * **Return_obj_desc - List of result objects to be returned
331 * from the method.
332 *
333 * RETURN: Status
334 *
335 * DESCRIPTION: Execute the requested method passing the given parameters
336 *
337 * MUTEX: Assumes namespace is locked
338 *
339 ******************************************************************************/
340
341 ACPI_STATUS
342 acpi_ns_execute_control_method (
343 ACPI_NAMESPACE_NODE *method_node,
344 ACPI_OPERAND_OBJECT **params,
345 ACPI_OPERAND_OBJECT **return_obj_desc)
346 {
347 ACPI_STATUS status;
348 ACPI_OPERAND_OBJECT *obj_desc;
349
350
351 /* Verify that there is a method associated with this object */
352
353 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_node);
354 if (!obj_desc) {
355 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
356 return (AE_ERROR);
357 }
358
359
360 /*
361 * Unlock the namespace before execution. This allows namespace access
362 * via the external Acpi* interfaces while a method is being executed.
363 * However, any namespace deletion must acquire both the namespace and
364 * interpreter locks to ensure that no thread is using the portion of the
365 * namespace that is being deleted.
366 */
367 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
368
369 /*
370 * Execute the method via the interpreter
371 */
372 status = acpi_aml_execute_method (method_node, params, return_obj_desc);
373
374 return (status);
375 }
376
377
378 /*******************************************************************************
379 *
380 * FUNCTION: Acpi_ns_get_object_value
381 *
382 * PARAMETERS: Node - The object
383 *
384 * RETURN: Status
385 *
386 * DESCRIPTION: Return the current value of the object
387 *
388 * MUTEX: Assumes namespace is locked
389 *
390 ******************************************************************************/
391
392 ACPI_STATUS
393 acpi_ns_get_object_value (
394 ACPI_NAMESPACE_NODE *node,
395 ACPI_OPERAND_OBJECT **return_obj_desc)
396 {
397 ACPI_STATUS status = AE_OK;
398 ACPI_OPERAND_OBJECT *obj_desc;
399 ACPI_OPERAND_OBJECT *val_desc;
400
401
402 /*
403 * We take the value from certain objects directly
404 */
405
406 if ((node->type == ACPI_TYPE_PROCESSOR) ||
407 (node->type == ACPI_TYPE_POWER)) {
408 /*
409 * Create a Reference object to contain the object
410 */
411 obj_desc = acpi_cm_create_internal_object (node->type);
412 if (!obj_desc) {
413 status = AE_NO_MEMORY;
414 goto unlock_and_exit;
415 }
416
417 /*
418 * Get the attached object
419 */
420
421 val_desc = acpi_ns_get_attached_object (node);
422 if (!val_desc) {
423 status = AE_NULL_OBJECT;
424 goto unlock_and_exit;
425 }
426
427 /*
428 * Just copy from the original to the return object
429 *
430 * TBD: [Future] - need a low-level object copy that handles
431 * the reference count automatically. (Don't want to copy it)
432 */
433
434 MEMCPY (obj_desc, val_desc, sizeof (ACPI_OPERAND_OBJECT));
435 obj_desc->common.reference_count = 1;
436 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
437 }
438
439
440 /*
441 * Other objects require a reference object wrapper which we
442 * then attempt to resolve.
443 */
444 else {
445 /* Create an Reference object to contain the object */
446
447 obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE);
448 if (!obj_desc) {
449 status = AE_NO_MEMORY;
450 goto unlock_and_exit;
451 }
452
453 /* Construct a descriptor pointing to the name */
454
455 obj_desc->reference.opcode = (u8) AML_NAME_OP;
456 obj_desc->reference.object = (void *) node;
457
458 /*
459 * Use Resolve_to_value() to get the associated value. This call
460 * always deletes Obj_desc (allocated above).
461 *
462 * NOTE: we can get away with passing in NULL for a walk state
463 * because Obj_desc is guaranteed to not be a reference to either
464 * a method local or a method argument
465 *
466 * Even though we do not directly invoke the interpreter
467 * for this, we must enter it because we could access an opregion.
468 * The opregion access code assumes that the interpreter
469 * is locked.
470 *
471 * We must release the namespace lock before entering the
472 * intepreter.
473 */
474
475 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
476 status = acpi_aml_enter_interpreter ();
477 if (ACPI_SUCCESS (status)) {
478 status = acpi_aml_resolve_to_value (&obj_desc, NULL);
479
480 acpi_aml_exit_interpreter ();
481 }
482 }
483
484 /*
485 * If Acpi_aml_resolve_to_value() succeeded, the return value was
486 * placed in Obj_desc.
487 */
488
489 if (ACPI_SUCCESS (status)) {
490 status = AE_CTRL_RETURN_VALUE;
491
492 *return_obj_desc = obj_desc;
493 }
494
495 /* Namespace is unlocked */
496
497 return (status);
498
499
500 unlock_and_exit:
501
502 /* Unlock the namespace */
503
504 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
505 return (status);
506 }