1 | #include <uacpi/platform/atomic.h> |
2 | #include <uacpi/internal/osi.h> |
3 | #include <uacpi/internal/helpers.h> |
4 | #include <uacpi/internal/stdlib.h> |
5 | #include <uacpi/internal/utilities.h> |
6 | #include <uacpi/kernel_api.h> |
7 | |
8 | struct registered_interface { |
9 | const uacpi_char *name; |
10 | uacpi_u8 weight; |
11 | uacpi_u8 kind; |
12 | |
13 | // Only applicable for predefined host interfaces |
14 | uacpi_u8 host_type; |
15 | |
16 | // Only applicable for predefined interfaces |
17 | uacpi_u8 disabled : 1; |
18 | uacpi_u8 dynamic : 1; |
19 | |
20 | struct registered_interface *next; |
21 | }; |
22 | |
23 | static uacpi_handle interface_mutex; |
24 | static struct registered_interface *registered_interfaces; |
25 | static uacpi_interface_handler interface_handler; |
26 | static uacpi_u32 latest_queried_interface; |
27 | |
28 | #define WINDOWS(string, interface) \ |
29 | { \ |
30 | .name = "Windows "string, \ |
31 | .weight = UACPI_VENDOR_INTERFACE_WINDOWS_##interface, \ |
32 | .kind = UACPI_INTERFACE_KIND_VENDOR, \ |
33 | .host_type = 0, \ |
34 | .disabled = 0, \ |
35 | .dynamic = 0, \ |
36 | .next = UACPI_NULL \ |
37 | } |
38 | |
39 | #define HOST_FEATURE(string, type) \ |
40 | { \ |
41 | .name = string, \ |
42 | .weight = 0, \ |
43 | .kind = UACPI_INTERFACE_KIND_FEATURE, \ |
44 | .host_type = UACPI_HOST_INTERFACE_##type, \ |
45 | .disabled = 1, \ |
46 | .dynamic = 0, \ |
47 | .next = UACPI_NULL, \ |
48 | } |
49 | |
50 | static struct registered_interface predefined_interfaces[] = { |
51 | // Vendor strings |
52 | WINDOWS("2000" , 2000), |
53 | WINDOWS("2001" , XP), |
54 | WINDOWS("2001 SP1" , XP_SP1), |
55 | WINDOWS("2001.1" , SERVER_2003), |
56 | WINDOWS("2001 SP2" , XP_SP2), |
57 | WINDOWS("2001.1 SP1" , SERVER_2003_SP1), |
58 | WINDOWS("2006" , VISTA), |
59 | WINDOWS("2006.1" , SERVER_2008), |
60 | WINDOWS("2006 SP1" , VISTA_SP1), |
61 | WINDOWS("2006 SP2" , VISTA_SP2), |
62 | WINDOWS("2009" , 7), |
63 | WINDOWS("2012" , 8), |
64 | WINDOWS("2013" , 8_1), |
65 | WINDOWS("2015" , 10), |
66 | WINDOWS("2016" , 10_RS1), |
67 | WINDOWS("2017" , 10_RS2), |
68 | WINDOWS("2017.2" , 10_RS3), |
69 | WINDOWS("2018" , 10_RS4), |
70 | WINDOWS("2018.2" , 10_RS5), |
71 | WINDOWS("2019" , 10_19H1), |
72 | WINDOWS("2020" , 10_20H1), |
73 | WINDOWS("2021" , 11), |
74 | WINDOWS("2022" , 11_22H2), |
75 | |
76 | // Feature strings |
77 | HOST_FEATURE("Module Device" , MODULE_DEVICE), |
78 | HOST_FEATURE("Processor Device" , PROCESSOR_DEVICE), |
79 | HOST_FEATURE("3.0 Thermal Model" , 3_0_THERMAL_MODEL), |
80 | HOST_FEATURE("3.0 _SCP Extensions" , 3_0_SCP_EXTENSIONS), |
81 | HOST_FEATURE("Processor Aggregator Device" , PROCESSOR_AGGREGATOR_DEVICE), |
82 | |
83 | // Interpreter features |
84 | { .name = "Extended Address Space Descriptor" }, |
85 | }; |
86 | |
87 | uacpi_status uacpi_initialize_interfaces(void) |
88 | { |
89 | uacpi_size i; |
90 | |
91 | registered_interfaces = &predefined_interfaces[0]; |
92 | |
93 | interface_mutex = uacpi_kernel_create_mutex(); |
94 | if (uacpi_unlikely(interface_mutex == UACPI_NULL)) |
95 | return UACPI_STATUS_OUT_OF_MEMORY; |
96 | |
97 | for (i = 0; i < (UACPI_ARRAY_SIZE(predefined_interfaces) - 1); ++i) |
98 | predefined_interfaces[i].next = &predefined_interfaces[i + 1]; |
99 | |
100 | return UACPI_STATUS_OK; |
101 | } |
102 | |
103 | uacpi_vendor_interface uacpi_latest_queried_vendor_interface(void) |
104 | { |
105 | return uacpi_atomic_load32(&latest_queried_interface); |
106 | } |
107 | |
108 | static struct registered_interface *find_interface_unlocked( |
109 | const uacpi_char *name |
110 | ) |
111 | { |
112 | struct registered_interface *interface = registered_interfaces; |
113 | |
114 | while (interface) { |
115 | if (uacpi_strcmp(lhs: interface->name, rhs: name) == 0) |
116 | return interface; |
117 | |
118 | interface = interface->next; |
119 | } |
120 | |
121 | return UACPI_NULL; |
122 | } |
123 | |
124 | static struct registered_interface *find_host_interface_unlocked( |
125 | uacpi_host_interface type |
126 | ) |
127 | { |
128 | struct registered_interface *interface = registered_interfaces; |
129 | |
130 | while (interface) { |
131 | if (interface->host_type == type) |
132 | return interface; |
133 | |
134 | interface = interface->next; |
135 | } |
136 | |
137 | return UACPI_NULL; |
138 | } |
139 | |
140 | uacpi_status uacpi_install_interface( |
141 | const uacpi_char *name, uacpi_interface_kind kind |
142 | ) |
143 | { |
144 | struct registered_interface *interface; |
145 | uacpi_status ret = UACPI_STATUS_ALREADY_EXISTS; |
146 | uacpi_char *name_copy; |
147 | uacpi_size name_size; |
148 | |
149 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED); |
150 | |
151 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
152 | |
153 | interface = find_interface_unlocked(name); |
154 | if (interface != UACPI_NULL) { |
155 | if (interface->disabled) { |
156 | interface->disabled = UACPI_FALSE; |
157 | ret = UACPI_STATUS_OK; |
158 | } |
159 | goto out; |
160 | } |
161 | |
162 | interface = uacpi_kernel_alloc(size: sizeof(*interface)); |
163 | if (uacpi_unlikely(interface == UACPI_NULL)) { |
164 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
165 | goto out; |
166 | } |
167 | |
168 | name_size = uacpi_strlen(str: name) + 1; |
169 | name_copy = uacpi_kernel_alloc(size: name_size); |
170 | if (uacpi_unlikely(name_copy == UACPI_NULL)) { |
171 | uacpi_free(interface, sizeof(*interface)); |
172 | ret = UACPI_STATUS_OUT_OF_MEMORY; |
173 | goto out; |
174 | } |
175 | |
176 | uacpi_memcpy(dest: name_copy, src: name, count: name_size); |
177 | interface->name = name_copy; |
178 | interface->weight = 0; |
179 | interface->kind = kind; |
180 | interface->host_type = 0; |
181 | interface->disabled = 0; |
182 | interface->dynamic = 1; |
183 | interface->next = registered_interfaces; |
184 | registered_interfaces = interface; |
185 | ret = UACPI_STATUS_OK; |
186 | |
187 | out: |
188 | UACPI_MUTEX_RELEASE(interface_mutex); |
189 | return ret; |
190 | } |
191 | |
192 | uacpi_status uacpi_uninstall_interface(const uacpi_char *name) |
193 | { |
194 | struct registered_interface *cur, *prev; |
195 | uacpi_status ret = UACPI_STATUS_NOT_FOUND; |
196 | |
197 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED); |
198 | |
199 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
200 | |
201 | cur = registered_interfaces; |
202 | prev = cur; |
203 | |
204 | while (cur) { |
205 | if (uacpi_strcmp(lhs: cur->name, rhs: name) != 0) { |
206 | prev = cur; |
207 | cur = cur->next; |
208 | continue; |
209 | } |
210 | |
211 | if (cur->dynamic) { |
212 | if (prev == cur) { |
213 | registered_interfaces = cur->next; |
214 | } else { |
215 | prev->next = cur->next; |
216 | } |
217 | |
218 | UACPI_MUTEX_RELEASE(interface_mutex); |
219 | uacpi_free_dynamic_string(str: cur->name); |
220 | uacpi_free(cur, sizeof(*cur)); |
221 | return UACPI_STATUS_OK; |
222 | } |
223 | |
224 | /* |
225 | * If this interface was already disabled, pretend we didn't actually |
226 | * find it and keep ret as UACPI_STATUS_NOT_FOUND. The fact that it's |
227 | * still in the registered list is an implementation detail of |
228 | * predefined interfaces. |
229 | */ |
230 | if (!cur->disabled) { |
231 | cur->disabled = UACPI_TRUE; |
232 | ret = UACPI_STATUS_OK; |
233 | } |
234 | |
235 | break; |
236 | } |
237 | |
238 | UACPI_MUTEX_RELEASE(interface_mutex); |
239 | return ret; |
240 | } |
241 | |
242 | static uacpi_status configure_host_interface( |
243 | uacpi_host_interface type, uacpi_bool enabled |
244 | ) |
245 | { |
246 | struct registered_interface *interface; |
247 | uacpi_status ret = UACPI_STATUS_NOT_FOUND; |
248 | |
249 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED); |
250 | |
251 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
252 | |
253 | interface = find_host_interface_unlocked(type); |
254 | if (interface == UACPI_NULL) |
255 | goto out; |
256 | |
257 | interface->disabled = !enabled; |
258 | ret = UACPI_STATUS_OK; |
259 | |
260 | out: |
261 | UACPI_MUTEX_RELEASE(interface_mutex); |
262 | return ret; |
263 | } |
264 | |
265 | uacpi_status uacpi_enable_host_interface(uacpi_host_interface type) |
266 | { |
267 | return configure_host_interface(type, UACPI_TRUE); |
268 | } |
269 | |
270 | uacpi_status uacpi_disable_host_interface(uacpi_host_interface type) |
271 | { |
272 | return configure_host_interface(type, UACPI_FALSE); |
273 | } |
274 | |
275 | uacpi_status uacpi_set_interface_query_handler( |
276 | uacpi_interface_handler handler |
277 | ) |
278 | { |
279 | uacpi_status ret = UACPI_STATUS_ALREADY_EXISTS; |
280 | |
281 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED); |
282 | |
283 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
284 | |
285 | if (interface_handler != UACPI_NULL && handler != UACPI_NULL) |
286 | goto out; |
287 | |
288 | interface_handler = handler; |
289 | ret = UACPI_STATUS_OK; |
290 | |
291 | out: |
292 | UACPI_MUTEX_RELEASE(interface_mutex); |
293 | return ret; |
294 | } |
295 | |
296 | uacpi_status uacpi_bulk_configure_interfaces( |
297 | uacpi_interface_action action, uacpi_interface_kind kind |
298 | ) |
299 | { |
300 | struct registered_interface *interface; |
301 | |
302 | UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_TABLES_LOADED); |
303 | |
304 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
305 | |
306 | interface = registered_interfaces; |
307 | while (interface) { |
308 | if (kind & interface->kind) |
309 | interface->disabled = (action == UACPI_INTERFACE_ACTION_DISABLE); |
310 | |
311 | interface = interface->next; |
312 | } |
313 | |
314 | UACPI_MUTEX_RELEASE(interface_mutex); |
315 | return UACPI_STATUS_OK; |
316 | } |
317 | |
318 | uacpi_status uacpi_handle_osi(const uacpi_char *string, uacpi_bool *out_value) |
319 | { |
320 | struct registered_interface *interface; |
321 | uacpi_bool is_supported = UACPI_FALSE; |
322 | |
323 | UACPI_MUTEX_ACQUIRE(interface_mutex); |
324 | |
325 | interface = find_interface_unlocked(name: string); |
326 | if (interface == UACPI_NULL) |
327 | goto out; |
328 | |
329 | if (interface->weight > latest_queried_interface) |
330 | uacpi_atomic_store32(&latest_queried_interface, interface->weight); |
331 | |
332 | is_supported = !interface->disabled; |
333 | if (interface_handler) |
334 | is_supported = interface_handler(string, is_supported); |
335 | out: |
336 | UACPI_MUTEX_RELEASE(interface_mutex); |
337 | *out_value = is_supported; |
338 | return UACPI_STATUS_OK; |
339 | } |
340 | |