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