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