162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: evxface - External interfaces for ACPI events
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define EXPORT_ACPI_INTERFACES
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <acpi/acpi.h>
1362306a36Sopenharmony_ci#include "accommon.h"
1462306a36Sopenharmony_ci#include "acnamesp.h"
1562306a36Sopenharmony_ci#include "acevents.h"
1662306a36Sopenharmony_ci#include "acinterp.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define _COMPONENT          ACPI_EVENTS
1962306a36Sopenharmony_ciACPI_MODULE_NAME("evxface")
2062306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE)
2162306a36Sopenharmony_ci/* Local prototypes */
2262306a36Sopenharmony_cistatic acpi_status
2362306a36Sopenharmony_ciacpi_ev_install_gpe_handler(acpi_handle gpe_device,
2462306a36Sopenharmony_ci			    u32 gpe_number,
2562306a36Sopenharmony_ci			    u32 type,
2662306a36Sopenharmony_ci			    u8 is_raw_handler,
2762306a36Sopenharmony_ci			    acpi_gpe_handler address, void *context);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#endif
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*******************************************************************************
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * FUNCTION:    acpi_install_notify_handler
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * PARAMETERS:  device          - The device for which notifies will be handled
3762306a36Sopenharmony_ci *              handler_type    - The type of handler:
3862306a36Sopenharmony_ci *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
3962306a36Sopenharmony_ci *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
4062306a36Sopenharmony_ci *                                  ACPI_ALL_NOTIFY:    Both System and Device
4162306a36Sopenharmony_ci *              handler         - Address of the handler
4262306a36Sopenharmony_ci *              context         - Value passed to the handler on each GPE
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * RETURN:      Status
4562306a36Sopenharmony_ci *
4662306a36Sopenharmony_ci * DESCRIPTION: Install a handler for notifications on an ACPI Device,
4762306a36Sopenharmony_ci *              thermal_zone, or Processor object.
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * NOTES:       The Root namespace object may have only one handler for each
5062306a36Sopenharmony_ci *              type of notify (System/Device). Device/Thermal/Processor objects
5162306a36Sopenharmony_ci *              may have one device notify handler, and multiple system notify
5262306a36Sopenharmony_ci *              handlers.
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci ******************************************************************************/
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciacpi_status
5762306a36Sopenharmony_ciacpi_install_notify_handler(acpi_handle device,
5862306a36Sopenharmony_ci			    u32 handler_type,
5962306a36Sopenharmony_ci			    acpi_notify_handler handler, void *context)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct acpi_namespace_node *node =
6262306a36Sopenharmony_ci	    ACPI_CAST_PTR(struct acpi_namespace_node, device);
6362306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
6462306a36Sopenharmony_ci	union acpi_operand_object *handler_obj;
6562306a36Sopenharmony_ci	acpi_status status;
6662306a36Sopenharmony_ci	u32 i;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Parameter validation */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if ((!device) || (!handler) || (!handler_type) ||
7362306a36Sopenharmony_ci	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
7462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
7862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/*
8362306a36Sopenharmony_ci	 * Root Object:
8462306a36Sopenharmony_ci	 * Registering a notify handler on the root object indicates that the
8562306a36Sopenharmony_ci	 * caller wishes to receive notifications for all objects. Note that
8662306a36Sopenharmony_ci	 * only one global handler can be registered per notify type.
8762306a36Sopenharmony_ci	 * Ensure that a handler is not already installed.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci	if (device == ACPI_ROOT_OBJECT) {
9062306a36Sopenharmony_ci		for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
9162306a36Sopenharmony_ci			if (handler_type & (i + 1)) {
9262306a36Sopenharmony_ci				if (acpi_gbl_global_notify[i].handler) {
9362306a36Sopenharmony_ci					status = AE_ALREADY_EXISTS;
9462306a36Sopenharmony_ci					goto unlock_and_exit;
9562306a36Sopenharmony_ci				}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci				acpi_gbl_global_notify[i].handler = handler;
9862306a36Sopenharmony_ci				acpi_gbl_global_notify[i].context = context;
9962306a36Sopenharmony_ci			}
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		goto unlock_and_exit;	/* Global notify handler installed, all done */
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/*
10662306a36Sopenharmony_ci	 * All Other Objects:
10762306a36Sopenharmony_ci	 * Caller will only receive notifications specific to the target
10862306a36Sopenharmony_ci	 * object. Note that only certain object types are allowed to
10962306a36Sopenharmony_ci	 * receive notifications.
11062306a36Sopenharmony_ci	 */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* Are Notifies allowed on this object? */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (!acpi_ev_is_notify_object(node)) {
11562306a36Sopenharmony_ci		status = AE_TYPE;
11662306a36Sopenharmony_ci		goto unlock_and_exit;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* Check for an existing internal object, might not exist */
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	obj_desc = acpi_ns_get_attached_object(node);
12262306a36Sopenharmony_ci	if (!obj_desc) {
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		/* Create a new object */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		obj_desc = acpi_ut_create_internal_object(node->type);
12762306a36Sopenharmony_ci		if (!obj_desc) {
12862306a36Sopenharmony_ci			status = AE_NO_MEMORY;
12962306a36Sopenharmony_ci			goto unlock_and_exit;
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		/* Attach new object to the Node, remove local reference */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		status = acpi_ns_attach_object(device, obj_desc, node->type);
13562306a36Sopenharmony_ci		acpi_ut_remove_reference(obj_desc);
13662306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
13762306a36Sopenharmony_ci			goto unlock_and_exit;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Ensure that the handler is not already installed in the lists */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
14462306a36Sopenharmony_ci		if (handler_type & (i + 1)) {
14562306a36Sopenharmony_ci			handler_obj = obj_desc->common_notify.notify_list[i];
14662306a36Sopenharmony_ci			while (handler_obj) {
14762306a36Sopenharmony_ci				if (handler_obj->notify.handler == handler) {
14862306a36Sopenharmony_ci					status = AE_ALREADY_EXISTS;
14962306a36Sopenharmony_ci					goto unlock_and_exit;
15062306a36Sopenharmony_ci				}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci				handler_obj = handler_obj->notify.next[i];
15362306a36Sopenharmony_ci			}
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* Create and populate a new notify handler object */
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
16062306a36Sopenharmony_ci	if (!handler_obj) {
16162306a36Sopenharmony_ci		status = AE_NO_MEMORY;
16262306a36Sopenharmony_ci		goto unlock_and_exit;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	handler_obj->notify.node = node;
16662306a36Sopenharmony_ci	handler_obj->notify.handler_type = handler_type;
16762306a36Sopenharmony_ci	handler_obj->notify.handler = handler;
16862306a36Sopenharmony_ci	handler_obj->notify.context = context;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Install the handler at the list head(s) */
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
17362306a36Sopenharmony_ci		if (handler_type & (i + 1)) {
17462306a36Sopenharmony_ci			handler_obj->notify.next[i] =
17562306a36Sopenharmony_ci			    obj_desc->common_notify.notify_list[i];
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci			obj_desc->common_notify.notify_list[i] = handler_obj;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Add an extra reference if handler was installed in both lists */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	if (handler_type == ACPI_ALL_NOTIFY) {
18462306a36Sopenharmony_ci		acpi_ut_add_reference(handler_obj);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciunlock_and_exit:
18862306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
18962306a36Sopenharmony_ci	return_ACPI_STATUS(status);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci/*******************************************************************************
19562306a36Sopenharmony_ci *
19662306a36Sopenharmony_ci * FUNCTION:    acpi_remove_notify_handler
19762306a36Sopenharmony_ci *
19862306a36Sopenharmony_ci * PARAMETERS:  device          - The device for which the handler is installed
19962306a36Sopenharmony_ci *              handler_type    - The type of handler:
20062306a36Sopenharmony_ci *                                  ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
20162306a36Sopenharmony_ci *                                  ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
20262306a36Sopenharmony_ci *                                  ACPI_ALL_NOTIFY:    Both System and Device
20362306a36Sopenharmony_ci *              handler         - Address of the handler
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * RETURN:      Status
20662306a36Sopenharmony_ci *
20762306a36Sopenharmony_ci * DESCRIPTION: Remove a handler for notifies on an ACPI device
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci ******************************************************************************/
21062306a36Sopenharmony_ciacpi_status
21162306a36Sopenharmony_ciacpi_remove_notify_handler(acpi_handle device,
21262306a36Sopenharmony_ci			   u32 handler_type, acpi_notify_handler handler)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct acpi_namespace_node *node =
21562306a36Sopenharmony_ci	    ACPI_CAST_PTR(struct acpi_namespace_node, device);
21662306a36Sopenharmony_ci	union acpi_operand_object *obj_desc;
21762306a36Sopenharmony_ci	union acpi_operand_object *handler_obj;
21862306a36Sopenharmony_ci	union acpi_operand_object *previous_handler_obj;
21962306a36Sopenharmony_ci	acpi_status status = AE_OK;
22062306a36Sopenharmony_ci	u32 i;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Parameter validation */
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if ((!device) || (!handler) || (!handler_type) ||
22762306a36Sopenharmony_ci	    (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
22862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	/* Root Object. Global handlers are removed here */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (device == ACPI_ROOT_OBJECT) {
23462306a36Sopenharmony_ci		for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
23562306a36Sopenharmony_ci			if (handler_type & (i + 1)) {
23662306a36Sopenharmony_ci				status =
23762306a36Sopenharmony_ci				    acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
23862306a36Sopenharmony_ci				if (ACPI_FAILURE(status)) {
23962306a36Sopenharmony_ci					return_ACPI_STATUS(status);
24062306a36Sopenharmony_ci				}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci				if (!acpi_gbl_global_notify[i].handler ||
24362306a36Sopenharmony_ci				    (acpi_gbl_global_notify[i].handler !=
24462306a36Sopenharmony_ci				     handler)) {
24562306a36Sopenharmony_ci					status = AE_NOT_EXIST;
24662306a36Sopenharmony_ci					goto unlock_and_exit;
24762306a36Sopenharmony_ci				}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
25062306a36Sopenharmony_ci						  "Removing global notify handler\n"));
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci				acpi_gbl_global_notify[i].handler = NULL;
25362306a36Sopenharmony_ci				acpi_gbl_global_notify[i].context = NULL;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci				(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci				/* Make sure all deferred notify tasks are completed */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci				acpi_os_wait_events_complete();
26062306a36Sopenharmony_ci			}
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_OK);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	/* All other objects: Are Notifies allowed on this object? */
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (!acpi_ev_is_notify_object(node)) {
26962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_TYPE);
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Must have an existing internal object */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	obj_desc = acpi_ns_get_attached_object(node);
27562306a36Sopenharmony_ci	if (!obj_desc) {
27662306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NOT_EXIST);
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Internal object exists. Find the handler and remove it */
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
28262306a36Sopenharmony_ci		if (handler_type & (i + 1)) {
28362306a36Sopenharmony_ci			status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
28462306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
28562306a36Sopenharmony_ci				return_ACPI_STATUS(status);
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci			handler_obj = obj_desc->common_notify.notify_list[i];
28962306a36Sopenharmony_ci			previous_handler_obj = NULL;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci			/* Attempt to find the handler in the handler list */
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			while (handler_obj &&
29462306a36Sopenharmony_ci			       (handler_obj->notify.handler != handler)) {
29562306a36Sopenharmony_ci				previous_handler_obj = handler_obj;
29662306a36Sopenharmony_ci				handler_obj = handler_obj->notify.next[i];
29762306a36Sopenharmony_ci			}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci			if (!handler_obj) {
30062306a36Sopenharmony_ci				status = AE_NOT_EXIST;
30162306a36Sopenharmony_ci				goto unlock_and_exit;
30262306a36Sopenharmony_ci			}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci			/* Remove the handler object from the list */
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci			if (previous_handler_obj) {	/* Handler is not at the list head */
30762306a36Sopenharmony_ci				previous_handler_obj->notify.next[i] =
30862306a36Sopenharmony_ci				    handler_obj->notify.next[i];
30962306a36Sopenharmony_ci			} else {	/* Handler is at the list head */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci				obj_desc->common_notify.notify_list[i] =
31262306a36Sopenharmony_ci				    handler_obj->notify.next[i];
31362306a36Sopenharmony_ci			}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci			(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci			/* Make sure all deferred notify tasks are completed */
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci			acpi_os_wait_events_complete();
32062306a36Sopenharmony_ci			acpi_ut_remove_reference(handler_obj);
32162306a36Sopenharmony_ci		}
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	return_ACPI_STATUS(status);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciunlock_and_exit:
32762306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
32862306a36Sopenharmony_ci	return_ACPI_STATUS(status);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci/*******************************************************************************
33462306a36Sopenharmony_ci *
33562306a36Sopenharmony_ci * FUNCTION:    acpi_install_exception_handler
33662306a36Sopenharmony_ci *
33762306a36Sopenharmony_ci * PARAMETERS:  handler         - Pointer to the handler function for the
33862306a36Sopenharmony_ci *                                event
33962306a36Sopenharmony_ci *
34062306a36Sopenharmony_ci * RETURN:      Status
34162306a36Sopenharmony_ci *
34262306a36Sopenharmony_ci * DESCRIPTION: Saves the pointer to the handler function
34362306a36Sopenharmony_ci *
34462306a36Sopenharmony_ci ******************************************************************************/
34562306a36Sopenharmony_ci#ifdef ACPI_FUTURE_USAGE
34662306a36Sopenharmony_ciacpi_status acpi_install_exception_handler(acpi_exception_handler handler)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	acpi_status status;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
35362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
35462306a36Sopenharmony_ci		return_ACPI_STATUS(status);
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* Don't allow two handlers. */
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (acpi_gbl_exception_handler) {
36062306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
36162306a36Sopenharmony_ci		goto cleanup;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Install the handler */
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	acpi_gbl_exception_handler = handler;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cicleanup:
36962306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
37062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
37462306a36Sopenharmony_ci#endif
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci#if (!ACPI_REDUCED_HARDWARE)
37762306a36Sopenharmony_ci/*******************************************************************************
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * FUNCTION:    acpi_install_sci_handler
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci * PARAMETERS:  address             - Address of the handler
38262306a36Sopenharmony_ci *              context             - Value passed to the handler on each SCI
38362306a36Sopenharmony_ci *
38462306a36Sopenharmony_ci * RETURN:      Status
38562306a36Sopenharmony_ci *
38662306a36Sopenharmony_ci * DESCRIPTION: Install a handler for a System Control Interrupt.
38762306a36Sopenharmony_ci *
38862306a36Sopenharmony_ci ******************************************************************************/
38962306a36Sopenharmony_ciacpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct acpi_sci_handler_info *new_sci_handler;
39262306a36Sopenharmony_ci	struct acpi_sci_handler_info *sci_handler;
39362306a36Sopenharmony_ci	acpi_cpu_flags flags;
39462306a36Sopenharmony_ci	acpi_status status;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_sci_handler);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!address) {
39962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Allocate and init a handler object */
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info));
40562306a36Sopenharmony_ci	if (!new_sci_handler) {
40662306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	new_sci_handler->address = address;
41062306a36Sopenharmony_ci	new_sci_handler->context = context;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
41362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
41462306a36Sopenharmony_ci		goto exit;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Lock list during installation */
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
42062306a36Sopenharmony_ci	sci_handler = acpi_gbl_sci_handler_list;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Ensure handler does not already exist */
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	while (sci_handler) {
42562306a36Sopenharmony_ci		if (address == sci_handler->address) {
42662306a36Sopenharmony_ci			status = AE_ALREADY_EXISTS;
42762306a36Sopenharmony_ci			goto unlock_and_exit;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		sci_handler = sci_handler->next;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	/* Install the new handler into the global list (at head) */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	new_sci_handler->next = acpi_gbl_sci_handler_list;
43662306a36Sopenharmony_ci	acpi_gbl_sci_handler_list = new_sci_handler;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciunlock_and_exit:
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
44162306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ciexit:
44462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
44562306a36Sopenharmony_ci		ACPI_FREE(new_sci_handler);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci	return_ACPI_STATUS(status);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci/*******************************************************************************
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci * FUNCTION:    acpi_remove_sci_handler
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * PARAMETERS:  address             - Address of the handler
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci * RETURN:      Status
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * DESCRIPTION: Remove a handler for a System Control Interrupt.
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci ******************************************************************************/
46362306a36Sopenharmony_ciacpi_status acpi_remove_sci_handler(acpi_sci_handler address)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct acpi_sci_handler_info *prev_sci_handler;
46662306a36Sopenharmony_ci	struct acpi_sci_handler_info *next_sci_handler;
46762306a36Sopenharmony_ci	acpi_cpu_flags flags;
46862306a36Sopenharmony_ci	acpi_status status;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_remove_sci_handler);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!address) {
47362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
47762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
47862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/* Remove the SCI handler with lock */
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	prev_sci_handler = NULL;
48662306a36Sopenharmony_ci	next_sci_handler = acpi_gbl_sci_handler_list;
48762306a36Sopenharmony_ci	while (next_sci_handler) {
48862306a36Sopenharmony_ci		if (next_sci_handler->address == address) {
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci			/* Unlink and free the SCI handler info block */
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci			if (prev_sci_handler) {
49362306a36Sopenharmony_ci				prev_sci_handler->next = next_sci_handler->next;
49462306a36Sopenharmony_ci			} else {
49562306a36Sopenharmony_ci				acpi_gbl_sci_handler_list =
49662306a36Sopenharmony_ci				    next_sci_handler->next;
49762306a36Sopenharmony_ci			}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci			acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
50062306a36Sopenharmony_ci			ACPI_FREE(next_sci_handler);
50162306a36Sopenharmony_ci			goto unlock_and_exit;
50262306a36Sopenharmony_ci		}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		prev_sci_handler = next_sci_handler;
50562306a36Sopenharmony_ci		next_sci_handler = next_sci_handler->next;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
50962306a36Sopenharmony_ci	status = AE_NOT_EXIST;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ciunlock_and_exit:
51262306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
51362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci/*******************************************************************************
51962306a36Sopenharmony_ci *
52062306a36Sopenharmony_ci * FUNCTION:    acpi_install_global_event_handler
52162306a36Sopenharmony_ci *
52262306a36Sopenharmony_ci * PARAMETERS:  handler         - Pointer to the global event handler function
52362306a36Sopenharmony_ci *              context         - Value passed to the handler on each event
52462306a36Sopenharmony_ci *
52562306a36Sopenharmony_ci * RETURN:      Status
52662306a36Sopenharmony_ci *
52762306a36Sopenharmony_ci * DESCRIPTION: Saves the pointer to the handler function. The global handler
52862306a36Sopenharmony_ci *              is invoked upon each incoming GPE and Fixed Event. It is
52962306a36Sopenharmony_ci *              invoked at interrupt level at the time of the event dispatch.
53062306a36Sopenharmony_ci *              Can be used to update event counters, etc.
53162306a36Sopenharmony_ci *
53262306a36Sopenharmony_ci ******************************************************************************/
53362306a36Sopenharmony_ciacpi_status
53462306a36Sopenharmony_ciacpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	acpi_status status;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	/* Parameter validation */
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!handler) {
54362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
54762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
54862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Don't allow two handlers. */
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (acpi_gbl_global_event_handler) {
55462306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
55562306a36Sopenharmony_ci		goto cleanup;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	acpi_gbl_global_event_handler = handler;
55962306a36Sopenharmony_ci	acpi_gbl_global_event_handler_context = context;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cicleanup:
56262306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
56362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci/*******************************************************************************
56962306a36Sopenharmony_ci *
57062306a36Sopenharmony_ci * FUNCTION:    acpi_install_fixed_event_handler
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * PARAMETERS:  event           - Event type to enable.
57362306a36Sopenharmony_ci *              handler         - Pointer to the handler function for the
57462306a36Sopenharmony_ci *                                event
57562306a36Sopenharmony_ci *              context         - Value passed to the handler on each GPE
57662306a36Sopenharmony_ci *
57762306a36Sopenharmony_ci * RETURN:      Status
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * DESCRIPTION: Saves the pointer to the handler function and then enables the
58062306a36Sopenharmony_ci *              event.
58162306a36Sopenharmony_ci *
58262306a36Sopenharmony_ci ******************************************************************************/
58362306a36Sopenharmony_ciacpi_status
58462306a36Sopenharmony_ciacpi_install_fixed_event_handler(u32 event,
58562306a36Sopenharmony_ci				 acpi_event_handler handler, void *context)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	acpi_status status;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* Parameter validation */
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (event > ACPI_EVENT_MAX) {
59462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
59862306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
59962306a36Sopenharmony_ci		return_ACPI_STATUS(status);
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* Do not allow multiple handlers */
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (acpi_gbl_fixed_event_handlers[event].handler) {
60562306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
60662306a36Sopenharmony_ci		goto cleanup;
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* Install the handler before enabling the event */
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	acpi_gbl_fixed_event_handlers[event].handler = handler;
61262306a36Sopenharmony_ci	acpi_gbl_fixed_event_handlers[event].context = context;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	status = acpi_clear_event(event);
61562306a36Sopenharmony_ci	if (ACPI_SUCCESS(status))
61662306a36Sopenharmony_ci		status = acpi_enable_event(event, 0);
61762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
61862306a36Sopenharmony_ci		ACPI_WARNING((AE_INFO,
61962306a36Sopenharmony_ci			      "Could not enable fixed event - %s (%u)",
62062306a36Sopenharmony_ci			      acpi_ut_get_event_name(event), event));
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		/* Remove the handler */
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		acpi_gbl_fixed_event_handlers[event].handler = NULL;
62562306a36Sopenharmony_ci		acpi_gbl_fixed_event_handlers[event].context = NULL;
62662306a36Sopenharmony_ci	} else {
62762306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
62862306a36Sopenharmony_ci				  "Enabled fixed event %s (%X), Handler=%p\n",
62962306a36Sopenharmony_ci				  acpi_ut_get_event_name(event), event,
63062306a36Sopenharmony_ci				  handler));
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cicleanup:
63462306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
63562306a36Sopenharmony_ci	return_ACPI_STATUS(status);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/*******************************************************************************
64162306a36Sopenharmony_ci *
64262306a36Sopenharmony_ci * FUNCTION:    acpi_remove_fixed_event_handler
64362306a36Sopenharmony_ci *
64462306a36Sopenharmony_ci * PARAMETERS:  event           - Event type to disable.
64562306a36Sopenharmony_ci *              handler         - Address of the handler
64662306a36Sopenharmony_ci *
64762306a36Sopenharmony_ci * RETURN:      Status
64862306a36Sopenharmony_ci *
64962306a36Sopenharmony_ci * DESCRIPTION: Disables the event and unregisters the event handler.
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci ******************************************************************************/
65262306a36Sopenharmony_ciacpi_status
65362306a36Sopenharmony_ciacpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	acpi_status status = AE_OK;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* Parameter validation */
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	if (event > ACPI_EVENT_MAX) {
66262306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
66662306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
66762306a36Sopenharmony_ci		return_ACPI_STATUS(status);
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* Disable the event before removing the handler */
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	status = acpi_disable_event(event, 0);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	/* Always Remove the handler */
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	acpi_gbl_fixed_event_handlers[event].handler = NULL;
67762306a36Sopenharmony_ci	acpi_gbl_fixed_event_handlers[event].context = NULL;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
68062306a36Sopenharmony_ci		ACPI_WARNING((AE_INFO,
68162306a36Sopenharmony_ci			      "Could not disable fixed event - %s (%u)",
68262306a36Sopenharmony_ci			      acpi_ut_get_event_name(event), event));
68362306a36Sopenharmony_ci	} else {
68462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
68562306a36Sopenharmony_ci				  "Disabled fixed event - %s (%X)\n",
68662306a36Sopenharmony_ci				  acpi_ut_get_event_name(event), event));
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
69062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci/*******************************************************************************
69662306a36Sopenharmony_ci *
69762306a36Sopenharmony_ci * FUNCTION:    acpi_ev_install_gpe_handler
69862306a36Sopenharmony_ci *
69962306a36Sopenharmony_ci * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
70062306a36Sopenharmony_ci *                                defined GPEs)
70162306a36Sopenharmony_ci *              gpe_number      - The GPE number within the GPE block
70262306a36Sopenharmony_ci *              type            - Whether this GPE should be treated as an
70362306a36Sopenharmony_ci *                                edge- or level-triggered interrupt.
70462306a36Sopenharmony_ci *              is_raw_handler  - Whether this GPE should be handled using
70562306a36Sopenharmony_ci *                                the special GPE handler mode.
70662306a36Sopenharmony_ci *              address         - Address of the handler
70762306a36Sopenharmony_ci *              context         - Value passed to the handler on each GPE
70862306a36Sopenharmony_ci *
70962306a36Sopenharmony_ci * RETURN:      Status
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci * DESCRIPTION: Internal function to install a handler for a General Purpose
71262306a36Sopenharmony_ci *              Event.
71362306a36Sopenharmony_ci *
71462306a36Sopenharmony_ci ******************************************************************************/
71562306a36Sopenharmony_cistatic acpi_status
71662306a36Sopenharmony_ciacpi_ev_install_gpe_handler(acpi_handle gpe_device,
71762306a36Sopenharmony_ci			    u32 gpe_number,
71862306a36Sopenharmony_ci			    u32 type,
71962306a36Sopenharmony_ci			    u8 is_raw_handler,
72062306a36Sopenharmony_ci			    acpi_gpe_handler address, void *context)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info;
72362306a36Sopenharmony_ci	struct acpi_gpe_handler_info *handler;
72462306a36Sopenharmony_ci	acpi_status status;
72562306a36Sopenharmony_ci	acpi_cpu_flags flags;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ev_install_gpe_handler);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* Parameter validation */
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) {
73262306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
73662306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
73762306a36Sopenharmony_ci		return_ACPI_STATUS(status);
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* Allocate and init handler object (before lock) */
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
74362306a36Sopenharmony_ci	if (!handler) {
74462306a36Sopenharmony_ci		status = AE_NO_MEMORY;
74562306a36Sopenharmony_ci		goto unlock_and_exit;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Ensure that we have a valid GPE number */
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
75362306a36Sopenharmony_ci	if (!gpe_event_info) {
75462306a36Sopenharmony_ci		status = AE_BAD_PARAMETER;
75562306a36Sopenharmony_ci		goto free_and_exit;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* Make sure that there isn't a handler there already */
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
76162306a36Sopenharmony_ci	     ACPI_GPE_DISPATCH_HANDLER) ||
76262306a36Sopenharmony_ci	    (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
76362306a36Sopenharmony_ci	     ACPI_GPE_DISPATCH_RAW_HANDLER)) {
76462306a36Sopenharmony_ci		status = AE_ALREADY_EXISTS;
76562306a36Sopenharmony_ci		goto free_and_exit;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	handler->address = address;
76962306a36Sopenharmony_ci	handler->context = context;
77062306a36Sopenharmony_ci	handler->method_node = gpe_event_info->dispatch.method_node;
77162306a36Sopenharmony_ci	handler->original_flags = (u8)(gpe_event_info->flags &
77262306a36Sopenharmony_ci				       (ACPI_GPE_XRUPT_TYPE_MASK |
77362306a36Sopenharmony_ci					ACPI_GPE_DISPATCH_MASK));
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/*
77662306a36Sopenharmony_ci	 * If the GPE is associated with a method, it may have been enabled
77762306a36Sopenharmony_ci	 * automatically during initialization, in which case it has to be
77862306a36Sopenharmony_ci	 * disabled now to avoid spurious execution of the handler.
77962306a36Sopenharmony_ci	 */
78062306a36Sopenharmony_ci	if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
78162306a36Sopenharmony_ci	      ACPI_GPE_DISPATCH_METHOD) ||
78262306a36Sopenharmony_ci	     (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
78362306a36Sopenharmony_ci	      ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) {
78462306a36Sopenharmony_ci		handler->originally_enabled = TRUE;
78562306a36Sopenharmony_ci		(void)acpi_ev_remove_gpe_reference(gpe_event_info);
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		/* Sanity check of original type against new type */
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		if (type !=
79062306a36Sopenharmony_ci		    (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
79162306a36Sopenharmony_ci			ACPI_WARNING((AE_INFO,
79262306a36Sopenharmony_ci				      "GPE type mismatch (level/edge)"));
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	/* Install the handler */
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	gpe_event_info->dispatch.handler = handler;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	/* Setup up dispatch flags to indicate handler (vs. method/notify) */
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	gpe_event_info->flags &=
80362306a36Sopenharmony_ci	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
80462306a36Sopenharmony_ci	gpe_event_info->flags |=
80562306a36Sopenharmony_ci	    (u8)(type |
80662306a36Sopenharmony_ci		 (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER :
80762306a36Sopenharmony_ci		  ACPI_GPE_DISPATCH_HANDLER));
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ciunlock_and_exit:
81262306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
81362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cifree_and_exit:
81662306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
81762306a36Sopenharmony_ci	ACPI_FREE(handler);
81862306a36Sopenharmony_ci	goto unlock_and_exit;
81962306a36Sopenharmony_ci}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci/*******************************************************************************
82262306a36Sopenharmony_ci *
82362306a36Sopenharmony_ci * FUNCTION:    acpi_install_gpe_handler
82462306a36Sopenharmony_ci *
82562306a36Sopenharmony_ci * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
82662306a36Sopenharmony_ci *                                defined GPEs)
82762306a36Sopenharmony_ci *              gpe_number      - The GPE number within the GPE block
82862306a36Sopenharmony_ci *              type            - Whether this GPE should be treated as an
82962306a36Sopenharmony_ci *                                edge- or level-triggered interrupt.
83062306a36Sopenharmony_ci *              address         - Address of the handler
83162306a36Sopenharmony_ci *              context         - Value passed to the handler on each GPE
83262306a36Sopenharmony_ci *
83362306a36Sopenharmony_ci * RETURN:      Status
83462306a36Sopenharmony_ci *
83562306a36Sopenharmony_ci * DESCRIPTION: Install a handler for a General Purpose Event.
83662306a36Sopenharmony_ci *
83762306a36Sopenharmony_ci ******************************************************************************/
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ciacpi_status
84062306a36Sopenharmony_ciacpi_install_gpe_handler(acpi_handle gpe_device,
84162306a36Sopenharmony_ci			 u32 gpe_number,
84262306a36Sopenharmony_ci			 u32 type, acpi_gpe_handler address, void *context)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	acpi_status status;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
84962306a36Sopenharmony_ci					     FALSE, address, context);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	return_ACPI_STATUS(status);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci/*******************************************************************************
85762306a36Sopenharmony_ci *
85862306a36Sopenharmony_ci * FUNCTION:    acpi_install_gpe_raw_handler
85962306a36Sopenharmony_ci *
86062306a36Sopenharmony_ci * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
86162306a36Sopenharmony_ci *                                defined GPEs)
86262306a36Sopenharmony_ci *              gpe_number      - The GPE number within the GPE block
86362306a36Sopenharmony_ci *              type            - Whether this GPE should be treated as an
86462306a36Sopenharmony_ci *                                edge- or level-triggered interrupt.
86562306a36Sopenharmony_ci *              address         - Address of the handler
86662306a36Sopenharmony_ci *              context         - Value passed to the handler on each GPE
86762306a36Sopenharmony_ci *
86862306a36Sopenharmony_ci * RETURN:      Status
86962306a36Sopenharmony_ci *
87062306a36Sopenharmony_ci * DESCRIPTION: Install a handler for a General Purpose Event.
87162306a36Sopenharmony_ci *
87262306a36Sopenharmony_ci ******************************************************************************/
87362306a36Sopenharmony_ciacpi_status
87462306a36Sopenharmony_ciacpi_install_gpe_raw_handler(acpi_handle gpe_device,
87562306a36Sopenharmony_ci			     u32 gpe_number,
87662306a36Sopenharmony_ci			     u32 type, acpi_gpe_handler address, void *context)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	acpi_status status;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
88362306a36Sopenharmony_ci					     TRUE, address, context);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return_ACPI_STATUS(status);
88662306a36Sopenharmony_ci}
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci/*******************************************************************************
89162306a36Sopenharmony_ci *
89262306a36Sopenharmony_ci * FUNCTION:    acpi_remove_gpe_handler
89362306a36Sopenharmony_ci *
89462306a36Sopenharmony_ci * PARAMETERS:  gpe_device      - Namespace node for the GPE (NULL for FADT
89562306a36Sopenharmony_ci *                                defined GPEs)
89662306a36Sopenharmony_ci *              gpe_number      - The event to remove a handler
89762306a36Sopenharmony_ci *              address         - Address of the handler
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * RETURN:      Status
90062306a36Sopenharmony_ci *
90162306a36Sopenharmony_ci * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
90262306a36Sopenharmony_ci *
90362306a36Sopenharmony_ci ******************************************************************************/
90462306a36Sopenharmony_ciacpi_status
90562306a36Sopenharmony_ciacpi_remove_gpe_handler(acpi_handle gpe_device,
90662306a36Sopenharmony_ci			u32 gpe_number, acpi_gpe_handler address)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct acpi_gpe_event_info *gpe_event_info;
90962306a36Sopenharmony_ci	struct acpi_gpe_handler_info *handler;
91062306a36Sopenharmony_ci	acpi_status status;
91162306a36Sopenharmony_ci	acpi_cpu_flags flags;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* Parameter validation */
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	if (!address) {
91862306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_PARAMETER);
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
92262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
92362306a36Sopenharmony_ci		return_ACPI_STATUS(status);
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* Ensure that we have a valid GPE number */
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
93162306a36Sopenharmony_ci	if (!gpe_event_info) {
93262306a36Sopenharmony_ci		status = AE_BAD_PARAMETER;
93362306a36Sopenharmony_ci		goto unlock_and_exit;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	/* Make sure that a handler is indeed installed */
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
93962306a36Sopenharmony_ci	     ACPI_GPE_DISPATCH_HANDLER) &&
94062306a36Sopenharmony_ci	    (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
94162306a36Sopenharmony_ci	     ACPI_GPE_DISPATCH_RAW_HANDLER)) {
94262306a36Sopenharmony_ci		status = AE_NOT_EXIST;
94362306a36Sopenharmony_ci		goto unlock_and_exit;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* Make sure that the installed handler is the same */
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (gpe_event_info->dispatch.handler->address != address) {
94962306a36Sopenharmony_ci		status = AE_BAD_PARAMETER;
95062306a36Sopenharmony_ci		goto unlock_and_exit;
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	/* Remove the handler */
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	handler = gpe_event_info->dispatch.handler;
95662306a36Sopenharmony_ci	gpe_event_info->dispatch.handler = NULL;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	/* Restore Method node (if any), set dispatch flags */
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	gpe_event_info->dispatch.method_node = handler->method_node;
96162306a36Sopenharmony_ci	gpe_event_info->flags &=
96262306a36Sopenharmony_ci	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
96362306a36Sopenharmony_ci	gpe_event_info->flags |= handler->original_flags;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/*
96662306a36Sopenharmony_ci	 * If the GPE was previously associated with a method and it was
96762306a36Sopenharmony_ci	 * enabled, it should be enabled at this point to restore the
96862306a36Sopenharmony_ci	 * post-initialization configuration.
96962306a36Sopenharmony_ci	 */
97062306a36Sopenharmony_ci	if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
97162306a36Sopenharmony_ci	      ACPI_GPE_DISPATCH_METHOD) ||
97262306a36Sopenharmony_ci	     (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
97362306a36Sopenharmony_ci	      ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
97462306a36Sopenharmony_ci		(void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
97562306a36Sopenharmony_ci		if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci			/* Poll edge triggered GPEs to handle existing events */
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci			acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
98062306a36Sopenharmony_ci			(void)acpi_ev_detect_gpe(gpe_device, gpe_event_info,
98162306a36Sopenharmony_ci						 gpe_number);
98262306a36Sopenharmony_ci			flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
98362306a36Sopenharmony_ci		}
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
98762306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	/* Make sure all deferred GPE tasks are completed */
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	acpi_os_wait_events_complete();
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/* Now we can free the handler object */
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	ACPI_FREE(handler);
99662306a36Sopenharmony_ci	return_ACPI_STATUS(status);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ciunlock_and_exit:
99962306a36Sopenharmony_ci	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
100262306a36Sopenharmony_ci	return_ACPI_STATUS(status);
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci/*******************************************************************************
100862306a36Sopenharmony_ci *
100962306a36Sopenharmony_ci * FUNCTION:    acpi_acquire_global_lock
101062306a36Sopenharmony_ci *
101162306a36Sopenharmony_ci * PARAMETERS:  timeout         - How long the caller is willing to wait
101262306a36Sopenharmony_ci *              handle          - Where the handle to the lock is returned
101362306a36Sopenharmony_ci *                                (if acquired)
101462306a36Sopenharmony_ci *
101562306a36Sopenharmony_ci * RETURN:      Status
101662306a36Sopenharmony_ci *
101762306a36Sopenharmony_ci * DESCRIPTION: Acquire the ACPI Global Lock
101862306a36Sopenharmony_ci *
101962306a36Sopenharmony_ci * Note: Allows callers with the same thread ID to acquire the global lock
102062306a36Sopenharmony_ci * multiple times. In other words, externally, the behavior of the global lock
102162306a36Sopenharmony_ci * is identical to an AML mutex. On the first acquire, a new handle is
102262306a36Sopenharmony_ci * returned. On any subsequent calls to acquire by the same thread, the same
102362306a36Sopenharmony_ci * handle is returned.
102462306a36Sopenharmony_ci *
102562306a36Sopenharmony_ci ******************************************************************************/
102662306a36Sopenharmony_ciacpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	acpi_status status;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (!handle) {
103162306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
103262306a36Sopenharmony_ci	}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	/* Must lock interpreter to prevent race conditions */
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	acpi_ex_enter_interpreter();
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	status = acpi_ex_acquire_mutex_object(timeout,
103962306a36Sopenharmony_ci					      acpi_gbl_global_lock_mutex,
104062306a36Sopenharmony_ci					      acpi_os_get_thread_id());
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci		/* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		*handle = acpi_gbl_global_lock_handle;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	acpi_ex_exit_interpreter();
105062306a36Sopenharmony_ci	return (status);
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci/*******************************************************************************
105662306a36Sopenharmony_ci *
105762306a36Sopenharmony_ci * FUNCTION:    acpi_release_global_lock
105862306a36Sopenharmony_ci *
105962306a36Sopenharmony_ci * PARAMETERS:  handle      - Returned from acpi_acquire_global_lock
106062306a36Sopenharmony_ci *
106162306a36Sopenharmony_ci * RETURN:      Status
106262306a36Sopenharmony_ci *
106362306a36Sopenharmony_ci * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
106462306a36Sopenharmony_ci *
106562306a36Sopenharmony_ci ******************************************************************************/
106662306a36Sopenharmony_ciacpi_status acpi_release_global_lock(u32 handle)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	acpi_status status;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (!handle || (handle != acpi_gbl_global_lock_handle)) {
107162306a36Sopenharmony_ci		return (AE_NOT_ACQUIRED);
107262306a36Sopenharmony_ci	}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
107562306a36Sopenharmony_ci	return (status);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_release_global_lock)
107962306a36Sopenharmony_ci#endif				/* !ACPI_REDUCED_HARDWARE */
1080