Ported ACPI CA (from the nice guys at Intel) to ReactOS (ACPI bus driver).
[reactos.git] / reactos / drivers / bus / acpi / namespace / nsxfobj.c
1 /*******************************************************************************
2 *
3 * Module Name: nsxfobj - Public interfaces to the ACPI subsystem
4 * ACPI Object oriented interfaces
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 "acdispat.h"
32
33
34 #define _COMPONENT ACPI_NAMESPACE
35 MODULE_NAME ("nsxfobj")
36
37
38 /*******************************************************************************
39 *
40 * FUNCTION: Acpi_evaluate_object
41 *
42 * PARAMETERS: Handle - Object handle (optional)
43 * *Pathname - Object pathname (optional)
44 * **Params - List of parameters to pass to
45 * method, terminated by NULL.
46 * Params itself may be NULL
47 * if no parameters are being
48 * 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 evaluate the given object, passing the given
55 * parameters if necessary. One of "Handle" or "Pathname" must
56 * be valid (non-null)
57 *
58 ******************************************************************************/
59
60 ACPI_STATUS
61 acpi_evaluate_object (
62 ACPI_HANDLE handle,
63 ACPI_STRING pathname,
64 ACPI_OBJECT_LIST *param_objects,
65 ACPI_BUFFER *return_buffer)
66 {
67 ACPI_STATUS status;
68 ACPI_OPERAND_OBJECT **param_ptr = NULL;
69 ACPI_OPERAND_OBJECT *return_obj = NULL;
70 ACPI_OPERAND_OBJECT *object_ptr = NULL;
71 u32 buffer_space_needed;
72 u32 user_buffer_length;
73 u32 count;
74 u32 i;
75 u32 param_length;
76 u32 object_length;
77
78
79 /*
80 * If there are parameters to be passed to the object
81 * (which must be a control method), the external objects
82 * must be converted to internal objects
83 */
84
85 if (param_objects && param_objects->count) {
86 /*
87 * Allocate a new parameter block for the internal objects
88 * Add 1 to count to allow for null terminated internal list
89 */
90
91 count = param_objects->count;
92 param_length = (count + 1) * sizeof (void *);
93 object_length = count * sizeof (ACPI_OPERAND_OBJECT);
94
95 param_ptr = acpi_cm_callocate (param_length + /* Parameter List part */
96 object_length); /* Actual objects */
97 if (!param_ptr) {
98 return (AE_NO_MEMORY);
99 }
100
101 object_ptr = (ACPI_OPERAND_OBJECT *) ((u8 *) param_ptr +
102 param_length);
103
104 /*
105 * Init the param array of pointers and NULL terminate
106 * the list
107 */
108
109 for (i = 0; i < count; i++) {
110 param_ptr[i] = &object_ptr[i];
111 acpi_cm_init_static_object (&object_ptr[i]);
112 }
113 param_ptr[count] = NULL;
114
115 /*
116 * Convert each external object in the list to an
117 * internal object
118 */
119 for (i = 0; i < count; i++) {
120 status = acpi_cm_copy_eobject_to_iobject (&param_objects->pointer[i],
121 param_ptr[i]);
122
123 if (ACPI_FAILURE (status)) {
124 acpi_cm_delete_internal_object_list (param_ptr);
125 return (status);
126 }
127 }
128 }
129
130
131 /*
132 * Three major cases:
133 * 1) Fully qualified pathname
134 * 2) No handle, not fully qualified pathname (error)
135 * 3) Valid handle
136 */
137
138 if ((pathname) &&
139 (acpi_ns_valid_root_prefix (pathname[0]))) {
140 /*
141 * The path is fully qualified, just evaluate by name
142 */
143 status = acpi_ns_evaluate_by_name (pathname, param_ptr, &return_obj);
144 }
145
146 else if (!handle) {
147 /*
148 * A handle is optional iff a fully qualified pathname
149 * is specified. Since we've already handled fully
150 * qualified names above, this is an error
151 */
152
153
154
155 status = AE_BAD_PARAMETER;
156 }
157
158 else {
159 /*
160 * We get here if we have a handle -- and if we have a
161 * pathname it is relative. The handle will be validated
162 * in the lower procedures
163 */
164
165 if (!pathname) {
166 /*
167 * The null pathname case means the handle is for
168 * the actual object to be evaluated
169 */
170 status = acpi_ns_evaluate_by_handle (handle, param_ptr, &return_obj);
171 }
172
173 else {
174 /*
175 * Both a Handle and a relative Pathname
176 */
177 status = acpi_ns_evaluate_relative (handle, pathname, param_ptr,
178 &return_obj);
179 }
180 }
181
182
183 /*
184 * If we are expecting a return value, and all went well above,
185 * copy the return value to an external object.
186 */
187
188 if (return_buffer) {
189 user_buffer_length = return_buffer->length;
190 return_buffer->length = 0;
191
192 if (return_obj) {
193 if (VALID_DESCRIPTOR_TYPE (return_obj, ACPI_DESC_TYPE_NAMED)) {
194 /*
195 * If we got an Node as a return object,
196 * this means the object we are evaluating
197 * has nothing interesting to return (such
198 * as a mutex, etc.) We return an error
199 * because these types are essentially
200 * unsupported by this interface. We
201 * don't check up front because this makes
202 * it easier to add support for various
203 * types at a later date if necessary.
204 */
205 status = AE_TYPE;
206 return_obj = NULL; /* No need to delete an Node */
207 }
208
209 if (ACPI_SUCCESS (status)) {
210 /*
211 * Find out how large a buffer is needed
212 * to contain the returned object
213 */
214 status = acpi_cm_get_object_size (return_obj,
215 &buffer_space_needed);
216 if (ACPI_SUCCESS (status)) {
217 /*
218 * Check if there is enough room in the
219 * caller's buffer
220 */
221
222 if (user_buffer_length < buffer_space_needed) {
223 /*
224 * Caller's buffer is too small, can't
225 * give him partial results fail the call
226 * but return the buffer size needed
227 */
228
229 return_buffer->length = buffer_space_needed;
230 status = AE_BUFFER_OVERFLOW;
231 }
232
233 else {
234 /*
235 * We have enough space for the object, build it
236 */
237 status = acpi_cm_copy_iobject_to_eobject (return_obj,
238 return_buffer);
239 return_buffer->length = buffer_space_needed;
240 }
241 }
242 }
243 }
244 }
245
246
247 /* Delete the return and parameter objects */
248
249 if (return_obj) {
250 /*
251 * Delete the internal return object. (Or at least
252 * decrement the reference count by one)
253 */
254 acpi_cm_remove_reference (return_obj);
255 }
256
257 /*
258 * Free the input parameter list (if we created one),
259 */
260
261 if (param_ptr) {
262 /* Free the allocated parameter block */
263
264 acpi_cm_delete_internal_object_list (param_ptr);
265 }
266
267 return (status);
268 }
269
270
271 /*******************************************************************************
272 *
273 * FUNCTION: Acpi_get_next_object
274 *
275 * PARAMETERS: Type - Type of object to be searched for
276 * Parent - Parent object whose children we are getting
277 * Last_child - Previous child that was found.
278 * The NEXT child will be returned
279 * Ret_handle - Where handle to the next object is placed
280 *
281 * RETURN: Status
282 *
283 * DESCRIPTION: Return the next peer object within the namespace. If Handle is
284 * valid, Scope is ignored. Otherwise, the first object within
285 * Scope is returned.
286 *
287 ******************************************************************************/
288
289 ACPI_STATUS
290 acpi_get_next_object (
291 ACPI_OBJECT_TYPE type,
292 ACPI_HANDLE parent,
293 ACPI_HANDLE child,
294 ACPI_HANDLE *ret_handle)
295 {
296 ACPI_STATUS status = AE_OK;
297 ACPI_NAMESPACE_NODE *node;
298 ACPI_NAMESPACE_NODE *parent_node = NULL;
299 ACPI_NAMESPACE_NODE *child_node = NULL;
300
301
302 /* Parameter validation */
303
304 if (type > ACPI_TYPE_MAX) {
305 return (AE_BAD_PARAMETER);
306 }
307
308 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
309
310 /* If null handle, use the parent */
311
312 if (!child) {
313 /* Start search at the beginning of the specified scope */
314
315 parent_node = acpi_ns_convert_handle_to_entry (parent);
316 if (!parent_node) {
317 status = AE_BAD_PARAMETER;
318 goto unlock_and_exit;
319 }
320 }
321
322 /* Non-null handle, ignore the parent */
323
324 else {
325 /* Convert and validate the handle */
326
327 child_node = acpi_ns_convert_handle_to_entry (child);
328 if (!child_node) {
329 status = AE_BAD_PARAMETER;
330 goto unlock_and_exit;
331 }
332 }
333
334
335 /* Internal function does the real work */
336
337 node = acpi_ns_get_next_object ((OBJECT_TYPE_INTERNAL) type,
338 parent_node, child_node);
339 if (!node) {
340 status = AE_NOT_FOUND;
341 goto unlock_and_exit;
342 }
343
344 if (ret_handle) {
345 *ret_handle = acpi_ns_convert_entry_to_handle (node);
346 }
347
348
349 unlock_and_exit:
350
351 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
352 return (status);
353 }
354
355
356 /*******************************************************************************
357 *
358 * FUNCTION: Acpi_get_type
359 *
360 * PARAMETERS: Handle - Handle of object whose type is desired
361 * *Ret_type - Where the type will be placed
362 *
363 * RETURN: Status
364 *
365 * DESCRIPTION: This routine returns the type associatd with a particular handle
366 *
367 ******************************************************************************/
368
369 ACPI_STATUS
370 acpi_get_type (
371 ACPI_HANDLE handle,
372 ACPI_OBJECT_TYPE *ret_type)
373 {
374 ACPI_NAMESPACE_NODE *node;
375
376
377 /* Parameter Validation */
378
379 if (!ret_type) {
380 return (AE_BAD_PARAMETER);
381 }
382
383 /*
384 * Special case for the predefined Root Node
385 * (return type ANY)
386 */
387 if (handle == ACPI_ROOT_OBJECT) {
388 *ret_type = ACPI_TYPE_ANY;
389 return (AE_OK);
390 }
391
392 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
393
394 /* Convert and validate the handle */
395
396 node = acpi_ns_convert_handle_to_entry (handle);
397 if (!node) {
398 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
399 return (AE_BAD_PARAMETER);
400 }
401
402 *ret_type = node->type;
403
404
405 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
406 return (AE_OK);
407 }
408
409
410 /*******************************************************************************
411 *
412 * FUNCTION: Acpi_get_parent
413 *
414 * PARAMETERS: Handle - Handle of object whose parent is desired
415 * Ret_handle - Where the parent handle will be placed
416 *
417 * RETURN: Status
418 *
419 * DESCRIPTION: Returns a handle to the parent of the object represented by
420 * Handle.
421 *
422 ******************************************************************************/
423
424 ACPI_STATUS
425 acpi_get_parent (
426 ACPI_HANDLE handle,
427 ACPI_HANDLE *ret_handle)
428 {
429 ACPI_NAMESPACE_NODE *node;
430 ACPI_STATUS status = AE_OK;
431
432
433 /* No trace macro, too verbose */
434
435
436 if (!ret_handle) {
437 return (AE_BAD_PARAMETER);
438 }
439
440 /* Special case for the predefined Root Node (no parent) */
441
442 if (handle == ACPI_ROOT_OBJECT) {
443 return (AE_NULL_ENTRY);
444 }
445
446
447 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
448
449 /* Convert and validate the handle */
450
451 node = acpi_ns_convert_handle_to_entry (handle);
452 if (!node) {
453 status = AE_BAD_PARAMETER;
454 goto unlock_and_exit;
455 }
456
457
458 /* Get the parent entry */
459
460 *ret_handle =
461 acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_object (node));
462
463 /* Return exeption if parent is null */
464
465 if (!acpi_ns_get_parent_object (node)) {
466 status = AE_NULL_ENTRY;
467 }
468
469
470 unlock_and_exit:
471
472 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
473 return (status);
474 }
475
476
477 /*******************************************************************************
478 *
479 * FUNCTION: Acpi_walk_namespace
480 *
481 * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for
482 * Start_object - Handle in namespace where search begins
483 * Max_depth - Depth to which search is to reach
484 * User_function - Called when an object of "Type" is found
485 * Context - Passed to user function
486 * Return_value - Location where return value of
487 * User_function is put if terminated early
488 *
489 * RETURNS Return value from the User_function if terminated early.
490 * Otherwise, returns NULL.
491 *
492 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
493 * starting (and ending) at the object specified by Start_handle.
494 * The User_function is called whenever an object that matches
495 * the type parameter is found. If the user function returns
496 * a non-zero value, the search is terminated immediately and this
497 * value is returned to the caller.
498 *
499 * The point of this procedure is to provide a generic namespace
500 * walk routine that can be called from multiple places to
501 * provide multiple services; the User Function can be tailored
502 * to each task, whether it is a print function, a compare
503 * function, etc.
504 *
505 ******************************************************************************/
506
507 ACPI_STATUS
508 acpi_walk_namespace (
509 ACPI_OBJECT_TYPE type,
510 ACPI_HANDLE start_object,
511 u32 max_depth,
512 WALK_CALLBACK user_function,
513 void *context,
514 void **return_value)
515 {
516 ACPI_STATUS status;
517
518
519 /* Parameter validation */
520
521 if ((type > ACPI_TYPE_MAX) ||
522 (!max_depth) ||
523 (!user_function)) {
524 return (AE_BAD_PARAMETER);
525 }
526
527 /*
528 * Lock the namespace around the walk.
529 * The namespace will be unlocked/locked around each call
530 * to the user function - since this function
531 * must be allowed to make Acpi calls itself.
532 */
533
534 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
535 status = acpi_ns_walk_namespace ((OBJECT_TYPE_INTERNAL) type,
536 start_object, max_depth,
537 NS_WALK_UNLOCK,
538 user_function, context,
539 return_value);
540
541 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
542
543 return (status);
544 }
545
546
547 /*******************************************************************************
548 *
549 * FUNCTION: Acpi_ns_get_device_callback
550 *
551 * PARAMETERS: Callback from Acpi_get_device
552 *
553 * RETURN: Status
554 *
555 * DESCRIPTION: Takes callbacks from Walk_namespace and filters out all non-
556 * present devices, or if they specified a HID, it filters based
557 * on that.
558 *
559 ******************************************************************************/
560
561 static ACPI_STATUS
562 acpi_ns_get_device_callback (
563 ACPI_HANDLE obj_handle,
564 u32 nesting_level,
565 void *context,
566 void **return_value)
567 {
568 ACPI_STATUS status;
569 ACPI_NAMESPACE_NODE *node;
570 u32 flags;
571 DEVICE_ID device_id;
572 ACPI_GET_DEVICES_INFO *info;
573
574
575 info = context;
576
577 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
578
579 node = acpi_ns_convert_handle_to_entry (obj_handle);
580
581 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
582
583 if (!node) {
584 return (AE_BAD_PARAMETER);
585 }
586
587 /*
588 * Run _STA to determine if device is present
589 */
590
591 status = acpi_cm_execute_STA (node, &flags);
592 if (ACPI_FAILURE (status)) {
593 return (status);
594 }
595
596 if (!(flags & 0x01)) {
597 /* don't return at the device or children of the device if not there */
598
599 return (AE_CTRL_DEPTH);
600 }
601
602 /*
603 * Filter based on device HID
604 */
605 if (info->hid != NULL) {
606 status = acpi_cm_execute_HID (node, &device_id);
607
608 if (status == AE_NOT_FOUND) {
609 return (AE_OK);
610 }
611
612 else if (ACPI_FAILURE (status)) {
613 return (status);
614 }
615
616 if (STRNCMP (device_id.buffer, info->hid, sizeof (device_id.buffer)) != 0) {
617 return (AE_OK);
618 }
619 }
620
621 info->user_function (obj_handle, nesting_level, info->context, return_value);
622
623 return (AE_OK);
624 }
625
626
627 /*******************************************************************************
628 *
629 * FUNCTION: Acpi_get_devices
630 *
631 * PARAMETERS: HID - HID to search for. Can be NULL.
632 * User_function - Called when a matching object is found
633 * Context - Passed to user function
634 * Return_value - Location where return value of
635 * User_function is put if terminated early
636 *
637 * RETURNS Return value from the User_function if terminated early.
638 * Otherwise, returns NULL.
639 *
640 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
641 * starting (and ending) at the object specified by Start_handle.
642 * The User_function is called whenever an object that matches
643 * the type parameter is found. If the user function returns
644 * a non-zero value, the search is terminated immediately and this
645 * value is returned to the caller.
646 *
647 * This is a wrapper for Walk_namespace, but the callback performs
648 * additional filtering. Please see Acpi_get_device_callback.
649 *
650 ******************************************************************************/
651
652 ACPI_STATUS
653 acpi_get_devices (
654 NATIVE_CHAR *HID,
655 WALK_CALLBACK user_function,
656 void *context,
657 void **return_value)
658 {
659 ACPI_STATUS status;
660 ACPI_GET_DEVICES_INFO info;
661
662
663 /* Parameter validation */
664
665 if (!user_function) {
666 return (AE_BAD_PARAMETER);
667 }
668
669 /*
670 * We're going to call their callback from OUR callback, so we need
671 * to know what it is, and their context parameter.
672 */
673 info.context = context;
674 info.user_function = user_function;
675 info.hid = HID;
676
677 /*
678 * Lock the namespace around the walk.
679 * The namespace will be unlocked/locked around each call
680 * to the user function - since this function
681 * must be allowed to make Acpi calls itself.
682 */
683
684 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
685 status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE,
686 ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
687 NS_WALK_UNLOCK,
688 acpi_ns_get_device_callback, &info,
689 return_value);
690
691 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
692
693 return (status);
694 }