:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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$
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 }