Sync ACPICA with Intel's version 20151124.
[dragonfly.git] / sys / contrib / dev / acpica / source / common / dmextern.c
1 /******************************************************************************
2  *
3  * Module Name: dmextern - Support for External() ASL statements
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2015, 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 "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 #include "acdisasm.h"
49 #include "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 */ ", UnknownObj",        /* 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 AcpiDmAddPathToExternalList (
108     char                    *Path,
109     UINT8                   Type,
110     UINT32                  Value,
111     UINT16                  Flags);
112
113 static ACPI_STATUS
114 AcpiDmCreateNewExternal (
115     char                    *ExternalPath,
116     char                    *InternalPath,
117     UINT8                   Type,
118     UINT32                  Value,
119     UINT16                  Flags);
120
121
122 /*******************************************************************************
123  *
124  * FUNCTION:    AcpiDmGetObjectTypeName
125  *
126  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
127  *
128  * RETURN:      Pointer to a string
129  *
130  * DESCRIPTION: Map an object type to the ASL object type string.
131  *
132  ******************************************************************************/
133
134 static const char *
135 AcpiDmGetObjectTypeName (
136     ACPI_OBJECT_TYPE        Type)
137 {
138
139     if (Type == ACPI_TYPE_LOCAL_SCOPE)
140     {
141         Type = ACPI_TYPE_DEVICE;
142     }
143     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
144     {
145         return ("");
146     }
147
148     return (AcpiGbl_DmTypeNames[Type]);
149 }
150
151
152 /*******************************************************************************
153  *
154  * FUNCTION:    AcpiDmNormalizeParentPrefix
155  *
156  * PARAMETERS:  Op                  - Parse op
157  *              Path                - Path with parent prefix
158  *
159  * RETURN:      The full pathname to the object (from the namespace root)
160  *
161  * DESCRIPTION: Returns the full pathname of a path with parent prefix
162  *              The caller must free the fullpath returned.
163  *
164  ******************************************************************************/
165
166 static char *
167 AcpiDmNormalizeParentPrefix (
168     ACPI_PARSE_OBJECT       *Op,
169     char                    *Path)
170 {
171     ACPI_NAMESPACE_NODE     *Node;
172     char                    *Fullpath;
173     char                    *ParentPath;
174     ACPI_SIZE               Length;
175     UINT32                  Index = 0;
176
177
178     if (!Op)
179     {
180         return (NULL);
181     }
182
183     /* Search upwards in the parse tree until we reach the next namespace node */
184
185     Op = Op->Common.Parent;
186     while (Op)
187     {
188         if (Op->Common.Node)
189         {
190             break;
191         }
192
193         Op = Op->Common.Parent;
194     }
195
196     if (!Op)
197     {
198         return (NULL);
199     }
200
201     /*
202      * Find the actual parent node for the reference:
203      * Remove all carat prefixes from the input path.
204      * There may be multiple parent prefixes (For example, ^^^M000)
205      */
206     Node = Op->Common.Node;
207     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
208     {
209         Node = Node->Parent;
210         Path++;
211     }
212
213     if (!Node)
214     {
215         return (NULL);
216     }
217
218     /* Get the full pathname for the parent node */
219
220     ParentPath = AcpiNsGetExternalPathname (Node);
221     if (!ParentPath)
222     {
223         return (NULL);
224     }
225
226     Length = (strlen (ParentPath) + strlen (Path) + 1);
227     if (ParentPath[1])
228     {
229         /*
230          * If ParentPath is not just a simple '\', increment the length
231          * for the required dot separator (ParentPath.Path)
232          */
233         Length++;
234
235         /* For External() statements, we do not want a leading '\' */
236
237         if (*ParentPath == AML_ROOT_PREFIX)
238         {
239             Index = 1;
240         }
241     }
242
243     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
244     if (!Fullpath)
245     {
246         goto Cleanup;
247     }
248
249     /*
250      * Concatenate parent fullpath and path. For example,
251      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
252      *
253      * Copy the parent path
254      */
255     strcpy (Fullpath, &ParentPath[Index]);
256
257     /*
258      * Add dot separator
259      * (don't need dot if parent fullpath is a single backslash)
260      */
261     if (ParentPath[1])
262     {
263         strcat (Fullpath, ".");
264     }
265
266     /* Copy child path (carat parent prefix(es) were skipped above) */
267
268     strcat (Fullpath, Path);
269
270 Cleanup:
271     ACPI_FREE (ParentPath);
272     return (Fullpath);
273 }
274
275
276 /*******************************************************************************
277  *
278  * FUNCTION:    AcpiDmAddToExternalFileList
279  *
280  * PARAMETERS:  PathList            - Single path or list separated by comma
281  *
282  * RETURN:      None
283  *
284  * DESCRIPTION: Add external files to global list
285  *
286  ******************************************************************************/
287
288 ACPI_STATUS
289 AcpiDmAddToExternalFileList (
290     char                    *Pathname)
291 {
292     ACPI_EXTERNAL_FILE      *ExternalFile;
293     char                    *LocalPathname;
294
295
296     if (!Pathname)
297     {
298         return (AE_OK);
299     }
300
301     LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1);
302     if (!LocalPathname)
303     {
304         return (AE_NO_MEMORY);
305     }
306
307     ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
308     if (!ExternalFile)
309     {
310         ACPI_FREE (LocalPathname);
311         return (AE_NO_MEMORY);
312     }
313
314     /* Take a copy of the file pathname */
315
316     strcpy (LocalPathname, Pathname);
317     ExternalFile->Path = LocalPathname;
318
319     if (AcpiGbl_ExternalFileList)
320     {
321         ExternalFile->Next = AcpiGbl_ExternalFileList;
322     }
323
324     AcpiGbl_ExternalFileList = ExternalFile;
325     return (AE_OK);
326 }
327
328
329 /*******************************************************************************
330  *
331  * FUNCTION:    AcpiDmClearExternalFileList
332  *
333  * PARAMETERS:  None
334  *
335  * RETURN:      None
336  *
337  * DESCRIPTION: Clear the external file list
338  *
339  ******************************************************************************/
340
341 void
342 AcpiDmClearExternalFileList (
343     void)
344 {
345     ACPI_EXTERNAL_FILE      *NextExternal;
346
347
348     while (AcpiGbl_ExternalFileList)
349     {
350         NextExternal = AcpiGbl_ExternalFileList->Next;
351         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
352         ACPI_FREE (AcpiGbl_ExternalFileList);
353         AcpiGbl_ExternalFileList = NextExternal;
354     }
355 }
356
357
358 /*******************************************************************************
359  *
360  * FUNCTION:    AcpiDmGetExternalsFromFile
361  *
362  * PARAMETERS:  None
363  *
364  * RETURN:      None
365  *
366  * DESCRIPTION: Process the optional external reference file.
367  *
368  * Each line in the file should be of the form:
369  *      External (<Method namepath>, MethodObj, <ArgCount>)
370  *
371  * Example:
372  *      External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
373  *
374  ******************************************************************************/
375
376 void
377 AcpiDmGetExternalsFromFile (
378     void)
379 {
380     FILE                    *ExternalRefFile;
381     char                    *Token;
382     char                    *MethodName;
383     UINT32                  ArgCount;
384     UINT32                  ImportCount = 0;
385
386
387     if (!Gbl_ExternalRefFilename)
388     {
389         return;
390     }
391
392     /* Open the file */
393
394     ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r");
395     if (!ExternalRefFile)
396     {
397         fprintf (stderr, "Could not open external reference file \"%s\"\n",
398             Gbl_ExternalRefFilename);
399         AslAbort ();
400         return;
401     }
402
403     /* Each line defines a method */
404
405     while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
406     {
407         Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
408         if (!Token)
409         {
410             continue;
411         }
412
413         if (strcmp (Token, "External"))
414         {
415             continue;
416         }
417
418         MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
419         if (!MethodName)
420         {
421             continue;
422         }
423
424         Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
425         if (!Token)
426         {
427             continue;
428         }
429
430         if (strcmp (Token, "MethodObj"))
431         {
432             continue;
433         }
434
435         Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
436         if (!Token)
437         {
438             continue;
439         }
440
441         /* Convert arg count string to an integer */
442
443         errno = 0;
444         ArgCount = strtoul (Token, NULL, 0);
445         if (errno)
446         {
447             fprintf (stderr, "Invalid argument count (%s)\n", Token);
448             continue;
449         }
450
451         if (ArgCount > 7)
452         {
453             fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
454             continue;
455         }
456
457         /* Add this external to the global list */
458
459         AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
460             Gbl_ExternalRefFilename, ArgCount, MethodName);
461
462         AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
463             ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
464         ImportCount++;
465     }
466
467     if (!ImportCount)
468     {
469         fprintf (stderr,
470             "Did not find any external methods in reference file \"%s\"\n",
471             Gbl_ExternalRefFilename);
472     }
473     else
474     {
475         /* Add the external(s) to the namespace */
476
477         AcpiDmAddExternalsToNamespace ();
478
479         AcpiOsPrintf ("%s: Imported %u external method definitions\n",
480             Gbl_ExternalRefFilename, ImportCount);
481     }
482
483     fclose (ExternalRefFile);
484 }
485
486
487 /*******************************************************************************
488  *
489  * FUNCTION:    AcpiDmAddOpToExternalList
490  *
491  * PARAMETERS:  Op                  - Current parser Op
492  *              Path                - Internal (AML) path to the object
493  *              Type                - ACPI object type to be added
494  *              Value               - Arg count if adding a Method object
495  *              Flags               - To be passed to the external object
496  *
497  * RETURN:      None
498  *
499  * DESCRIPTION: Insert a new name into the global list of Externals which
500  *              will in turn be later emitted as an External() declaration
501  *              in the disassembled output.
502  *
503  *              This function handles the most common case where the referenced
504  *              name is simply not found in the constructed namespace.
505  *
506  ******************************************************************************/
507
508 void
509 AcpiDmAddOpToExternalList (
510     ACPI_PARSE_OBJECT       *Op,
511     char                    *Path,
512     UINT8                   Type,
513     UINT32                  Value,
514     UINT16                  Flags)
515 {
516     char                    *ExternalPath;
517     char                    *InternalPath = Path;
518     char                    *Temp;
519     ACPI_STATUS             Status;
520
521
522     ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
523
524
525     if (!Path)
526     {
527         return_VOID;
528     }
529
530     /* Remove a root backslash if present */
531
532     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
533     {
534         Path++;
535     }
536
537     /* Externalize the pathname */
538
539     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
540         NULL, &ExternalPath);
541     if (ACPI_FAILURE (Status))
542     {
543         return_VOID;
544     }
545
546     /*
547      * Get the full pathname from the root if "Path" has one or more
548      * parent prefixes (^). Note: path will not contain a leading '\'.
549      */
550     if (*Path == (UINT8) AML_PARENT_PREFIX)
551     {
552         Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
553
554         /* Set new external path */
555
556         ACPI_FREE (ExternalPath);
557         ExternalPath = Temp;
558         if (!Temp)
559         {
560             return_VOID;
561         }
562
563         /* Create the new internal pathname */
564
565         Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
566         Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
567         if (ACPI_FAILURE (Status))
568         {
569             ACPI_FREE (ExternalPath);
570             return_VOID;
571         }
572     }
573
574     /* Create the new External() declaration node */
575
576     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
577         Type, Value, Flags);
578     if (ACPI_FAILURE (Status))
579     {
580         ACPI_FREE (ExternalPath);
581         if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
582         {
583             ACPI_FREE (InternalPath);
584         }
585     }
586
587     return_VOID;
588 }
589
590
591 /*******************************************************************************
592  *
593  * FUNCTION:    AcpiDmAddNodeToExternalList
594  *
595  * PARAMETERS:  Node                - Namespace node for object to be added
596  *              Type                - ACPI object type to be added
597  *              Value               - Arg count if adding a Method object
598  *              Flags               - To be passed to the external object
599  *
600  * RETURN:      None
601  *
602  * DESCRIPTION: Insert a new name into the global list of Externals which
603  *              will in turn be later emitted as an External() declaration
604  *              in the disassembled output.
605  *
606  *              This function handles the case where the referenced name has
607  *              been found in the namespace, but the name originated in a
608  *              table other than the one that is being disassembled (such
609  *              as a table that is added via the iASL -e option).
610  *
611  ******************************************************************************/
612
613 void
614 AcpiDmAddNodeToExternalList (
615     ACPI_NAMESPACE_NODE     *Node,
616     UINT8                   Type,
617     UINT32                  Value,
618     UINT16                  Flags)
619 {
620     char                    *ExternalPath;
621     char                    *InternalPath;
622     char                    *Temp;
623     ACPI_STATUS             Status;
624
625
626     ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
627
628
629     if (!Node)
630     {
631         return_VOID;
632     }
633
634     /* Get the full external and internal pathnames to the node */
635
636     ExternalPath = AcpiNsGetExternalPathname (Node);
637     if (!ExternalPath)
638     {
639         return_VOID;
640     }
641
642     Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
643     if (ACPI_FAILURE (Status))
644     {
645         ACPI_FREE (ExternalPath);
646         return_VOID;
647     }
648
649     /* Remove the root backslash */
650
651     if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1]))
652     {
653         Temp = ACPI_ALLOCATE_ZEROED (strlen (ExternalPath) + 1);
654         if (!Temp)
655         {
656             return_VOID;
657         }
658
659         strcpy (Temp, &ExternalPath[1]);
660         ACPI_FREE (ExternalPath);
661         ExternalPath = Temp;
662     }
663
664     /* Create the new External() declaration node */
665
666     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
667         Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
668     if (ACPI_FAILURE (Status))
669     {
670         ACPI_FREE (ExternalPath);
671         ACPI_FREE (InternalPath);
672     }
673
674     return_VOID;
675 }
676
677
678 /*******************************************************************************
679  *
680  * FUNCTION:    AcpiDmAddPathToExternalList
681  *
682  * PARAMETERS:  Path                - External name of the object to be added
683  *              Type                - ACPI object type to be added
684  *              Value               - Arg count if adding a Method object
685  *              Flags               - To be passed to the external object
686  *
687  * RETURN:      None
688  *
689  * DESCRIPTION: Insert a new name into the global list of Externals which
690  *              will in turn be later emitted as an External() declaration
691  *              in the disassembled output.
692  *
693  *              This function currently is used to add externals via a
694  *              reference file (via the -fe iASL option).
695  *
696  ******************************************************************************/
697
698 static void
699 AcpiDmAddPathToExternalList (
700     char                    *Path,
701     UINT8                   Type,
702     UINT32                  Value,
703     UINT16                  Flags)
704 {
705     char                    *InternalPath;
706     char                    *ExternalPath;
707     ACPI_STATUS             Status;
708
709
710     ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
711
712
713     if (!Path)
714     {
715         return_VOID;
716     }
717
718     /* Remove a root backslash if present */
719
720     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
721     {
722         Path++;
723     }
724
725     /* Create the internal and external pathnames */
726
727     Status = AcpiNsInternalizeName (Path, &InternalPath);
728     if (ACPI_FAILURE (Status))
729     {
730         return_VOID;
731     }
732
733     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
734         NULL, &ExternalPath);
735     if (ACPI_FAILURE (Status))
736     {
737         ACPI_FREE (InternalPath);
738         return_VOID;
739     }
740
741     /* Create the new External() declaration node */
742
743     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
744         Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
745     if (ACPI_FAILURE (Status))
746     {
747         ACPI_FREE (ExternalPath);
748         ACPI_FREE (InternalPath);
749     }
750
751     return_VOID;
752 }
753
754
755 /*******************************************************************************
756  *
757  * FUNCTION:    AcpiDmCreateNewExternal
758  *
759  * PARAMETERS:  ExternalPath        - External path to the object
760  *              InternalPath        - Internal (AML) path to the object
761  *              Type                - ACPI object type to be added
762  *              Value               - Arg count if adding a Method object
763  *              Flags               - To be passed to the external object
764  *
765  * RETURN:      Status
766  *
767  * DESCRIPTION: Common low-level function to insert a new name into the global
768  *              list of Externals which will in turn be later emitted as
769  *              External() declarations in the disassembled output.
770  *
771  *              Note: The external name should not include a root prefix
772  *              (backslash). We do not want External() statements to contain
773  *              a leading '\', as this prevents duplicate external statements
774  *              of the form:
775  *
776  *                  External (\ABCD)
777  *                  External (ABCD)
778  *
779  *              This would cause a compile time error when the disassembled
780  *              output file is recompiled.
781  *
782  *              There are two cases that are handled here. For both, we emit
783  *              an External() statement:
784  *              1) The name was simply not found in the namespace.
785  *              2) The name was found, but it originated in a table other than
786  *              the table that is being disassembled.
787  *
788  ******************************************************************************/
789
790 static ACPI_STATUS
791 AcpiDmCreateNewExternal (
792     char                    *ExternalPath,
793     char                    *InternalPath,
794     UINT8                   Type,
795     UINT32                  Value,
796     UINT16                  Flags)
797 {
798     ACPI_EXTERNAL_LIST      *NewExternal;
799     ACPI_EXTERNAL_LIST      *NextExternal;
800     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
801
802
803     ACPI_FUNCTION_TRACE (DmCreateNewExternal);
804
805
806     /* Check all existing externals to ensure no duplicates */
807
808     NextExternal = AcpiGbl_ExternalList;
809     while (NextExternal)
810     {
811         if (!strcmp (ExternalPath, NextExternal->Path))
812         {
813             /* Duplicate method, check that the Value (ArgCount) is the same */
814
815             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
816                 (NextExternal->Value != Value) &&
817                 (Value > 0))
818             {
819                 ACPI_ERROR ((AE_INFO,
820                     "External method arg count mismatch %s: "
821                     "Current %u, attempted %u",
822                     NextExternal->Path, NextExternal->Value, Value));
823             }
824
825             /* Allow upgrade of type from ANY */
826
827             else if (NextExternal->Type == ACPI_TYPE_ANY)
828             {
829                 NextExternal->Type = Type;
830                 NextExternal->Value = Value;
831             }
832
833             return_ACPI_STATUS (AE_ALREADY_EXISTS);
834         }
835
836         NextExternal = NextExternal->Next;
837     }
838
839     /* Allocate and init a new External() descriptor */
840
841     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
842     if (!NewExternal)
843     {
844         return_ACPI_STATUS (AE_NO_MEMORY);
845     }
846
847     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
848         "Adding external reference node (%s) type [%s]\n",
849         ExternalPath, AcpiUtGetTypeName (Type)));
850
851     NewExternal->Flags = Flags;
852     NewExternal->Value = Value;
853     NewExternal->Path = ExternalPath;
854     NewExternal->Type = Type;
855     NewExternal->Length = (UINT16) strlen (ExternalPath);
856     NewExternal->InternalPath = InternalPath;
857
858     /* Link the new descriptor into the global list, alphabetically ordered */
859
860     NextExternal = AcpiGbl_ExternalList;
861     while (NextExternal)
862     {
863         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
864         {
865             if (PrevExternal)
866             {
867                 PrevExternal->Next = NewExternal;
868             }
869             else
870             {
871                 AcpiGbl_ExternalList = NewExternal;
872             }
873
874             NewExternal->Next = NextExternal;
875             return_ACPI_STATUS (AE_OK);
876         }
877
878         PrevExternal = NextExternal;
879         NextExternal = NextExternal->Next;
880     }
881
882     if (PrevExternal)
883     {
884         PrevExternal->Next = NewExternal;
885     }
886     else
887     {
888         AcpiGbl_ExternalList = NewExternal;
889     }
890
891     return_ACPI_STATUS (AE_OK);
892 }
893
894
895 /*******************************************************************************
896  *
897  * FUNCTION:    AcpiDmAddExternalsToNamespace
898  *
899  * PARAMETERS:  None
900  *
901  * RETURN:      None
902  *
903  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
904  *              "resolved".
905  *
906  ******************************************************************************/
907
908 void
909 AcpiDmAddExternalsToNamespace (
910     void)
911 {
912     ACPI_STATUS             Status;
913     ACPI_NAMESPACE_NODE     *Node;
914     ACPI_OPERAND_OBJECT     *ObjDesc;
915     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
916
917
918     while (External)
919     {
920         /* Add the external name (object) into the namespace */
921
922         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
923             ACPI_IMODE_LOAD_PASS1,
924             ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
925             NULL, &Node);
926
927         if (ACPI_FAILURE (Status))
928         {
929             ACPI_EXCEPTION ((AE_INFO, Status,
930                 "while adding external to namespace [%s]",
931                 External->Path));
932         }
933
934         else switch (External->Type)
935         {
936         case ACPI_TYPE_METHOD:
937
938             /* For methods, we need to save the argument count */
939
940             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
941             ObjDesc->Method.ParamCount = (UINT8) External->Value;
942             Node->Object = ObjDesc;
943             break;
944
945         case ACPI_TYPE_REGION:
946
947             /* Regions require a region sub-object */
948
949             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
950             ObjDesc->Region.Node = Node;
951             Node->Object = ObjDesc;
952             break;
953
954         default:
955
956             break;
957         }
958
959         External = External->Next;
960     }
961 }
962
963
964 /*******************************************************************************
965  *
966  * FUNCTION:    AcpiDmGetExternalMethodCount
967  *
968  * PARAMETERS:  None
969  *
970  * RETURN:      The number of control method externals in the external list
971  *
972  * DESCRIPTION: Return the number of method externals that have been generated.
973  *              If any control method externals have been found, we must
974  *              re-parse the entire definition block with the new information
975  *              (number of arguments for the methods.) This is limitation of
976  *              AML, we don't know the number of arguments from the control
977  *              method invocation itself.
978  *
979  ******************************************************************************/
980
981 UINT32
982 AcpiDmGetExternalMethodCount (
983     void)
984 {
985     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
986     UINT32                  Count = 0;
987
988
989     while (External)
990     {
991         if (External->Type == ACPI_TYPE_METHOD)
992         {
993             Count++;
994         }
995
996         External = External->Next;
997     }
998
999     return (Count);
1000 }
1001
1002
1003 /*******************************************************************************
1004  *
1005  * FUNCTION:    AcpiDmClearExternalList
1006  *
1007  * PARAMETERS:  None
1008  *
1009  * RETURN:      None
1010  *
1011  * DESCRIPTION: Free the entire External info list
1012  *
1013  ******************************************************************************/
1014
1015 void
1016 AcpiDmClearExternalList (
1017     void)
1018 {
1019     ACPI_EXTERNAL_LIST      *NextExternal;
1020
1021
1022     while (AcpiGbl_ExternalList)
1023     {
1024         NextExternal = AcpiGbl_ExternalList->Next;
1025         ACPI_FREE (AcpiGbl_ExternalList->Path);
1026         ACPI_FREE (AcpiGbl_ExternalList);
1027         AcpiGbl_ExternalList = NextExternal;
1028     }
1029 }
1030
1031
1032 /*******************************************************************************
1033  *
1034  * FUNCTION:    AcpiDmEmitExternals
1035  *
1036  * PARAMETERS:  None
1037  *
1038  * RETURN:      None
1039  *
1040  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1041  *              the global external info list.
1042  *
1043  ******************************************************************************/
1044
1045 void
1046 AcpiDmEmitExternals (
1047     void)
1048 {
1049     ACPI_EXTERNAL_LIST      *NextExternal;
1050
1051
1052     if (!AcpiGbl_ExternalList)
1053     {
1054         return;
1055     }
1056
1057     /*
1058      * Determine the number of control methods in the external list, and
1059      * also how many of those externals were resolved via the namespace.
1060      */
1061     NextExternal = AcpiGbl_ExternalList;
1062     while (NextExternal)
1063     {
1064         if (NextExternal->Type == ACPI_TYPE_METHOD)
1065         {
1066             AcpiGbl_NumExternalMethods++;
1067             if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1068             {
1069                 AcpiGbl_ResolvedExternalMethods++;
1070             }
1071         }
1072
1073         NextExternal = NextExternal->Next;
1074     }
1075
1076     /* Check if any control methods were unresolved */
1077
1078     AcpiDmUnresolvedWarning (1);
1079
1080     /* Emit any unresolved method externals in a single text block */
1081
1082     NextExternal = AcpiGbl_ExternalList;
1083     while (NextExternal)
1084     {
1085         if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
1086             (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1087         {
1088             AcpiOsPrintf ("    External (%s%s",
1089                 NextExternal->Path,
1090                 AcpiDmGetObjectTypeName (NextExternal->Type));
1091
1092             AcpiOsPrintf (")    // Warning: Unresolved method, "
1093                 "guessing %u arguments\n",
1094                 NextExternal->Value);
1095
1096             NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1097         }
1098
1099         NextExternal = NextExternal->Next;
1100     }
1101
1102     AcpiOsPrintf ("\n");
1103
1104
1105     /* Emit externals that were imported from a file */
1106
1107     if (Gbl_ExternalRefFilename)
1108     {
1109         AcpiOsPrintf (
1110             "    /*\n     * External declarations that were imported from\n"
1111             "     * the reference file [%s]\n     */\n",
1112             Gbl_ExternalRefFilename);
1113
1114         NextExternal = AcpiGbl_ExternalList;
1115         while (NextExternal)
1116         {
1117             if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) &&
1118                 (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE))
1119             {
1120                 AcpiOsPrintf ("    External (%s%s",
1121                     NextExternal->Path,
1122                     AcpiDmGetObjectTypeName (NextExternal->Type));
1123
1124                 if (NextExternal->Type == ACPI_TYPE_METHOD)
1125                 {
1126                     AcpiOsPrintf (")    // %u Arguments\n",
1127                         NextExternal->Value);
1128                 }
1129                 else
1130                 {
1131                     AcpiOsPrintf (")\n");
1132                 }
1133                 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1134             }
1135
1136             NextExternal = NextExternal->Next;
1137         }
1138
1139         AcpiOsPrintf ("\n");
1140     }
1141
1142     /*
1143      * Walk the list of externals found during the AML parsing
1144      */
1145     while (AcpiGbl_ExternalList)
1146     {
1147         if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1148         {
1149             AcpiOsPrintf ("    External (%s%s",
1150                 AcpiGbl_ExternalList->Path,
1151                 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1152
1153             /* For methods, add a comment with the number of arguments */
1154
1155             if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1156             {
1157                 AcpiOsPrintf (")    // %u Arguments\n",
1158                     AcpiGbl_ExternalList->Value);
1159             }
1160             else
1161             {
1162                 AcpiOsPrintf (")\n");
1163             }
1164         }
1165
1166         /* Free this external info block and move on to next external */
1167
1168         NextExternal = AcpiGbl_ExternalList->Next;
1169         if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1170         {
1171             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1172         }
1173
1174         ACPI_FREE (AcpiGbl_ExternalList->Path);
1175         ACPI_FREE (AcpiGbl_ExternalList);
1176         AcpiGbl_ExternalList = NextExternal;
1177     }
1178
1179     AcpiOsPrintf ("\n");
1180 }
1181
1182
1183 /*******************************************************************************
1184  *
1185  * FUNCTION:    AcpiDmUnresolvedWarning
1186  *
1187  * PARAMETERS:  Type                - Where to output the warning.
1188  *                                    0 means write to stderr
1189  *                                    1 means write to AcpiOsPrintf
1190  *
1191  * RETURN:      None
1192  *
1193  * DESCRIPTION: Issue warning message if there are unresolved external control
1194  *              methods within the disassembly.
1195  *
1196  ******************************************************************************/
1197
1198 #if 0
1199 Summary of the external control method problem:
1200
1201 When the -e option is used with disassembly, the various SSDTs are simply
1202 loaded into a global namespace for the disassembler to use in order to
1203 resolve control method references (invocations).
1204
1205 The disassembler tracks any such references, and will emit an External()
1206 statement for these types of methods, with the proper number of arguments .
1207
1208 Without the SSDTs, the AML does not contain enough information to properly
1209 disassemble the control method invocation -- because the disassembler does
1210 not know how many arguments to parse.
1211
1212 An example: Assume we have two control methods. ABCD has one argument, and
1213 EFGH has zero arguments. Further, we have two additional control methods
1214 that invoke ABCD and EFGH, named T1 and T2:
1215
1216     Method (ABCD, 1)
1217     {
1218     }
1219     Method (EFGH, 0)
1220     {
1221     }
1222     Method (T1)
1223     {
1224         ABCD (Add (2, 7, Local0))
1225     }
1226     Method (T2)
1227     {
1228         EFGH ()
1229         Add (2, 7, Local0)
1230     }
1231
1232 Here is the AML code that is generated for T1 and T2:
1233
1234      185:      Method (T1)
1235
1236 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1237
1238      186:      {
1239      187:          ABCD (Add (2, 7, Local0))
1240
1241 00000353:  41 42 43 44 ............    "ABCD"
1242 00000357:  72 0A 02 0A 07 60 ......    "r....`"
1243
1244      188:      }
1245
1246      190:      Method (T2)
1247
1248 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1249
1250      191:      {
1251      192:          EFGH ()
1252
1253 00000364:  45 46 47 48 ............    "EFGH"
1254
1255      193:          Add (2, 7, Local0)
1256
1257 00000368:  72 0A 02 0A 07 60 ......    "r....`"
1258      194:      }
1259
1260 Note that the AML code for T1 and T2 is essentially identical. When
1261 disassembling this code, the methods ABCD and EFGH must be known to the
1262 disassembler, otherwise it does not know how to handle the method invocations.
1263
1264 In other words, if ABCD and EFGH are actually external control methods
1265 appearing in an SSDT, the disassembler does not know what to do unless
1266 the owning SSDT has been loaded via the -e option.
1267 #endif
1268
1269 void
1270 AcpiDmUnresolvedWarning (
1271     UINT8                   Type)
1272 {
1273
1274     if (!AcpiGbl_NumExternalMethods)
1275     {
1276         return;
1277     }
1278
1279     if (Type)
1280     {
1281         if (!AcpiGbl_ExternalFileList)
1282         {
1283             /* The -e option was not specified */
1284
1285            AcpiOsPrintf ("    /*\n"
1286                 "     * iASL Warning: There were %u external control methods found during\n"
1287                 "     * disassembly, but additional ACPI tables to resolve these externals\n"
1288                 "     * were not specified. This resulting disassembler output file may not\n"
1289                 "     * compile because the disassembler did not know how many arguments\n"
1290                 "     * to assign to these methods. To specify the tables needed to resolve\n"
1291                 "     * external control method references, the -e option can be used to\n"
1292                 "     * specify the filenames. Note: SSDTs can be dynamically loaded at\n"
1293                 "     * runtime and may or may not be available via the host OS.\n"
1294                 "     * Example iASL invocations:\n"
1295                 "     *     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1296                 "     *     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1297                 "     *     iasl -e ssdt*.aml -d dsdt.aml\n"
1298                 "     *\n"
1299                 "     * In addition, the -fe option can be used to specify a file containing\n"
1300                 "     * control method external declarations with the associated method\n"
1301                 "     * argument counts. Each line of the file must be of the form:\n"
1302                 "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1303                 "     * Invocation:\n"
1304                 "     *     iasl -fe refs.txt -d dsdt.aml\n"
1305                 "     *\n"
1306                 "     * The following methods were unresolved and many not compile properly\n"
1307                 "     * because the disassembler had to guess at the number of arguments\n"
1308                 "     * required for each:\n"
1309                 "     */\n",
1310                AcpiGbl_NumExternalMethods);
1311         }
1312         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1313         {
1314             /* The -e option was specified, but there are still some unresolved externals */
1315
1316             AcpiOsPrintf ("    /*\n"
1317                 "     * iASL Warning: There were %u external control methods found during\n"
1318                 "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1319                 "     * ACPI tables may be required to properly disassemble the code. This\n"
1320                 "     * resulting disassembler output file may not compile because the\n"
1321                 "     * disassembler did not know how many arguments to assign to the\n"
1322                 "     * unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1323                 "     * runtime and may or may not be available via the host OS.\n"
1324                 "     *\n"
1325                 "     * If necessary, the -fe option can be used to specify a file containing\n"
1326                 "     * control method external declarations with the associated method\n"
1327                 "     * argument counts. Each line of the file must be of the form:\n"
1328                 "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1329                 "     * Invocation:\n"
1330                 "     *     iasl -fe refs.txt -d dsdt.aml\n"
1331                 "     *\n"
1332                 "     * The following methods were unresolved and many not compile properly\n"
1333                 "     * because the disassembler had to guess at the number of arguments\n"
1334                 "     * required for each:\n"
1335                 "     */\n",
1336                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1337                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1338                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1339         }
1340     }
1341     else
1342     {
1343         if (!AcpiGbl_ExternalFileList)
1344         {
1345             /* The -e option was not specified */
1346
1347             fprintf (stderr, "\n"
1348                 "iASL Warning: There were %u external control methods found during\n"
1349                 "disassembly, but additional ACPI tables to resolve these externals\n"
1350                 "were not specified. The resulting disassembler output file may not\n"
1351                 "compile because the disassembler did not know how many arguments\n"
1352                 "to assign to these methods. To specify the tables needed to resolve\n"
1353                 "external control method references, the -e option can be used to\n"
1354                 "specify the filenames. Note: SSDTs can be dynamically loaded at\n"
1355                 "runtime and may or may not be available via the host OS.\n"
1356                 "Example iASL invocations:\n"
1357                 "    iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1358                 "    iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1359                 "    iasl -e ssdt*.aml -d dsdt.aml\n"
1360                 "\n"
1361                 "In addition, the -fe option can be used to specify a file containing\n"
1362                 "control method external declarations with the associated method\n"
1363                 "argument counts. Each line of the file must be of the form:\n"
1364                 "    External (<method pathname>, MethodObj, <argument count>)\n"
1365                 "Invocation:\n"
1366                 "    iasl -fe refs.txt -d dsdt.aml\n",
1367                 AcpiGbl_NumExternalMethods);
1368         }
1369         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1370         {
1371             /* The -e option was specified, but there are still some unresolved externals */
1372
1373             fprintf (stderr, "\n"
1374                 "iASL Warning: There were %u external control methods found during\n"
1375                 "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1376                 "ACPI tables may be required to properly disassemble the code. The\n"
1377                 "resulting disassembler output file may not compile because the\n"
1378                 "disassembler did not know how many arguments to assign to the\n"
1379                 "unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1380                 "runtime and may or may not be available via the host OS.\n"
1381                 "\n"
1382                 "If necessary, the -fe option can be used to specify a file containing\n"
1383                 "control method external declarations with the associated method\n"
1384                 "argument counts. Each line of the file must be of the form:\n"
1385                 "    External (<method pathname>, MethodObj, <argument count>)\n"
1386                 "Invocation:\n"
1387                 "    iasl -fe refs.txt -d dsdt.aml\n",
1388                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1389                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1390                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1391         }
1392     }
1393 }