1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "uacpi/event.h"
4#include "uacpi/namespace.h"
5#include "uacpi/uacpi.h"
6#include "uacpi/utilities.h"
7
8#include <fcntl.h>
9#include <iostream>
10#include <mos/mos_global.h>
11#include <mos/syscall/usermode.h>
12
13fd_t mem_fd = 0;
14
15int main(int argc, const char *argv[])
16{
17 std::cout << "ACPI Daemon for MOS" << std::endl;
18
19 syscall_arch_syscall(nr: X86_SYSCALL_IOPL_ENABLE, arg1: 0, arg2: 0, arg3: 0, arg4: 0);
20
21 mem_fd = open(path: "/sys/mem", O_RDWR);
22
23 uacpi_phys_addr rsdp_phys_addr = MOS_FOURCC('R', 'S', 'D', 'P');
24
25 /*
26 * Set up the initialization parameters structure that configures uACPI
27 * behavior both at bring up and during runtime.
28 */
29 uacpi_init_params init_params = {
30 /*
31 * Physical address of the RSDP structure that we have either found
32 * ourselves manually by scanning memory or (ideally) provided to us by
33 * the bootloader.
34 */
35 .rsdp = rsdp_phys_addr,
36
37 /*
38 * Set the log level to TRACE, this is a bit verbose but perhaps
39 * okay for now since we're just getting started. We can change this
40 * to INFO later on, which is the recommended level for release
41 * builds. There's also the loudest UACPI_LOG_DEBUG log level, which
42 * is recommended to pin down lockups or hangs.
43 */
44 .log_level = UACPI_LOG_TRACE,
45
46 /*
47 * Don't set any behavior flags, the defaults should work on most
48 * hardware.
49 */
50 .flags = 0,
51 };
52
53 /*
54 * Proceed to the first step of the initialization. This loads all tables,
55 * brings the event subsystem online, and enters ACPI mode.
56 */
57 uacpi_status ret = uacpi_initialize(&init_params);
58 if (uacpi_unlikely_error(ret))
59 {
60 std::cerr << "uacpi_initialize error: " << uacpi_status_to_string(ret) << std::endl;
61 return -ENODEV;
62 }
63
64 /*
65 * Load the AML namespace. This feeds DSDT and all SSDTs to the interpreter
66 * for execution.
67 */
68 ret = uacpi_namespace_load();
69 if (uacpi_unlikely_error(ret))
70 {
71 std::cerr << "uacpi_namespace_load error: " << uacpi_status_to_string(ret) << std::endl;
72 return -ENODEV;
73 }
74
75 /*
76 * Initialize the namespace. This calls all necessary _STA/_INI AML methods,
77 * as well as _REG for registered operation region handlers.
78 */
79 ret = uacpi_namespace_initialize();
80 if (uacpi_unlikely_error(ret))
81 {
82 std::cerr << "uacpi_namespace_initialize error: %s" << uacpi_status_to_string(ret) << std::endl;
83 return -ENODEV;
84 }
85
86 /*
87 * Tell uACPI that we have marked all GPEs we wanted for wake (even though we haven't
88 * actually marked any, as we have no power management support right now). This is
89 * needed to let uACPI enable all unmarked GPEs that have a corresponding AML handler.
90 * These handlers are used by the firmware to dynamically execute AML code at runtime
91 * to e.g. react to thermal events or device hotplug.
92 */
93 ret = uacpi_finalize_gpe_initialization();
94 if (uacpi_unlikely_error(ret))
95 {
96 std::cerr << "uACPI GPE initialization error: " << uacpi_status_to_string(ret) << std::endl;
97 return -ENODEV;
98 }
99
100 /*
101 * That's it, uACPI is now fully initialized and working! You can proceed to
102 * using any public API at your discretion. The next recommended step is namespace
103 * enumeration and device discovery so you can bind drivers to ACPI objects.
104 */
105
106 const auto acpi_init_one_device = [](void *user, uacpi_namespace_node *node) -> uacpi_ns_iteration_decision
107 {
108 uacpi_namespace_node_info *info;
109
110 uacpi_status ret = uacpi_get_namespace_node_info(node, out_info: &info);
111
112 if (uacpi_unlikely_error(ret))
113 {
114 const char *path = uacpi_namespace_node_generate_absolute_path(node);
115 std::cerr << "unable to retrieve node " << path << ", " << uacpi_status_to_string(ret) << std::endl;
116 uacpi_free_absolute_path(path);
117 return UACPI_NS_ITERATION_DECISION_CONTINUE;
118 }
119
120 if (info->type != UACPI_OBJECT_DEVICE)
121 {
122 // We probably don't care about anything but devices at this point
123 uacpi_free_namespace_node_info(info);
124 return UACPI_NS_ITERATION_DECISION_CONTINUE;
125 }
126
127 if (info->flags & UACPI_NS_NODE_INFO_HAS_HID)
128 {
129 // Match the HID against every existing acpi_driver pnp id list
130 std::cout << "HID: " << info->hid.value << std::endl;
131 }
132
133 if (info->flags & UACPI_NS_NODE_INFO_HAS_CID)
134 {
135 // Match the CID list against every existing acpi_driver pnp id list
136 for (uacpi_u32 i = 0; i < info->cid.num_ids; i++)
137 {
138 std::cout << "CID: " << info->cid.ids[i].value << std::endl;
139 }
140 }
141
142 uacpi_free_namespace_node_info(info);
143
144 return UACPI_NS_ITERATION_DECISION_CONTINUE;
145 };
146
147 uacpi_namespace_for_each_node_depth_first(parent: uacpi_namespace_root(), callback: acpi_init_one_device, UACPI_NULL);
148
149 while (true)
150 ;
151
152 return 0;
153}
154