1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: utxface - External interfaces, miscellaneous utility functions
5 *
6 * Copyright (C) 2000 - 2023, Intel Corp.
7 *
8 *****************************************************************************/
9
10#define EXPORT_ACPI_INTERFACES
11
12#include <acpi/acpi.h>
13#include "accommon.h"
14#include "acdebug.h"
15
16#define _COMPONENT          ACPI_UTILITIES
17ACPI_MODULE_NAME("utxface")
18
19/*******************************************************************************
20 *
21 * FUNCTION:    acpi_terminate
22 *
23 * PARAMETERS:  None
24 *
25 * RETURN:      Status
26 *
27 * DESCRIPTION: Shutdown the ACPICA subsystem and release all resources.
28 *
29 ******************************************************************************/
30acpi_status ACPI_INIT_FUNCTION acpi_terminate(void)
31{
32	acpi_status status;
33
34	ACPI_FUNCTION_TRACE(acpi_terminate);
35
36	/* Shutdown and free all resources */
37
38	acpi_ut_subsystem_shutdown();
39
40	/* Free the mutex objects */
41
42	acpi_ut_mutex_terminate();
43
44	/* Now we can shutdown the OS-dependent layer */
45
46	status = acpi_os_terminate();
47	return_ACPI_STATUS(status);
48}
49
50ACPI_EXPORT_SYMBOL_INIT(acpi_terminate)
51
52#ifndef ACPI_ASL_COMPILER
53#ifdef ACPI_FUTURE_USAGE
54/*******************************************************************************
55 *
56 * FUNCTION:    acpi_subsystem_status
57 *
58 * PARAMETERS:  None
59 *
60 * RETURN:      Status of the ACPI subsystem
61 *
62 * DESCRIPTION: Other drivers that use the ACPI subsystem should call this
63 *              before making any other calls, to ensure the subsystem
64 *              initialized successfully.
65 *
66 ******************************************************************************/
67acpi_status acpi_subsystem_status(void)
68{
69
70	if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) {
71		return (AE_OK);
72	} else {
73		return (AE_ERROR);
74	}
75}
76
77ACPI_EXPORT_SYMBOL(acpi_subsystem_status)
78
79/*******************************************************************************
80 *
81 * FUNCTION:    acpi_get_system_info
82 *
83 * PARAMETERS:  out_buffer      - A buffer to receive the resources for the
84 *                                device
85 *
86 * RETURN:      status          - the status of the call
87 *
88 * DESCRIPTION: This function is called to get information about the current
89 *              state of the ACPI subsystem. It will return system information
90 *              in the out_buffer.
91 *
92 *              If the function fails an appropriate status will be returned
93 *              and the value of out_buffer is undefined.
94 *
95 ******************************************************************************/
96acpi_status acpi_get_system_info(struct acpi_buffer *out_buffer)
97{
98	struct acpi_system_info *info_ptr;
99	acpi_status status;
100
101	ACPI_FUNCTION_TRACE(acpi_get_system_info);
102
103	/* Parameter validation */
104
105	status = acpi_ut_validate_buffer(out_buffer);
106	if (ACPI_FAILURE(status)) {
107		return_ACPI_STATUS(status);
108	}
109
110	/* Validate/Allocate/Clear caller buffer */
111
112	status =
113	    acpi_ut_initialize_buffer(out_buffer,
114				      sizeof(struct acpi_system_info));
115	if (ACPI_FAILURE(status)) {
116		return_ACPI_STATUS(status);
117	}
118
119	/*
120	 * Populate the return buffer
121	 */
122	info_ptr = (struct acpi_system_info *)out_buffer->pointer;
123	info_ptr->acpi_ca_version = ACPI_CA_VERSION;
124
125	/* System flags (ACPI capabilities) */
126
127	info_ptr->flags = ACPI_SYS_MODE_ACPI;
128
129	/* Timer resolution - 24 or 32 bits  */
130
131	if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
132		info_ptr->timer_resolution = 24;
133	} else {
134		info_ptr->timer_resolution = 32;
135	}
136
137	/* Clear the reserved fields */
138
139	info_ptr->reserved1 = 0;
140	info_ptr->reserved2 = 0;
141
142	/* Current debug levels */
143
144	info_ptr->debug_layer = acpi_dbg_layer;
145	info_ptr->debug_level = acpi_dbg_level;
146
147	return_ACPI_STATUS(AE_OK);
148}
149
150ACPI_EXPORT_SYMBOL(acpi_get_system_info)
151
152/*******************************************************************************
153 *
154 * FUNCTION:    acpi_get_statistics
155 *
156 * PARAMETERS:  stats           - Where the statistics are returned
157 *
158 * RETURN:      status          - the status of the call
159 *
160 * DESCRIPTION: Get the contents of the various system counters
161 *
162 ******************************************************************************/
163acpi_status acpi_get_statistics(struct acpi_statistics *stats)
164{
165	ACPI_FUNCTION_TRACE(acpi_get_statistics);
166
167	/* Parameter validation */
168
169	if (!stats) {
170		return_ACPI_STATUS(AE_BAD_PARAMETER);
171	}
172
173	/* Various interrupt-based event counters */
174
175	stats->sci_count = acpi_sci_count;
176	stats->gpe_count = acpi_gpe_count;
177
178	memcpy(stats->fixed_event_count, acpi_fixed_event_count,
179	       sizeof(acpi_fixed_event_count));
180
181	/* Other counters */
182
183	stats->method_count = acpi_method_count;
184	return_ACPI_STATUS(AE_OK);
185}
186
187ACPI_EXPORT_SYMBOL(acpi_get_statistics)
188
189/*****************************************************************************
190 *
191 * FUNCTION:    acpi_install_initialization_handler
192 *
193 * PARAMETERS:  handler             - Callback procedure
194 *              function            - Not (currently) used, see below
195 *
196 * RETURN:      Status
197 *
198 * DESCRIPTION: Install an initialization handler
199 *
200 * TBD: When a second function is added, must save the Function also.
201 *
202 ****************************************************************************/
203acpi_status
204acpi_install_initialization_handler(acpi_init_handler handler, u32 function)
205{
206
207	if (!handler) {
208		return (AE_BAD_PARAMETER);
209	}
210
211	if (acpi_gbl_init_handler) {
212		return (AE_ALREADY_EXISTS);
213	}
214
215	acpi_gbl_init_handler = handler;
216	return (AE_OK);
217}
218
219ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
220#endif
221
222/*****************************************************************************
223 *
224 * FUNCTION:    acpi_purge_cached_objects
225 *
226 * PARAMETERS:  None
227 *
228 * RETURN:      Status
229 *
230 * DESCRIPTION: Empty all caches (delete the cached objects)
231 *
232 ****************************************************************************/
233acpi_status acpi_purge_cached_objects(void)
234{
235	ACPI_FUNCTION_TRACE(acpi_purge_cached_objects);
236
237	(void)acpi_os_purge_cache(acpi_gbl_state_cache);
238	(void)acpi_os_purge_cache(acpi_gbl_operand_cache);
239	(void)acpi_os_purge_cache(acpi_gbl_ps_node_cache);
240	(void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache);
241
242	return_ACPI_STATUS(AE_OK);
243}
244
245ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
246
247/*****************************************************************************
248 *
249 * FUNCTION:    acpi_install_interface
250 *
251 * PARAMETERS:  interface_name      - The interface to install
252 *
253 * RETURN:      Status
254 *
255 * DESCRIPTION: Install an _OSI interface to the global list
256 *
257 ****************************************************************************/
258acpi_status acpi_install_interface(acpi_string interface_name)
259{
260	acpi_status status;
261	struct acpi_interface_info *interface_info;
262
263	/* Parameter validation */
264
265	if (!interface_name || (strlen(interface_name) == 0)) {
266		return (AE_BAD_PARAMETER);
267	}
268
269	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
270	if (ACPI_FAILURE(status)) {
271		return (status);
272	}
273
274	/* Check if the interface name is already in the global list */
275
276	interface_info = acpi_ut_get_interface(interface_name);
277	if (interface_info) {
278		/*
279		 * The interface already exists in the list. This is OK if the
280		 * interface has been marked invalid -- just clear the bit.
281		 */
282		if (interface_info->flags & ACPI_OSI_INVALID) {
283			interface_info->flags &= ~ACPI_OSI_INVALID;
284			status = AE_OK;
285		} else {
286			status = AE_ALREADY_EXISTS;
287		}
288	} else {
289		/* New interface name, install into the global list */
290
291		status = acpi_ut_install_interface(interface_name);
292	}
293
294	acpi_os_release_mutex(acpi_gbl_osi_mutex);
295	return (status);
296}
297
298ACPI_EXPORT_SYMBOL(acpi_install_interface)
299
300/*****************************************************************************
301 *
302 * FUNCTION:    acpi_remove_interface
303 *
304 * PARAMETERS:  interface_name      - The interface to remove
305 *
306 * RETURN:      Status
307 *
308 * DESCRIPTION: Remove an _OSI interface from the global list
309 *
310 ****************************************************************************/
311acpi_status acpi_remove_interface(acpi_string interface_name)
312{
313	acpi_status status;
314
315	/* Parameter validation */
316
317	if (!interface_name || (strlen(interface_name) == 0)) {
318		return (AE_BAD_PARAMETER);
319	}
320
321	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
322	if (ACPI_FAILURE(status)) {
323		return (status);
324	}
325
326	status = acpi_ut_remove_interface(interface_name);
327
328	acpi_os_release_mutex(acpi_gbl_osi_mutex);
329	return (status);
330}
331
332ACPI_EXPORT_SYMBOL(acpi_remove_interface)
333
334/*****************************************************************************
335 *
336 * FUNCTION:    acpi_install_interface_handler
337 *
338 * PARAMETERS:  handler             - The _OSI interface handler to install
339 *                                    NULL means "remove existing handler"
340 *
341 * RETURN:      Status
342 *
343 * DESCRIPTION: Install a handler for the predefined _OSI ACPI method.
344 *              invoked during execution of the internal implementation of
345 *              _OSI. A NULL handler simply removes any existing handler.
346 *
347 ****************************************************************************/
348acpi_status acpi_install_interface_handler(acpi_interface_handler handler)
349{
350	acpi_status status;
351
352	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
353	if (ACPI_FAILURE(status)) {
354		return (status);
355	}
356
357	if (handler && acpi_gbl_interface_handler) {
358		status = AE_ALREADY_EXISTS;
359	} else {
360		acpi_gbl_interface_handler = handler;
361	}
362
363	acpi_os_release_mutex(acpi_gbl_osi_mutex);
364	return (status);
365}
366
367ACPI_EXPORT_SYMBOL(acpi_install_interface_handler)
368
369/*****************************************************************************
370 *
371 * FUNCTION:    acpi_update_interfaces
372 *
373 * PARAMETERS:  action              - Actions to be performed during the
374 *                                    update
375 *
376 * RETURN:      Status
377 *
378 * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
379 *              string or/and feature group strings.
380 *
381 ****************************************************************************/
382acpi_status acpi_update_interfaces(u8 action)
383{
384	acpi_status status;
385
386	status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
387	if (ACPI_FAILURE(status)) {
388		return (status);
389	}
390
391	status = acpi_ut_update_interfaces(action);
392
393	acpi_os_release_mutex(acpi_gbl_osi_mutex);
394	return (status);
395}
396
397/*****************************************************************************
398 *
399 * FUNCTION:    acpi_check_address_range
400 *
401 * PARAMETERS:  space_id            - Address space ID
402 *              address             - Start address
403 *              length              - Length
404 *              warn                - TRUE if warning on overlap desired
405 *
406 * RETURN:      Count of the number of conflicts detected.
407 *
408 * DESCRIPTION: Check if the input address range overlaps any of the
409 *              ASL operation region address ranges.
410 *
411 ****************************************************************************/
412
413u32
414acpi_check_address_range(acpi_adr_space_type space_id,
415			 acpi_physical_address address,
416			 acpi_size length, u8 warn)
417{
418	u32 overlaps;
419	acpi_status status;
420
421	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
422	if (ACPI_FAILURE(status)) {
423		return (0);
424	}
425
426	overlaps = acpi_ut_check_address_range(space_id, address,
427					       (u32)length, warn);
428
429	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
430	return (overlaps);
431}
432
433ACPI_EXPORT_SYMBOL(acpi_check_address_range)
434#endif				/* !ACPI_ASL_COMPILER */
435/*******************************************************************************
436 *
437 * FUNCTION:    acpi_decode_pld_buffer
438 *
439 * PARAMETERS:  in_buffer           - Buffer returned by _PLD method
440 *              length              - Length of the in_buffer
441 *              return_buffer       - Where the decode buffer is returned
442 *
443 * RETURN:      Status and the decoded _PLD buffer. User must deallocate
444 *              the buffer via ACPI_FREE.
445 *
446 * DESCRIPTION: Decode the bit-packed buffer returned by the _PLD method into
447 *              a local struct that is much more useful to an ACPI driver.
448 *
449 ******************************************************************************/
450acpi_status
451acpi_decode_pld_buffer(u8 *in_buffer,
452		       acpi_size length, struct acpi_pld_info **return_buffer)
453{
454	struct acpi_pld_info *pld_info;
455	u32 *buffer = ACPI_CAST_PTR(u32, in_buffer);
456	u32 dword;
457
458	/* Parameter validation */
459
460	if (!in_buffer || !return_buffer
461	    || (length < ACPI_PLD_REV1_BUFFER_SIZE)) {
462		return (AE_BAD_PARAMETER);
463	}
464
465	pld_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pld_info));
466	if (!pld_info) {
467		return (AE_NO_MEMORY);
468	}
469
470	/* First 32-bit DWord */
471
472	ACPI_MOVE_32_TO_32(&dword, &buffer[0]);
473	pld_info->revision = ACPI_PLD_GET_REVISION(&dword);
474	pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword);
475	pld_info->red = ACPI_PLD_GET_RED(&dword);
476	pld_info->green = ACPI_PLD_GET_GREEN(&dword);
477	pld_info->blue = ACPI_PLD_GET_BLUE(&dword);
478
479	/* Second 32-bit DWord */
480
481	ACPI_MOVE_32_TO_32(&dword, &buffer[1]);
482	pld_info->width = ACPI_PLD_GET_WIDTH(&dword);
483	pld_info->height = ACPI_PLD_GET_HEIGHT(&dword);
484
485	/* Third 32-bit DWord */
486
487	ACPI_MOVE_32_TO_32(&dword, &buffer[2]);
488	pld_info->user_visible = ACPI_PLD_GET_USER_VISIBLE(&dword);
489	pld_info->dock = ACPI_PLD_GET_DOCK(&dword);
490	pld_info->lid = ACPI_PLD_GET_LID(&dword);
491	pld_info->panel = ACPI_PLD_GET_PANEL(&dword);
492	pld_info->vertical_position = ACPI_PLD_GET_VERTICAL(&dword);
493	pld_info->horizontal_position = ACPI_PLD_GET_HORIZONTAL(&dword);
494	pld_info->shape = ACPI_PLD_GET_SHAPE(&dword);
495	pld_info->group_orientation = ACPI_PLD_GET_ORIENTATION(&dword);
496	pld_info->group_token = ACPI_PLD_GET_TOKEN(&dword);
497	pld_info->group_position = ACPI_PLD_GET_POSITION(&dword);
498	pld_info->bay = ACPI_PLD_GET_BAY(&dword);
499
500	/* Fourth 32-bit DWord */
501
502	ACPI_MOVE_32_TO_32(&dword, &buffer[3]);
503	pld_info->ejectable = ACPI_PLD_GET_EJECTABLE(&dword);
504	pld_info->ospm_eject_required = ACPI_PLD_GET_OSPM_EJECT(&dword);
505	pld_info->cabinet_number = ACPI_PLD_GET_CABINET(&dword);
506	pld_info->card_cage_number = ACPI_PLD_GET_CARD_CAGE(&dword);
507	pld_info->reference = ACPI_PLD_GET_REFERENCE(&dword);
508	pld_info->rotation = ACPI_PLD_GET_ROTATION(&dword);
509	pld_info->order = ACPI_PLD_GET_ORDER(&dword);
510
511	if (length >= ACPI_PLD_REV2_BUFFER_SIZE) {
512
513		/* Fifth 32-bit DWord (Revision 2 of _PLD) */
514
515		ACPI_MOVE_32_TO_32(&dword, &buffer[4]);
516		pld_info->vertical_offset = ACPI_PLD_GET_VERT_OFFSET(&dword);
517		pld_info->horizontal_offset = ACPI_PLD_GET_HORIZ_OFFSET(&dword);
518	}
519
520	*return_buffer = pld_info;
521	return (AE_OK);
522}
523
524ACPI_EXPORT_SYMBOL(acpi_decode_pld_buffer)
525