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