1/******************************************************************************
2 *
3 * Module Name: examples - Example ACPICA initialization and execution code
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 "examples.h"
45
46#define _COMPONENT          ACPI_EXAMPLE
47        ACPI_MODULE_NAME    ("examples")
48
49
50/******************************************************************************
51 *
52 * ACPICA Example Code
53 *
54 * This module contains examples of how the host OS should interface to the
55 * ACPICA subsystem.
56 *
57 * 1) How to use the platform/acenv.h file and how to set configuration
58 *      options.
59 *
60 * 2) main - using the debug output mechanism and the error/warning output
61 *      macros.
62 *
63 * 3) Two examples of the ACPICA initialization sequence. The first is a
64 *      initialization with no "early" ACPI table access. The second shows
65 *      how to use ACPICA to obtain the tables very early during kernel
66 *      initialization, even before dynamic memory is available.
67 *
68 * 4) How to invoke a control method, including argument setup and how to
69 *      access the return value.
70 *
71 *****************************************************************************/
72
73
74/* Local Prototypes */
75
76static ACPI_STATUS
77InitializeFullAcpica (void);
78
79static ACPI_STATUS
80InstallHandlers (void);
81
82static void
83NotifyHandler (
84    ACPI_HANDLE             Device,
85    UINT32                  Value,
86    void                    *Context);
87
88static ACPI_STATUS
89RegionHandler (
90    UINT32                  Function,
91    ACPI_PHYSICAL_ADDRESS   Address,
92    UINT32                  BitWidth,
93    UINT64                  *Value,
94    void                    *HandlerContext,
95    void                    *RegionContext);
96
97static ACPI_STATUS
98RegionInit (
99    ACPI_HANDLE             RegionHandle,
100    UINT32                  Function,
101    void                    *HandlerContext,
102    void                    **RegionContext);
103
104static void
105ExecuteMAIN (void);
106
107ACPI_STATUS
108InitializeAcpiTables (
109    void);
110
111ACPI_STATUS
112InitializeAcpi (
113    void);
114
115
116/******************************************************************************
117 *
118 * FUNCTION:    main
119 *
120 * PARAMETERS:  argc, argv
121 *
122 * RETURN:      Status
123 *
124 * DESCRIPTION: Main routine. Shows the use of the various output macros, as
125 *              well as the use of the debug layer/level globals.
126 *
127 *****************************************************************************/
128
129int ACPI_SYSTEM_XFACE
130main (
131    int                     argc,
132    char                    **argv)
133{
134
135    ACPI_DEBUG_INITIALIZE (); /* For debug version only */
136
137    printf (ACPI_COMMON_SIGNON ("ACPI Example Code"));
138
139    /* Initialize the local ACPI tables (RSDP/RSDT/XSDT/FADT/DSDT/FACS) */
140
141    ExInitializeAcpiTables ();
142
143    /* Initialize the ACPICA subsystem */
144
145    InitializeFullAcpica ();
146
147    /* Example warning and error output */
148
149    ACPI_INFO        (("Example ACPICA info message"));
150    ACPI_WARNING     ((AE_INFO, "Example ACPICA warning message"));
151    ACPI_ERROR       ((AE_INFO, "Example ACPICA error message"));
152    ACPI_EXCEPTION   ((AE_INFO, AE_AML_OPERAND_TYPE,
153        "Example ACPICA exception message"));
154
155    ExecuteOSI (NULL, 0);
156    ExecuteMAIN ();
157    return (0);
158}
159
160
161/******************************************************************************
162 *
163 * Example ACPICA initialization code. This shows a full initialization with
164 * no early ACPI table access.
165 *
166 *****************************************************************************/
167
168static ACPI_STATUS
169InitializeFullAcpica (void)
170{
171    ACPI_STATUS             Status;
172
173
174    /* Initialize the ACPICA subsystem */
175
176    Status = AcpiInitializeSubsystem ();
177    if (ACPI_FAILURE (Status))
178    {
179        ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA"));
180        return (Status);
181    }
182
183    /* Initialize the ACPICA Table Manager and get all ACPI tables */
184
185    ACPI_INFO (("Loading ACPI tables"));
186
187    Status = AcpiInitializeTables (NULL, 16, FALSE);
188    if (ACPI_FAILURE (Status))
189    {
190        ACPI_EXCEPTION ((AE_INFO, Status, "While initializing Table Manager"));
191        return (Status);
192    }
193
194    /* Install local handlers */
195
196    Status = InstallHandlers ();
197    if (ACPI_FAILURE (Status))
198    {
199        ACPI_EXCEPTION ((AE_INFO, Status, "While installing handlers"));
200        return (Status);
201    }
202
203    /* Initialize the ACPI hardware */
204
205    Status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
206    if (ACPI_FAILURE (Status))
207    {
208        ACPI_EXCEPTION ((AE_INFO, Status, "While enabling ACPICA"));
209        return (Status);
210    }
211
212    /* Create the ACPI namespace from ACPI tables */
213
214    Status = AcpiLoadTables ();
215    if (ACPI_FAILURE (Status))
216    {
217        ACPI_EXCEPTION ((AE_INFO, Status, "While loading ACPI tables"));
218        return (Status);
219    }
220
221    /* Complete the ACPI namespace object initialization */
222
223    Status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
224    if (ACPI_FAILURE (Status))
225    {
226        ACPI_EXCEPTION ((AE_INFO, Status, "While initializing ACPICA objects"));
227        return (Status);
228    }
229
230    return (AE_OK);
231}
232
233
234/******************************************************************************
235 *
236 * Example ACPICA initialization code with early ACPI table access. This shows
237 * an initialization that requires early access to ACPI tables (before
238 * kernel dynamic memory is available)
239 *
240 *****************************************************************************/
241
242/*
243 * The purpose of this static table array is to avoid the use of kernel
244 * dynamic memory which may not be available during early ACPI table
245 * access.
246 */
247#define ACPI_MAX_INIT_TABLES    16
248static ACPI_TABLE_DESC      TableArray[ACPI_MAX_INIT_TABLES];
249
250
251/*
252 * This function would be called early in kernel initialization. After this
253 * is called, all ACPI tables are available to the host.
254 */
255ACPI_STATUS
256InitializeAcpiTables (
257    void)
258{
259    ACPI_STATUS             Status;
260
261
262    /* Initialize the ACPICA Table Manager and get all ACPI tables */
263
264    Status = AcpiInitializeTables (TableArray, ACPI_MAX_INIT_TABLES, TRUE);
265    return (Status);
266}
267
268
269/*
270 * This function would be called after the kernel is initialized and
271 * dynamic/virtual memory is available. It completes the initialization of
272 * the ACPICA subsystem.
273 */
274ACPI_STATUS
275InitializeAcpi (
276    void)
277{
278    ACPI_STATUS             Status;
279
280
281    /* Initialize the ACPICA subsystem */
282
283    Status = AcpiInitializeSubsystem ();
284    if (ACPI_FAILURE (Status))
285    {
286        return (Status);
287    }
288
289    /* Copy the root table list to dynamic memory */
290
291    Status = AcpiReallocateRootTable ();
292    if (ACPI_FAILURE (Status))
293    {
294        return (Status);
295    }
296
297    /* Install local handlers */
298
299    Status = InstallHandlers ();
300    if (ACPI_FAILURE (Status))
301    {
302        ACPI_EXCEPTION ((AE_INFO, Status, "While installing handlers"));
303        return (Status);
304    }
305
306    /* Initialize the ACPI hardware */
307
308    Status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
309    if (ACPI_FAILURE (Status))
310    {
311        return (Status);
312    }
313
314    /* Create the ACPI namespace from ACPI tables */
315
316    Status = AcpiLoadTables ();
317    if (ACPI_FAILURE (Status))
318    {
319        return (Status);
320    }
321
322    /* Complete the ACPI namespace object initialization */
323
324    Status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
325    if (ACPI_FAILURE (Status))
326    {
327        return (Status);
328    }
329
330    return (AE_OK);
331}
332
333
334/******************************************************************************
335 *
336 * Example ACPICA handler and handler installation
337 *
338 *****************************************************************************/
339
340static void
341NotifyHandler (
342    ACPI_HANDLE                 Device,
343    UINT32                      Value,
344    void                        *Context)
345{
346
347    ACPI_INFO (("Received a notify 0x%X", Value));
348}
349
350
351static ACPI_STATUS
352RegionInit (
353    ACPI_HANDLE                 RegionHandle,
354    UINT32                      Function,
355    void                        *HandlerContext,
356    void                        **RegionContext)
357{
358
359    if (Function == ACPI_REGION_DEACTIVATE)
360    {
361        *RegionContext = NULL;
362    }
363    else
364    {
365        *RegionContext = RegionHandle;
366    }
367
368    return (AE_OK);
369}
370
371
372static ACPI_STATUS
373RegionHandler (
374    UINT32                      Function,
375    ACPI_PHYSICAL_ADDRESS       Address,
376    UINT32                      BitWidth,
377    UINT64                      *Value,
378    void                        *HandlerContext,
379    void                        *RegionContext)
380{
381
382    ACPI_INFO (("Received a region access"));
383
384    return (AE_OK);
385}
386
387
388static ACPI_STATUS
389InstallHandlers (void)
390{
391    ACPI_STATUS             Status;
392
393
394    /* Install global notify handler */
395
396    Status = AcpiInstallNotifyHandler (ACPI_ROOT_OBJECT,
397        ACPI_SYSTEM_NOTIFY, NotifyHandler, NULL);
398    if (ACPI_FAILURE (Status))
399    {
400        ACPI_EXCEPTION ((AE_INFO, Status, "While installing Notify handler"));
401        return (Status);
402    }
403
404    Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
405        ACPI_ADR_SPACE_SYSTEM_MEMORY, RegionHandler, RegionInit, NULL);
406    if (ACPI_FAILURE (Status))
407    {
408        ACPI_EXCEPTION ((AE_INFO, Status, "While installing an OpRegion handler"));
409        return (Status);
410    }
411
412    return (AE_OK);
413}
414
415
416/******************************************************************************
417 *
418 * Examples of control method execution.
419 *
420 * _OSI is a predefined method that is implemented internally within ACPICA.
421 *
422 * Shows the following elements:
423 *
424 * 1) How to setup a control method argument and argument list
425 * 2) How to setup the return value object
426 * 3) How to invoke AcpiEvaluateObject
427 * 4) How to check the returned ACPI_STATUS
428 * 5) How to analyze the return value
429 *
430 *****************************************************************************/
431
432ACPI_STATUS
433ExecuteOSI (
434    char                    *OsiString,
435    UINT64                  ExpectedResult)
436{
437    ACPI_STATUS             Status;
438    ACPI_OBJECT_LIST        ArgList;
439    ACPI_OBJECT             Arg[1];
440    ACPI_BUFFER             ReturnValue;
441    ACPI_OBJECT             *Object;
442
443
444    ACPI_INFO (("Executing _OSI reserved method"));
445
446    /* Setup input argument */
447
448    ArgList.Count = 1;
449    ArgList.Pointer = Arg;
450
451    Arg[0].Type = ACPI_TYPE_STRING;
452    Arg[0].String.Pointer = "Windows 2001";
453    Arg[0].String.Length = strlen (Arg[0].String.Pointer);
454
455    /* Ask ACPICA to allocate space for the return object */
456
457    ReturnValue.Length = ACPI_ALLOCATE_BUFFER;
458
459    Status = AcpiEvaluateObject (NULL, "\\_OSI", &ArgList, &ReturnValue);
460    if (ACPI_FAILURE (Status))
461    {
462        ACPI_EXCEPTION ((AE_INFO, Status, "While executing _OSI"));
463        return (AE_OK);
464    }
465
466    /* Ensure that the return object is large enough */
467
468    if (ReturnValue.Length < sizeof (ACPI_OBJECT))
469    {
470        AcpiOsPrintf ("Return value from _OSI method too small, %.8X\n",
471            (UINT32) ReturnValue.Length);
472        goto ErrorExit;
473    }
474
475    /* Expect an integer return value from execution of _OSI */
476
477    Object = ReturnValue.Pointer;
478    if (Object->Type != ACPI_TYPE_INTEGER)
479    {
480        AcpiOsPrintf ("Invalid return type from _OSI, %.2X\n", Object->Type);
481    }
482
483    ACPI_INFO (("_OSI returned 0x%8.8X",
484        (UINT32) Object->Integer.Value));
485
486
487ErrorExit:
488
489    /* Free a buffer created via ACPI_ALLOCATE_BUFFER */
490
491    AcpiOsFree (ReturnValue.Pointer);
492    return (AE_OK);
493}
494
495
496/******************************************************************************
497 *
498 * Execute an actual control method in the DSDT (MAIN)
499 *
500 *****************************************************************************/
501
502static void
503ExecuteMAIN (void)
504{
505    ACPI_STATUS             Status;
506    ACPI_OBJECT_LIST        ArgList;
507    ACPI_OBJECT             Arg[1];
508    ACPI_BUFFER             ReturnValue;
509    ACPI_OBJECT             *Object;
510
511
512    ACPI_INFO (("Executing MAIN method"));
513
514    /* Setup input argument */
515
516    ArgList.Count = 1;
517    ArgList.Pointer = Arg;
518
519    Arg[0].Type = ACPI_TYPE_STRING;
520    Arg[0].String.Pointer = "Method [MAIN] is executing";
521    Arg[0].String.Length = strlen (Arg[0].String.Pointer);
522
523    /* Ask ACPICA to allocate space for the return object */
524
525    ReturnValue.Length = ACPI_ALLOCATE_BUFFER;
526
527    Status = AcpiEvaluateObject (NULL, "\\MAIN", &ArgList, &ReturnValue);
528    if (ACPI_FAILURE (Status))
529    {
530        ACPI_EXCEPTION ((AE_INFO, Status, "While executing MAIN"));
531        return;
532    }
533
534    if (ReturnValue.Pointer)
535    {
536        /* Obtain and validate the returned ACPI_OBJECT */
537
538        Object = ReturnValue.Pointer;
539        if (Object->Type == ACPI_TYPE_STRING)
540        {
541            AcpiOsPrintf ("Method [MAIN] returned: \"%s\"\n",
542                Object->String.Pointer);
543        }
544
545        ACPI_FREE (ReturnValue.Pointer);
546    }
547}
548