:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / namespace / nsutils.c
1 /******************************************************************************
2  *
3  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
4  *                        parents and siblings and Scope manipulation
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 "acnamesp.h"
30 #include "acinterp.h"
31 #include "amlcode.h"
32 #include "actables.h"
33
34 #define _COMPONENT          ACPI_NAMESPACE
35          MODULE_NAME         ("nsutils")
36
37
38 /****************************************************************************
39  *
40  * FUNCTION:    Acpi_ns_valid_root_prefix
41  *
42  * PARAMETERS:  Prefix          - Character to be checked
43  *
44  * RETURN:      TRUE if a valid prefix
45  *
46  * DESCRIPTION: Check if a character is a valid ACPI Root prefix
47  *
48  ***************************************************************************/
49
50 u8
51 acpi_ns_valid_root_prefix (
52         NATIVE_CHAR             prefix)
53 {
54
55         return ((u8) (prefix == '\\'));
56 }
57
58
59 /****************************************************************************
60  *
61  * FUNCTION:    Acpi_ns_valid_path_separator
62  *
63  * PARAMETERS:  Sep              - Character to be checked
64  *
65  * RETURN:      TRUE if a valid path separator
66  *
67  * DESCRIPTION: Check if a character is a valid ACPI path separator
68  *
69  ***************************************************************************/
70
71 u8
72 acpi_ns_valid_path_separator (
73         NATIVE_CHAR             sep)
74 {
75
76         return ((u8) (sep == '.'));
77 }
78
79
80 /****************************************************************************
81  *
82  * FUNCTION:    Acpi_ns_get_type
83  *
84  * PARAMETERS:  Handle              - Parent Node to be examined
85  *
86  * RETURN:      Type field from Node whose handle is passed
87  *
88  ***************************************************************************/
89
90 OBJECT_TYPE_INTERNAL
91 acpi_ns_get_type (
92         ACPI_HANDLE             handle)
93 {
94
95         if (!handle) {
96                 REPORT_WARNING (("Ns_get_type: Null handle\n"));
97                 return (ACPI_TYPE_ANY);
98         }
99
100         return (((ACPI_NAMESPACE_NODE *) handle)->type);
101 }
102
103
104 /****************************************************************************
105  *
106  * FUNCTION:    Acpi_ns_local
107  *
108  * PARAMETERS:  Type            - A namespace object type
109  *
110  * RETURN:      LOCAL if names must be found locally in objects of the
111  *              passed type, 0 if enclosing scopes should be searched
112  *
113  ***************************************************************************/
114
115 u32
116 acpi_ns_local (
117         OBJECT_TYPE_INTERNAL    type)
118 {
119
120         if (!acpi_cm_valid_object_type (type)) {
121                 /* Type code out of range  */
122
123                 REPORT_WARNING (("Ns_local: Invalid Object Type\n"));
124                 return (NSP_NORMAL);
125         }
126
127         return ((u32) acpi_gbl_ns_properties[type] & NSP_LOCAL);
128 }
129
130
131 /****************************************************************************
132  *
133  * FUNCTION:    Acpi_ns_internalize_name
134  *
135  * PARAMETERS:  *External_name            - External representation of name
136  *              **Converted Name        - Where to return the resulting
137  *                                        internal represention of the name
138  *
139  * RETURN:      Status
140  *
141  * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
142  *              to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
143  *
144  ****************************************************************************/
145
146 ACPI_STATUS
147 acpi_ns_internalize_name (
148         NATIVE_CHAR             *external_name,
149         NATIVE_CHAR             **converted_name)
150 {
151         NATIVE_CHAR             *result = NULL;
152         NATIVE_CHAR             *internal_name;
153         u32                     num_segments = 0;
154         u8                      fully_qualified = FALSE;
155         u32                     i;
156         u32                     num_carats = 0;
157
158
159         if ((!external_name)     ||
160                 (*external_name == 0) ||
161                 (!converted_name)) {
162                 return (AE_BAD_PARAMETER);
163         }
164
165
166         /*
167          * For the internal name, the required length is 4 bytes
168          * per segment, plus 1 each for Root_prefix, Multi_name_prefix_op,
169          * segment count, trailing null (which is not really needed,
170          * but no there's harm in putting it there)
171          *
172          * strlen() + 1 covers the first Name_seg, which has no
173          * path separator
174          */
175
176         if (acpi_ns_valid_root_prefix (external_name[0])) {
177                 fully_qualified = TRUE;
178                 external_name++;
179         }
180
181         else {
182                 /*
183                  * Handle Carat prefixes
184                  */
185
186                 while (*external_name == '^') {
187                         num_carats++;
188                         external_name++;
189                 }
190         }
191
192         /*
193          * Determine the number of ACPI name "segments" by counting
194          * the number of path separators within the string.  Start
195          * with one segment since the segment count is (# separators)
196          * + 1, and zero separators is ok.
197          */
198
199         if (*external_name) {
200                 num_segments = 1;
201                 for (i = 0; external_name[i]; i++) {
202                         if (acpi_ns_valid_path_separator (external_name[i])) {
203                                 num_segments++;
204                         }
205                 }
206         }
207
208
209         /* We need a segment to store the internal version of the name */
210
211         internal_name = acpi_cm_callocate ((ACPI_NAME_SIZE * num_segments) + 4 + num_carats);
212         if (!internal_name) {
213                 return (AE_NO_MEMORY);
214         }
215
216
217         /* Setup the correct prefixes, counts, and pointers */
218
219         if (fully_qualified) {
220                 internal_name[0] = '\\';
221
222                 if (num_segments <= 1) {
223                         result = &internal_name[1];
224                 }
225                 else if (num_segments == 2) {
226                         internal_name[1] = AML_DUAL_NAME_PREFIX;
227                         result = &internal_name[2];
228                 }
229                 else {
230                         internal_name[1] = AML_MULTI_NAME_PREFIX_OP;
231                         internal_name[2] = (char) num_segments;
232                         result = &internal_name[3];
233                 }
234
235         }
236
237         else {
238                 /*
239                  * Not fully qualified.
240                  * Handle Carats first, then append the name segments
241                  */
242
243                 i = 0;
244                 if (num_carats) {
245                         for (i = 0; i < num_carats; i++) {
246                                 internal_name[i] = '^';
247                         }
248                 }
249
250                 if (num_segments == 1) {
251                         result = &internal_name[i];
252                 }
253
254                 else if (num_segments == 2) {
255                         internal_name[i] = AML_DUAL_NAME_PREFIX;
256                         result = &internal_name[i+1];
257                 }
258
259                 else {
260                         internal_name[i] = AML_MULTI_NAME_PREFIX_OP;
261                         internal_name[i+1] = (char) num_segments;
262                         result = &internal_name[i+2];
263                 }
264         }
265
266
267         /* Build the name (minus path separators) */
268
269         for (; num_segments; num_segments--) {
270                 for (i = 0; i < ACPI_NAME_SIZE; i++) {
271                         if (acpi_ns_valid_path_separator (*external_name) ||
272                            (*external_name == 0)) {
273                                 /*
274                                  * Pad the segment with underscore(s) if
275                                  * segment is short
276                                  */
277
278                                 result[i] = '_';
279                         }
280
281                         else {
282                                 /* Convert s8 to uppercase and save it */
283
284                                 result[i] = (char) TOUPPER (*external_name);
285                                 external_name++;
286                         }
287
288                 }
289
290                 /* Now we must have a path separator, or the pathname is bad */
291
292                 if (!acpi_ns_valid_path_separator (*external_name) &&
293                         (*external_name != 0)) {
294                         acpi_cm_free (internal_name);
295                         return (AE_BAD_PARAMETER);
296                 }
297
298                 /* Move on the next segment */
299
300                 external_name++;
301                 result += ACPI_NAME_SIZE;
302         }
303
304
305         /* Return the completed name */
306
307         /* Terminate the string! */
308         *result = 0;
309         *converted_name = internal_name;
310
311
312
313         return (AE_OK);
314 }
315
316
317 /****************************************************************************
318  *
319  * FUNCTION:    Acpi_ns_externalize_name
320  *
321  * PARAMETERS:  *Internal_name         - Internal representation of name
322  *              **Converted_name       - Where to return the resulting
323  *                                        external representation of name
324  *
325  * RETURN:      Status
326  *
327  * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
328  *              to its external form (e.g. "\_PR_.CPU0")
329  *
330  ****************************************************************************/
331
332 ACPI_STATUS
333 acpi_ns_externalize_name (
334         u32                     internal_name_length,
335         char                    *internal_name,
336         u32                     *converted_name_length,
337         char                    **converted_name)
338 {
339         u32                     prefix_length = 0;
340         u32                     names_index = 0;
341         u32                     names_count = 0;
342         u32                     i = 0;
343         u32                     j = 0;
344
345
346         if (!internal_name_length   ||
347                 !internal_name          ||
348                 !converted_name_length  ||
349                 !converted_name) {
350                 return (AE_BAD_PARAMETER);
351         }
352
353
354         /*
355          * Check for a prefix (one '\' | one or more '^').
356          */
357         switch (internal_name[0]) {
358         case '\\':
359                 prefix_length = 1;
360                 break;
361
362         case '^':
363                 for (i = 0; i < internal_name_length; i++) {
364                         if (internal_name[i] != '^') {
365                                 prefix_length = i + 1;
366                         }
367                 }
368
369                 if (i == internal_name_length) {
370                         prefix_length = i;
371                 }
372
373                 break;
374         }
375
376         /*
377          * Check for object names.  Note that there could be 0-255 of these
378          * 4-byte elements.
379          */
380         if (prefix_length < internal_name_length) {
381                 switch (internal_name[prefix_length]) {
382
383                 /* <count> 4-byte names */
384
385                 case AML_MULTI_NAME_PREFIX_OP:
386                         names_index = prefix_length + 2;
387                         names_count = (u32) internal_name[prefix_length + 1];
388                         break;
389
390
391                 /* two 4-byte names */
392
393                 case AML_DUAL_NAME_PREFIX:
394                         names_index = prefix_length + 1;
395                         names_count = 2;
396                         break;
397
398
399                 /* Null_name */
400
401                 case 0:
402                         names_index = 0;
403                         names_count = 0;
404                         break;
405
406
407                 /* one 4-byte name */
408
409                 default:
410                         names_index = prefix_length;
411                         names_count = 1;
412                         break;
413                 }
414         }
415
416         /*
417          * Calculate the length of Converted_name, which equals the length
418          * of the prefix, length of all object names, length of any required
419          * punctuation ('.') between object names, plus the NULL terminator.
420          */
421         *converted_name_length = prefix_length + (4 * names_count) +
422                            ((names_count > 0) ? (names_count - 1) : 0) + 1;
423
424         /*
425          * Check to see if we're still in bounds.  If not, there's a problem
426          * with Internal_name (invalid format).
427          */
428         if (*converted_name_length > internal_name_length) {
429                 REPORT_ERROR (("Ns_externalize_name: Invalid internal name\n"));
430                 return (AE_BAD_PATHNAME);
431         }
432
433         /*
434          * Build Converted_name...
435          */
436
437         (*converted_name) = acpi_cm_callocate (*converted_name_length);
438         if (!(*converted_name)) {
439                 return (AE_NO_MEMORY);
440         }
441
442         j = 0;
443
444         for (i = 0; i < prefix_length; i++) {
445                 (*converted_name)[j++] = internal_name[i];
446         }
447
448         if (names_count > 0) {
449                 for (i = 0; i < names_count; i++) {
450                         if (i > 0) {
451                                 (*converted_name)[j++] = '.';
452                         }
453
454                         (*converted_name)[j++] = internal_name[names_index++];
455                         (*converted_name)[j++] = internal_name[names_index++];
456                         (*converted_name)[j++] = internal_name[names_index++];
457                         (*converted_name)[j++] = internal_name[names_index++];
458                 }
459         }
460
461         return (AE_OK);
462 }
463
464
465 /****************************************************************************
466  *
467  * FUNCTION:    Acpi_ns_convert_handle_to_entry
468  *
469  * PARAMETERS:  Handle          - Handle to be converted to an Node
470  *
471  * RETURN:      A Name table entry pointer
472  *
473  * DESCRIPTION: Convert a namespace handle to a real Node
474  *
475  ****************************************************************************/
476
477 ACPI_NAMESPACE_NODE *
478 acpi_ns_convert_handle_to_entry (
479         ACPI_HANDLE             handle)
480 {
481
482         /*
483          * Simple implementation for now;
484          * TBD: [Future] Real integer handles allow for more verification
485          * and keep all pointers within this subsystem!
486          */
487
488         if (!handle) {
489                 return (NULL);
490         }
491
492         if (handle == ACPI_ROOT_OBJECT) {
493                 return (acpi_gbl_root_node);
494         }
495
496
497         /* We can at least attempt to verify the handle */
498
499         if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) {
500                 return (NULL);
501         }
502
503         return ((ACPI_NAMESPACE_NODE *) handle);
504 }
505
506
507 /****************************************************************************
508  *
509  * FUNCTION:    Acpi_ns_convert_entry_to_handle
510  *
511  * PARAMETERS:  Node          - Node to be converted to a Handle
512  *
513  * RETURN:      An USER ACPI_HANDLE
514  *
515  * DESCRIPTION: Convert a real Node to a namespace handle
516  *
517  ****************************************************************************/
518
519 ACPI_HANDLE
520 acpi_ns_convert_entry_to_handle (
521         ACPI_NAMESPACE_NODE         *node)
522 {
523
524
525         /*
526          * Simple implementation for now;
527          * TBD: [Future] Real integer handles allow for more verification
528          * and keep all pointers within this subsystem!
529          */
530
531         return ((ACPI_HANDLE) node);
532
533
534 /* ---------------------------------------------------
535
536         if (!Node)
537         {
538                 return (NULL);
539         }
540
541         if (Node == Acpi_gbl_Root_node)
542         {
543                 return (ACPI_ROOT_OBJECT);
544         }
545
546
547         return ((ACPI_HANDLE) Node);
548 ------------------------------------------------------*/
549 }
550
551
552 /******************************************************************************
553  *
554  * FUNCTION:    Acpi_ns_terminate
555  *
556  * PARAMETERS:  none
557  *
558  * RETURN:      none
559  *
560  * DESCRIPTION: free memory allocated for table storage.
561  *
562  ******************************************************************************/
563
564 void
565 acpi_ns_terminate (void)
566 {
567         ACPI_OPERAND_OBJECT     *obj_desc;
568         ACPI_NAMESPACE_NODE     *this_node;
569
570
571         this_node = acpi_gbl_root_node;
572
573         /*
574          * 1) Free the entire namespace -- all objects, tables, and stacks
575          */
576         /*
577          * Delete all objects linked to the root
578          * (additional table descriptors)
579          */
580
581         acpi_ns_delete_namespace_subtree (this_node);
582
583         /* Detach any object(s) attached to the root */
584
585         obj_desc = acpi_ns_get_attached_object (this_node);
586         if (obj_desc) {
587                 acpi_ns_detach_object (this_node);
588                 acpi_cm_remove_reference (obj_desc);
589         }
590
591         acpi_ns_delete_children (this_node);
592
593
594         /*
595          * 2) Now we can delete the ACPI tables
596          */
597
598         acpi_tb_delete_acpi_tables ();
599
600         return;
601 }
602
603
604 /****************************************************************************
605  *
606  * FUNCTION:    Acpi_ns_opens_scope
607  *
608  * PARAMETERS:  Type        - A valid namespace type
609  *
610  * RETURN:      NEWSCOPE if the passed type "opens a name scope" according
611  *              to the ACPI specification, else 0
612  *
613  ***************************************************************************/
614
615 u32
616 acpi_ns_opens_scope (
617         OBJECT_TYPE_INTERNAL    type)
618 {
619
620         if (!acpi_cm_valid_object_type (type)) {
621                 /* type code out of range  */
622
623                 REPORT_WARNING (("Ns_opens_scope: Invalid Object Type\n"));
624                 return (NSP_NORMAL);
625         }
626
627         return (((u32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE);
628 }
629
630
631 /****************************************************************************
632  *
633  * FUNCTION:    Acpi_ns_get_node
634  *
635  * PARAMETERS:  *Pathname   - Name to be found, in external (ASL) format. The
636  *                            \ (backslash) and ^ (carat) prefixes, and the
637  *                            . (period) to separate segments are supported.
638  *              Start_node  - Root of subtree to be searched, or NS_ALL for the
639  *                            root of the name space.  If Name is fully
640  *                            qualified (first s8 is '\'), the passed value
641  *                            of Scope will not be accessed.
642  *              Return_node - Where the Node is returned
643  *
644  * DESCRIPTION: Look up a name relative to a given scope and return the
645  *              corresponding Node.  NOTE: Scope can be null.
646  *
647  * MUTEX:       Locks namespace
648  *
649  ***************************************************************************/
650
651 ACPI_STATUS
652 acpi_ns_get_node (
653         NATIVE_CHAR             *pathname,
654         ACPI_NAMESPACE_NODE     *start_node,
655         ACPI_NAMESPACE_NODE     **return_node)
656 {
657         ACPI_GENERIC_STATE      scope_info;
658         ACPI_STATUS             status;
659         NATIVE_CHAR             *internal_path = NULL;
660
661
662         /* Ensure that the namespace has been initialized */
663
664         if (!acpi_gbl_root_node) {
665                 return (AE_NO_NAMESPACE);
666         }
667
668         if (!pathname) {
669                 return (AE_BAD_PARAMETER);
670         }
671
672
673         /* Convert path to internal representation */
674
675         status = acpi_ns_internalize_name (pathname, &internal_path);
676         if (ACPI_FAILURE (status)) {
677                 return (status);
678         }
679
680
681         acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
682
683         /* Setup lookup scope (search starting point) */
684
685         scope_info.scope.node = start_node;
686
687         /* Lookup the name in the namespace */
688
689         status = acpi_ns_lookup (&scope_info, internal_path,
690                          ACPI_TYPE_ANY, IMODE_EXECUTE,
691                          NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
692                          NULL, return_node);
693
694
695
696         acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
697
698         /* Cleanup */
699
700         acpi_cm_free (internal_path);
701
702         return (status);
703 }
704
705
706 /****************************************************************************
707  *
708  * FUNCTION:    Acpi_ns_find_parent_name
709  *
710  * PARAMETERS:  *Child_node            - Named Obj whose name is to be found
711  *
712  * RETURN:      The ACPI name
713  *
714  * DESCRIPTION: Search for the given obj in its parent scope and return the
715  *              name segment, or "????" if the parent name can't be found
716  *              (which "should not happen").
717  *
718  ***************************************************************************/
719
720 ACPI_NAME
721 acpi_ns_find_parent_name (
722         ACPI_NAMESPACE_NODE     *child_node)
723 {
724         ACPI_NAMESPACE_NODE     *parent_node;
725
726
727         if (child_node) {
728                 /* Valid entry.  Get the parent Node */
729
730                 parent_node = acpi_ns_get_parent_object (child_node);
731                 if (parent_node) {
732                         if (parent_node->name) {
733                                 return (parent_node->name);
734                         }
735                 }
736
737         }
738
739
740         return (ACPI_UNKNOWN_NAME);
741 }
742
743
744 /****************************************************************************
745  *
746  * FUNCTION:    Acpi_ns_get_parent_object
747  *
748  * PARAMETERS:  Node       - Current table entry
749  *
750  * RETURN:      Parent entry of the given entry
751  *
752  * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
753  *
754  ***************************************************************************/
755
756
757 ACPI_NAMESPACE_NODE *
758 acpi_ns_get_parent_object (
759         ACPI_NAMESPACE_NODE     *node)
760 {
761
762
763         if (!node) {
764                 return (NULL);
765         }
766
767         /*
768          * Walk to the end of this peer list.
769          * The last entry is marked with a flag and the peer
770          * pointer is really a pointer back to the parent.
771          * This saves putting a parent back pointer in each and
772          * every named object!
773          */
774
775         while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
776                 node = node->peer;
777         }
778
779
780         return (node->peer);
781 }
782
783
784 /****************************************************************************
785  *
786  * FUNCTION:    Acpi_ns_get_next_valid_object
787  *
788  * PARAMETERS:  Node       - Current table entry
789  *
790  * RETURN:      Next valid object in the table.  NULL if no more valid
791  *              objects
792  *
793  * DESCRIPTION: Find the next valid object within a name table.
794  *              Useful for implementing NULL-end-of-list loops.
795  *
796  ***************************************************************************/
797
798
799 ACPI_NAMESPACE_NODE *
800 acpi_ns_get_next_valid_object (
801         ACPI_NAMESPACE_NODE     *node)
802 {
803
804         /* If we are at the end of this peer list, return NULL */
805
806         if (node->flags & ANOBJ_END_OF_PEER_LIST) {
807                 return NULL;
808         }
809
810         /* Otherwise just return the next peer */
811
812         return (node->peer);
813 }
814
815