merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / 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: 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 "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