]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/contrib/dev/acpica/common/dmextern.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / sys / contrib / dev / acpica / common / dmextern.c
1 /******************************************************************************
2  *
3  * Module Name: dmextern - Support for External() ASL statements
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2013, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #include <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/amlcode.h>
47 #include <contrib/dev/acpica/include/acnamesp.h>
48 #include <contrib/dev/acpica/include/acdisasm.h>
49 #include <contrib/dev/acpica/compiler/aslcompiler.h>
50 #include <stdio.h>
51 #include <errno.h>
52
53
54 /*
55  * This module is used for application-level code (iASL disassembler) only.
56  *
57  * It contains the code to create and emit any necessary External() ASL
58  * statements for the module being disassembled.
59  */
60 #define _COMPONENT          ACPI_CA_DISASSEMBLER
61         ACPI_MODULE_NAME    ("dmextern")
62
63
64 /*
65  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
66  * ObjectTypeKeyword. Used to generate typed external declarations
67  */
68 static const char           *AcpiGbl_DmTypeNames[] =
69 {
70     /* 00 */ "",                    /* Type ANY */
71     /* 01 */ ", IntObj",
72     /* 02 */ ", StrObj",
73     /* 03 */ ", BuffObj",
74     /* 04 */ ", PkgObj",
75     /* 05 */ ", FieldUnitObj",
76     /* 06 */ ", DeviceObj",
77     /* 07 */ ", EventObj",
78     /* 08 */ ", MethodObj",
79     /* 09 */ ", MutexObj",
80     /* 10 */ ", OpRegionObj",
81     /* 11 */ ", PowerResObj",
82     /* 12 */ ", ProcessorObj",
83     /* 13 */ ", ThermalZoneObj",
84     /* 14 */ ", BuffFieldObj",
85     /* 15 */ ", DDBHandleObj",
86     /* 16 */ "",                    /* Debug object */
87     /* 17 */ ", FieldUnitObj",
88     /* 18 */ ", FieldUnitObj",
89     /* 19 */ ", FieldUnitObj"
90 };
91
92 #define METHOD_SEPARATORS           " \t,()\n"
93
94
95 /* Local prototypes */
96
97 static const char *
98 AcpiDmGetObjectTypeName (
99     ACPI_OBJECT_TYPE        Type);
100
101 static char *
102 AcpiDmNormalizeParentPrefix (
103     ACPI_PARSE_OBJECT       *Op,
104     char                    *Path);
105
106 static void
107 AcpiDmAddToExternalListFromFile (
108     char                    *Path,
109     UINT8                   Type,
110     UINT32                  Value);
111
112
113 /*******************************************************************************
114  *
115  * FUNCTION:    AcpiDmGetObjectTypeName
116  *
117  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
118  *
119  * RETURN:      Pointer to a string
120  *
121  * DESCRIPTION: Map an object type to the ASL object type string.
122  *
123  ******************************************************************************/
124
125 static const char *
126 AcpiDmGetObjectTypeName (
127     ACPI_OBJECT_TYPE        Type)
128 {
129
130     if (Type == ACPI_TYPE_LOCAL_SCOPE)
131     {
132         Type = ACPI_TYPE_DEVICE;
133     }
134
135     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
136     {
137         return ("");
138     }
139
140     return (AcpiGbl_DmTypeNames[Type]);
141 }
142
143
144 /*******************************************************************************
145  *
146  * FUNCTION:    AcpiDmNormalizeParentPrefix
147  *
148  * PARAMETERS:  Op                  - Parse op
149  *              Path                - Path with parent prefix
150  *
151  * RETURN:      The full pathname to the object (from the namespace root)
152  *
153  * DESCRIPTION: Returns the full pathname of a path with parent prefix
154  *              The caller must free the fullpath returned.
155  *
156  ******************************************************************************/
157
158 static char *
159 AcpiDmNormalizeParentPrefix (
160     ACPI_PARSE_OBJECT       *Op,
161     char                    *Path)
162 {
163     ACPI_NAMESPACE_NODE     *Node;
164     char                    *Fullpath;
165     char                    *ParentPath;
166     ACPI_SIZE               Length;
167     UINT32                  Index = 0;
168
169
170     if (!Op)
171     {
172         return (NULL);
173     }
174
175     /* Search upwards in the parse tree until we reach the next namespace node */
176
177     Op = Op->Common.Parent;
178     while (Op)
179     {
180         if (Op->Common.Node)
181         {
182             break;
183         }
184
185         Op = Op->Common.Parent;
186     }
187
188     if (!Op)
189     {
190         return (NULL);
191     }
192
193     /*
194      * Find the actual parent node for the reference:
195      * Remove all carat prefixes from the input path.
196      * There may be multiple parent prefixes (For example, ^^^M000)
197      */
198     Node = Op->Common.Node;
199     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
200     {
201         Node = Node->Parent;
202         Path++;
203     }
204
205     if (!Node)
206     {
207         return (NULL);
208     }
209
210     /* Get the full pathname for the parent node */
211
212     ParentPath = AcpiNsGetExternalPathname (Node);
213     if (!ParentPath)
214     {
215         return (NULL);
216     }
217
218     Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
219     if (ParentPath[1])
220     {
221         /*
222          * If ParentPath is not just a simple '\', increment the length
223          * for the required dot separator (ParentPath.Path)
224          */
225         Length++;
226
227         /* For External() statements, we do not want a leading '\' */
228
229         if (*ParentPath == AML_ROOT_PREFIX)
230         {
231             Index = 1;
232         }
233     }
234
235     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
236     if (!Fullpath)
237     {
238         goto Cleanup;
239     }
240
241     /*
242      * Concatenate parent fullpath and path. For example,
243      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
244      *
245      * Copy the parent path
246      */
247     ACPI_STRCPY (Fullpath, &ParentPath[Index]);
248
249     /*
250      * Add dot separator
251      * (don't need dot if parent fullpath is a single backslash)
252      */
253     if (ParentPath[1])
254     {
255         ACPI_STRCAT (Fullpath, ".");
256     }
257
258     /* Copy child path (carat parent prefix(es) were skipped above) */
259
260     ACPI_STRCAT (Fullpath, Path);
261
262 Cleanup:
263     ACPI_FREE (ParentPath);
264     return (Fullpath);
265 }
266
267
268 /*******************************************************************************
269  *
270  * FUNCTION:    AcpiDmAddToExternalFileList
271  *
272  * PARAMETERS:  PathList            - Single path or list separated by comma
273  *
274  * RETURN:      None
275  *
276  * DESCRIPTION: Add external files to global list
277  *
278  ******************************************************************************/
279
280 ACPI_STATUS
281 AcpiDmAddToExternalFileList (
282     char                    *PathList)
283 {
284     ACPI_EXTERNAL_FILE      *ExternalFile;
285     char                    *Path;
286     char                    *TmpPath;
287
288
289     if (!PathList)
290     {
291         return (AE_OK);
292     }
293
294     Path = strtok (PathList, ",");
295
296     while (Path)
297     {
298         TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
299         if (!TmpPath)
300         {
301             return (AE_NO_MEMORY);
302         }
303
304         ACPI_STRCPY (TmpPath, Path);
305
306         ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
307         if (!ExternalFile)
308         {
309             ACPI_FREE (TmpPath);
310             return (AE_NO_MEMORY);
311         }
312
313         ExternalFile->Path = TmpPath;
314
315         if (AcpiGbl_ExternalFileList)
316         {
317             ExternalFile->Next = AcpiGbl_ExternalFileList;
318         }
319
320         AcpiGbl_ExternalFileList = ExternalFile;
321         Path = strtok (NULL, ",");
322     }
323
324     return (AE_OK);
325 }
326
327
328 /*******************************************************************************
329  *
330  * FUNCTION:    AcpiDmClearExternalFileList
331  *
332  * PARAMETERS:  None
333  *
334  * RETURN:      None
335  *
336  * DESCRIPTION: Clear the external file list
337  *
338  ******************************************************************************/
339
340 void
341 AcpiDmClearExternalFileList (
342     void)
343 {
344     ACPI_EXTERNAL_FILE      *NextExternal;
345
346
347     while (AcpiGbl_ExternalFileList)
348     {
349         NextExternal = AcpiGbl_ExternalFileList->Next;
350         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
351         ACPI_FREE (AcpiGbl_ExternalFileList);
352         AcpiGbl_ExternalFileList = NextExternal;
353     }
354 }
355
356
357 /*******************************************************************************
358  *
359  * FUNCTION:    AcpiDmAddToExternalList
360  *
361  * PARAMETERS:  Op                  - Current parser Op
362  *              Path                - Internal (AML) path to the object
363  *              Type                - ACPI object type to be added
364  *              Value               - Arg count if adding a Method object
365  *
366  * RETURN:      None
367  *
368  * DESCRIPTION: Insert a new name into the global list of Externals which
369  *              will in turn be later emitted as an External() declaration
370  *              in the disassembled output.
371  *
372  ******************************************************************************/
373
374 void
375 AcpiDmAddToExternalList (
376     ACPI_PARSE_OBJECT       *Op,
377     char                    *Path,
378     UINT8                   Type,
379     UINT32                  Value)
380 {
381     char                    *ExternalPath;
382     char                    *Fullpath = NULL;
383     ACPI_EXTERNAL_LIST      *NewExternal;
384     ACPI_EXTERNAL_LIST      *NextExternal;
385     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
386     ACPI_STATUS             Status;
387     BOOLEAN                 Resolved = FALSE;
388
389
390     if (!Path)
391     {
392         return;
393     }
394
395     if (Type == ACPI_TYPE_METHOD)
396     {
397         if (Value & 0x80)
398         {
399             Resolved = TRUE;
400         }
401         Value &= 0x07;
402     }
403
404     /*
405      * We don't want External() statements to contain a leading '\'.
406      * This prevents duplicate external statements of the form:
407      *
408      *    External (\ABCD)
409      *    External (ABCD)
410      *
411      * This would cause a compile time error when the disassembled
412      * output file is recompiled.
413      */
414     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
415     {
416         Path++;
417     }
418
419     /* Externalize the ACPI pathname */
420
421     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
422                 NULL, &ExternalPath);
423     if (ACPI_FAILURE (Status))
424     {
425         return;
426     }
427
428     /*
429      * Get the full pathname from the root if "Path" has one or more
430      * parent prefixes (^). Note: path will not contain a leading '\'.
431      */
432     if (*Path == (UINT8) AML_PARENT_PREFIX)
433     {
434         Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
435         if (Fullpath)
436         {
437             /* Set new external path */
438
439             ACPI_FREE (ExternalPath);
440             ExternalPath = Fullpath;
441         }
442     }
443
444     /* Check all existing externals to ensure no duplicates */
445
446     NextExternal = AcpiGbl_ExternalList;
447     while (NextExternal)
448     {
449         if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
450         {
451             /* Duplicate method, check that the Value (ArgCount) is the same */
452
453             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
454                 (NextExternal->Value != Value))
455             {
456                 ACPI_ERROR ((AE_INFO,
457                     "External method arg count mismatch %s: Current %u, attempted %u",
458                     NextExternal->Path, NextExternal->Value, Value));
459             }
460
461             /* Allow upgrade of type from ANY */
462
463             else if (NextExternal->Type == ACPI_TYPE_ANY)
464             {
465                 NextExternal->Type = Type;
466                 NextExternal->Value = Value;
467             }
468
469             ACPI_FREE (ExternalPath);
470             return;
471         }
472
473         NextExternal = NextExternal->Next;
474     }
475
476     /* Allocate and init a new External() descriptor */
477
478     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
479     if (!NewExternal)
480     {
481         ACPI_FREE (ExternalPath);
482         return;
483     }
484
485     NewExternal->Path = ExternalPath;
486     NewExternal->Type = Type;
487     NewExternal->Value = Value;
488     NewExternal->Resolved = Resolved;
489     NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
490
491     /* Was the external path with parent prefix normalized to a fullpath? */
492
493     if (Fullpath == ExternalPath)
494     {
495         /* Get new internal path */
496
497         Status = AcpiNsInternalizeName (ExternalPath, &Path);
498         if (ACPI_FAILURE (Status))
499         {
500             ACPI_FREE (ExternalPath);
501             ACPI_FREE (NewExternal);
502             return;
503         }
504
505         /* Set flag to indicate External->InternalPath need to be freed */
506
507         NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
508     }
509
510     NewExternal->InternalPath = Path;
511
512     /* Link the new descriptor into the global list, alphabetically ordered */
513
514     NextExternal = AcpiGbl_ExternalList;
515     while (NextExternal)
516     {
517         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
518         {
519             if (PrevExternal)
520             {
521                 PrevExternal->Next = NewExternal;
522             }
523             else
524             {
525                 AcpiGbl_ExternalList = NewExternal;
526             }
527
528             NewExternal->Next = NextExternal;
529             return;
530         }
531
532         PrevExternal = NextExternal;
533         NextExternal = NextExternal->Next;
534     }
535
536     if (PrevExternal)
537     {
538         PrevExternal->Next = NewExternal;
539     }
540     else
541     {
542         AcpiGbl_ExternalList = NewExternal;
543     }
544 }
545
546
547 /*******************************************************************************
548  *
549  * FUNCTION:    AcpiDmGetExternalsFromFile
550  *
551  * PARAMETERS:  None
552  *
553  * RETURN:      None
554  *
555  * DESCRIPTION: Process the optional external reference file.
556  *
557  * Each line in the file should be of the form:
558  *      External (<Method namepath>, MethodObj, <ArgCount>)
559  *
560  * Example:
561  *      External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
562  *
563  ******************************************************************************/
564
565 void
566 AcpiDmGetExternalsFromFile (
567     void)
568 {
569     FILE                    *ExternalRefFile;
570     char                    *Token;
571     char                    *MethodName;
572     UINT32                  ArgCount;
573     UINT32                  ImportCount = 0;
574
575
576     if (!Gbl_ExternalRefFilename)
577     {
578         return;
579     }
580
581     /* Open the file */
582
583     ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r");
584     if (!ExternalRefFile)
585     {
586         fprintf (stderr, "Could not open external reference file \"%s\"\n",
587             Gbl_ExternalRefFilename);
588         return;
589     }
590
591     /* Each line defines a method */
592
593     while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
594     {
595         Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
596         if (!Token) continue;
597         if (strcmp (Token, "External")) continue;
598
599         MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
600         if (!MethodName) continue;
601
602         Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
603         if (!Token) continue;
604         if (strcmp (Token, "MethodObj")) continue;
605
606         Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
607         if (!Token) continue;
608
609         /* Convert arg count string to an integer */
610
611         errno = 0;
612         ArgCount = strtoul (Token, NULL, 0);
613         if (errno)
614         {
615             fprintf (stderr, "Invalid argument count (%s)\n", Token);
616             continue;
617         }
618         if (ArgCount > 7)
619         {
620             fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
621             continue;
622         }
623
624         /* Add this external to the global list */
625
626         AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
627             Gbl_ExternalRefFilename, ArgCount, MethodName);
628
629         AcpiDmAddToExternalListFromFile (MethodName, ACPI_TYPE_METHOD, ArgCount | 0x80);
630         ImportCount++;
631     }
632
633     if (!ImportCount)
634     {
635         fprintf (stderr, "Did not find any external methods in reference file \"%s\"\n",
636             Gbl_ExternalRefFilename);
637     }
638     else
639     {
640         /* Add the external(s) to the namespace */
641
642         AcpiDmAddExternalsToNamespace ();
643
644         AcpiOsPrintf ("%s: Imported %u external method definitions\n",
645             Gbl_ExternalRefFilename, ImportCount);
646     }
647
648     fclose (ExternalRefFile);
649 }
650
651
652 /*******************************************************************************
653  *
654  * FUNCTION:    AcpiDmAddToExternalListFromFile
655  *
656  * PARAMETERS:  Path                - Internal (AML) path to the object
657  *              Type                - ACPI object type to be added
658  *              Value               - Arg count if adding a Method object
659  *
660  * RETURN:      None
661  *
662  * DESCRIPTION: Insert a new name into the global list of Externals which
663  *              will in turn be later emitted as an External() declaration
664  *              in the disassembled output.
665  *
666  ******************************************************************************/
667
668 static void
669 AcpiDmAddToExternalListFromFile (
670     char                    *Path,
671     UINT8                   Type,
672     UINT32                  Value)
673 {
674     char                    *InternalPath;
675     char                    *ExternalPath;
676     ACPI_EXTERNAL_LIST      *NewExternal;
677     ACPI_EXTERNAL_LIST      *NextExternal;
678     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
679     ACPI_STATUS             Status;
680     BOOLEAN                 Resolved = FALSE;
681
682
683     if (!Path)
684     {
685         return;
686     }
687
688     /* TBD: Add a flags parameter */
689
690     if (Type == ACPI_TYPE_METHOD)
691     {
692         if (Value & 0x80)
693         {
694             Resolved = TRUE;
695         }
696         Value &= 0x07;
697     }
698
699     /*
700      * We don't want External() statements to contain a leading '\'.
701      * This prevents duplicate external statements of the form:
702      *
703      *    External (\ABCD)
704      *    External (ABCD)
705      *
706      * This would cause a compile time error when the disassembled
707      * output file is recompiled.
708      */
709     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
710     {
711         Path++;
712     }
713
714     /* Check all existing externals to ensure no duplicates */
715
716     NextExternal = AcpiGbl_ExternalList;
717     while (NextExternal)
718     {
719         if (!ACPI_STRCMP (Path, NextExternal->Path))
720         {
721             /* Duplicate method, check that the Value (ArgCount) is the same */
722
723             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
724                 (NextExternal->Value != Value))
725             {
726                 ACPI_ERROR ((AE_INFO,
727                     "(File) External method arg count mismatch %s: Current %u, override to %u",
728                     NextExternal->Path, NextExternal->Value, Value));
729
730                 /* Override, since new value came from external reference file */
731
732                 NextExternal->Value = Value;
733             }
734
735             /* Allow upgrade of type from ANY */
736
737             else if (NextExternal->Type == ACPI_TYPE_ANY)
738             {
739                 NextExternal->Type = Type;
740                 NextExternal->Value = Value;
741             }
742
743             return;
744         }
745
746         NextExternal = NextExternal->Next;
747     }
748
749     /* Get the internal pathname (AML format) */
750
751     Status = AcpiNsInternalizeName (Path, &InternalPath);
752     if (ACPI_FAILURE (Status))
753     {
754         return;
755     }
756
757     /* Allocate and init a new External() descriptor */
758
759     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
760     if (!NewExternal)
761     {
762         ACPI_FREE (InternalPath);
763         return;
764     }
765
766     /* Must copy and normalize the input path */
767
768     AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, NULL, &ExternalPath);
769
770     NewExternal->Path = ExternalPath;
771     NewExternal->Type = Type;
772     NewExternal->Value = Value;
773     NewExternal->Resolved = Resolved;
774     NewExternal->Length = (UINT16) ACPI_STRLEN (Path);
775     NewExternal->InternalPath = InternalPath;
776
777     /* Set flag to indicate External->InternalPath needs to be freed */
778
779     NewExternal->Flags |= ACPI_IPATH_ALLOCATED | ACPI_FROM_REFERENCE_FILE;
780
781     /* Link the new descriptor into the global list, alphabetically ordered */
782
783     NextExternal = AcpiGbl_ExternalList;
784     while (NextExternal)
785     {
786         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
787         {
788             if (PrevExternal)
789             {
790                 PrevExternal->Next = NewExternal;
791             }
792             else
793             {
794                 AcpiGbl_ExternalList = NewExternal;
795             }
796
797             NewExternal->Next = NextExternal;
798             return;
799         }
800
801         PrevExternal = NextExternal;
802         NextExternal = NextExternal->Next;
803     }
804
805     if (PrevExternal)
806     {
807         PrevExternal->Next = NewExternal;
808     }
809     else
810     {
811         AcpiGbl_ExternalList = NewExternal;
812     }
813 }
814
815
816 /*******************************************************************************
817  *
818  * FUNCTION:    AcpiDmAddExternalsToNamespace
819  *
820  * PARAMETERS:  None
821  *
822  * RETURN:      None
823  *
824  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
825  *              "resolved".
826  *
827  ******************************************************************************/
828
829 void
830 AcpiDmAddExternalsToNamespace (
831     void)
832 {
833     ACPI_STATUS             Status;
834     ACPI_NAMESPACE_NODE     *Node;
835     ACPI_OPERAND_OBJECT     *ObjDesc;
836     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
837
838
839     while (External)
840     {
841         /* Add the external name (object) into the namespace */
842
843         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
844                    ACPI_IMODE_LOAD_PASS1,
845                    ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
846                    NULL, &Node);
847
848         if (ACPI_FAILURE (Status))
849         {
850             ACPI_EXCEPTION ((AE_INFO, Status,
851                 "while adding external to namespace [%s]",
852                 External->Path));
853         }
854
855         else switch (External->Type)
856         {
857         case ACPI_TYPE_METHOD:
858
859             /* For methods, we need to save the argument count */
860
861             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
862             ObjDesc->Method.ParamCount = (UINT8) External->Value;
863             Node->Object = ObjDesc;
864             break;
865
866         case ACPI_TYPE_REGION:
867
868             /* Regions require a region sub-object */
869
870             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
871             ObjDesc->Region.Node = Node;
872             Node->Object = ObjDesc;
873             break;
874
875         default:
876
877             break;
878         }
879
880         External = External->Next;
881     }
882 }
883
884
885 /*******************************************************************************
886  *
887  * FUNCTION:    AcpiDmGetExternalMethodCount
888  *
889  * PARAMETERS:  None
890  *
891  * RETURN:      The number of control method externals in the external list
892  *
893  * DESCRIPTION: Return the number of method externals that have been generated.
894  *              If any control method externals have been found, we must
895  *              re-parse the entire definition block with the new information
896  *              (number of arguments for the methods.) This is limitation of
897  *              AML, we don't know the number of arguments from the control
898  *              method invocation itself.
899  *
900  ******************************************************************************/
901
902 UINT32
903 AcpiDmGetExternalMethodCount (
904     void)
905 {
906     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
907     UINT32                  Count = 0;
908
909
910     while (External)
911     {
912         if (External->Type == ACPI_TYPE_METHOD)
913         {
914             Count++;
915         }
916
917         External = External->Next;
918     }
919
920     return (Count);
921 }
922
923
924 /*******************************************************************************
925  *
926  * FUNCTION:    AcpiDmClearExternalList
927  *
928  * PARAMETERS:  None
929  *
930  * RETURN:      None
931  *
932  * DESCRIPTION: Free the entire External info list
933  *
934  ******************************************************************************/
935
936 void
937 AcpiDmClearExternalList (
938     void)
939 {
940     ACPI_EXTERNAL_LIST      *NextExternal;
941
942
943     while (AcpiGbl_ExternalList)
944     {
945         NextExternal = AcpiGbl_ExternalList->Next;
946         ACPI_FREE (AcpiGbl_ExternalList->Path);
947         ACPI_FREE (AcpiGbl_ExternalList);
948         AcpiGbl_ExternalList = NextExternal;
949     }
950 }
951
952
953 /*******************************************************************************
954  *
955  * FUNCTION:    AcpiDmEmitExternals
956  *
957  * PARAMETERS:  None
958  *
959  * RETURN:      None
960  *
961  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
962  *              the global external info list.
963  *
964  ******************************************************************************/
965
966 void
967 AcpiDmEmitExternals (
968     void)
969 {
970     ACPI_EXTERNAL_LIST      *NextExternal;
971
972
973     if (!AcpiGbl_ExternalList)
974     {
975         return;
976     }
977
978     /*
979      * Determine the number of control methods in the external list, and
980      * also how many of those externals were resolved via the namespace.
981      */
982     NextExternal = AcpiGbl_ExternalList;
983     while (NextExternal)
984     {
985         if (NextExternal->Type == ACPI_TYPE_METHOD)
986         {
987             AcpiGbl_NumExternalMethods++;
988             if (NextExternal->Resolved)
989             {
990                 AcpiGbl_ResolvedExternalMethods++;
991             }
992         }
993
994         NextExternal = NextExternal->Next;
995     }
996
997     /* Check if any control methods were unresolved */
998
999     AcpiDmUnresolvedWarning (1);
1000
1001     /* Emit any unresolved method externals in a single text block */
1002
1003     NextExternal = AcpiGbl_ExternalList;
1004     while (NextExternal)
1005     {
1006         if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
1007             (!NextExternal->Resolved))
1008         {
1009             AcpiOsPrintf ("    External (%s%s",
1010                 NextExternal->Path,
1011                 AcpiDmGetObjectTypeName (NextExternal->Type));
1012
1013             AcpiOsPrintf (
1014                 ")    // Warning: Unresolved Method, "
1015                 "guessing %u arguments (may be incorrect, see warning above)\n",
1016                 NextExternal->Value);
1017
1018             NextExternal->Emitted = TRUE;
1019         }
1020
1021         NextExternal = NextExternal->Next;
1022     }
1023
1024     AcpiOsPrintf ("\n");
1025
1026
1027     /* Emit externals that were imported from a file */
1028
1029     if (Gbl_ExternalRefFilename)
1030     {
1031         AcpiOsPrintf (
1032             "    /*\n     * External declarations that were imported from\n"
1033             "     * the reference file [%s]\n     */\n",
1034             Gbl_ExternalRefFilename);
1035
1036         NextExternal = AcpiGbl_ExternalList;
1037         while (NextExternal)
1038         {
1039             if (!NextExternal->Emitted && (NextExternal->Flags & ACPI_FROM_REFERENCE_FILE))
1040             {
1041                 AcpiOsPrintf ("    External (%s%s",
1042                     NextExternal->Path,
1043                     AcpiDmGetObjectTypeName (NextExternal->Type));
1044
1045                 if (NextExternal->Type == ACPI_TYPE_METHOD)
1046                 {
1047                     AcpiOsPrintf (")    // %u Arguments\n",
1048                         NextExternal->Value);
1049                 }
1050                 else
1051                 {
1052                     AcpiOsPrintf (")\n");
1053                 }
1054                 NextExternal->Emitted = TRUE;
1055             }
1056
1057             NextExternal = NextExternal->Next;
1058         }
1059
1060         AcpiOsPrintf ("\n");
1061     }
1062
1063     /*
1064      * Walk the list of externals found during the AML parsing
1065      */
1066     while (AcpiGbl_ExternalList)
1067     {
1068         if (!AcpiGbl_ExternalList->Emitted)
1069         {
1070             AcpiOsPrintf ("    External (%s%s",
1071                 AcpiGbl_ExternalList->Path,
1072                 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1073
1074             /* For methods, add a comment with the number of arguments */
1075
1076             if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1077             {
1078                 AcpiOsPrintf (")    // %u Arguments\n",
1079                     AcpiGbl_ExternalList->Value);
1080             }
1081             else
1082             {
1083                 AcpiOsPrintf (")\n");
1084             }
1085         }
1086
1087         /* Free this external info block and move on to next external */
1088
1089         NextExternal = AcpiGbl_ExternalList->Next;
1090         if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
1091         {
1092             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1093         }
1094
1095         ACPI_FREE (AcpiGbl_ExternalList->Path);
1096         ACPI_FREE (AcpiGbl_ExternalList);
1097         AcpiGbl_ExternalList = NextExternal;
1098     }
1099
1100     AcpiOsPrintf ("\n");
1101 }
1102
1103
1104 /*******************************************************************************
1105  *
1106  * FUNCTION:    AcpiDmUnresolvedWarning
1107  *
1108  * PARAMETERS:  Type                - Where to output the warning.
1109  *                                    0 means write to stderr
1110  *                                    1 means write to AcpiOsPrintf
1111  *
1112  * RETURN:      None
1113  *
1114  * DESCRIPTION: Issue warning message if there are unresolved external control
1115  *              methods within the disassembly.
1116  *
1117  ******************************************************************************/
1118
1119 #if 0
1120 Summary of the external control method problem:
1121
1122 When the -e option is used with disassembly, the various SSDTs are simply
1123 loaded into a global namespace for the disassembler to use in order to
1124 resolve control method references (invocations).
1125
1126 The disassembler tracks any such references, and will emit an External()
1127 statement for these types of methods, with the proper number of arguments .
1128
1129 Without the SSDTs, the AML does not contain enough information to properly
1130 disassemble the control method invocation -- because the disassembler does
1131 not know how many arguments to parse.
1132
1133 An example: Assume we have two control methods. ABCD has one argument, and
1134 EFGH has zero arguments. Further, we have two additional control methods
1135 that invoke ABCD and EFGH, named T1 and T2:
1136
1137     Method (ABCD, 1)
1138     {
1139     }
1140     Method (EFGH, 0)
1141     {
1142     }
1143     Method (T1)
1144     {
1145         ABCD (Add (2, 7, Local0))
1146     }
1147     Method (T2)
1148     {
1149         EFGH ()
1150         Add (2, 7, Local0)
1151     }
1152
1153 Here is the AML code that is generated for T1 and T2:
1154
1155      185:      Method (T1)
1156
1157 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1158
1159      186:      {
1160      187:          ABCD (Add (2, 7, Local0))
1161
1162 00000353:  41 42 43 44 ............    "ABCD"
1163 00000357:  72 0A 02 0A 07 60 ......    "r....`"
1164
1165      188:      }
1166
1167      190:      Method (T2)
1168
1169 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1170
1171      191:      {
1172      192:          EFGH ()
1173
1174 00000364:  45 46 47 48 ............    "EFGH"
1175
1176      193:          Add (2, 7, Local0)
1177
1178 00000368:  72 0A 02 0A 07 60 ......    "r....`"
1179      194:      }
1180
1181 Note that the AML code for T1 and T2 is essentially identical. When
1182 disassembling this code, the methods ABCD and EFGH must be known to the
1183 disassembler, otherwise it does not know how to handle the method invocations.
1184
1185 In other words, if ABCD and EFGH are actually external control methods
1186 appearing in an SSDT, the disassembler does not know what to do unless
1187 the owning SSDT has been loaded via the -e option.
1188 #endif
1189
1190 void
1191 AcpiDmUnresolvedWarning (
1192     UINT8                   Type)
1193 {
1194
1195     if (!AcpiGbl_NumExternalMethods)
1196     {
1197         return;
1198     }
1199
1200     if (Type)
1201     {
1202         if (!AcpiGbl_ExternalFileList)
1203         {
1204             /* The -e option was not specified */
1205
1206            AcpiOsPrintf ("    /*\n"
1207                 "     * iASL Warning: There were %u external control methods found during\n"
1208                 "     * disassembly, but additional ACPI tables to resolve these externals\n"
1209                 "     * were not specified. This resulting disassembler output file may not\n"
1210                 "     * compile because the disassembler did not know how many arguments\n"
1211                 "     * to assign to these methods. To specify the tables needed to resolve\n"
1212                 "     * external control method references, use the one of the following\n"
1213                 "     * example iASL invocations:\n"
1214                 "     *     iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
1215                 "     *     iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n"
1216                 "     */\n",
1217                 AcpiGbl_NumExternalMethods);
1218         }
1219         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1220         {
1221             /* The -e option was specified, but there are still some unresolved externals */
1222
1223             AcpiOsPrintf ("    /*\n"
1224                 "     * iASL Warning: There were %u external control methods found during\n"
1225                 "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1226                 "     * ACPI tables are required to properly disassemble the code. This\n"
1227                 "     * resulting disassembler output file may not compile because the\n"
1228                 "     * disassembler did not know how many arguments to assign to the\n"
1229                 "     * unresolved methods.\n"
1230                 "     */\n",
1231                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1232                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1233                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1234         }
1235     }
1236     else
1237     {
1238         if (!AcpiGbl_ExternalFileList)
1239         {
1240             /* The -e option was not specified */
1241
1242             fprintf (stderr, "\n"
1243                 "iASL Warning: There were %u external control methods found during\n"
1244                 "disassembly, but additional ACPI tables to resolve these externals\n"
1245                 "were not specified. The resulting disassembler output file may not\n"
1246                 "compile because the disassembler did not know how many arguments\n"
1247                 "to assign to these methods. To specify the tables needed to resolve\n"
1248                 "external control method references, use the one of the following\n"
1249                 "example iASL invocations:\n"
1250                 "    iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
1251                 "    iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n",
1252                 AcpiGbl_NumExternalMethods);
1253         }
1254         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1255         {
1256             /* The -e option was specified, but there are still some unresolved externals */
1257
1258             fprintf (stderr, "\n"
1259                 "iASL Warning: There were %u external control methods found during\n"
1260                 "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1261                 "ACPI tables are required to properly disassemble the code. The\n"
1262                 "resulting disassembler output file may not compile because the\n"
1263                 "disassembler did not know how many arguments to assign to the\n"
1264                 "unresolved methods.\n",
1265                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1266                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1267                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1268         }
1269     }
1270 }