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 | |
13 | fd_t mem_fd = 0; |
14 | |
15 | int 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 | |