Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
*
* Module Name: evmisc - Miscellaneous event manager support functions
*
* Copyright (C) 2000 - 2019, Intel Corp.
*
*****************************************************************************/
#include <acpi/acpi.h>
#include "accommon.h"
#include "acevents.h"
#include "acnamesp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
/* Local prototypes */
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
/*******************************************************************************
*
* FUNCTION: acpi_ev_is_notify_object
*
* PARAMETERS: node - Node to check
*
* RETURN: TRUE if notifies allowed on this object
*
* DESCRIPTION: Check type of node for a object that supports notifies.
*
* TBD: This could be replaced by a flag bit in the node.
*
******************************************************************************/
u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
{
switch (node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
/*
* These are the ONLY objects that can receive ACPI notifications
*/
return (TRUE);
default:
return (FALSE);
}
}
/*******************************************************************************
*
* FUNCTION: acpi_ev_queue_notify_request
*
* PARAMETERS: node - NS node for the notified object
* notify_value - Value from the Notify() request
*
* RETURN: Status
*
* DESCRIPTION: Dispatch a device notification event to a previously
* installed handler.
*
******************************************************************************/
acpi_status
acpi_ev_queue_notify_request(struct acpi_namespace_node *node, u32 notify_value)
{
union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_list_head = NULL;
union acpi_generic_state *info;
u8 handler_list_id = 0;
acpi_status status = AE_OK;
ACPI_FUNCTION_NAME(ev_queue_notify_request);
/* Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) {
return (AE_TYPE);
}
/* Get the correct notify list type (System or Device) */
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
} else {
handler_list_id = ACPI_DEVICE_HANDLER_LIST;
}
/* Get the notify object attached to the namespace Node */
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
/* We have an attached object, Get the correct handler list */
handler_list_head =
obj_desc->common_notify.notify_list[handler_list_id];
}
/*
* If there is no notify handler (Global or Local)
* for this object, just ignore the notify
*/
if (!acpi_gbl_global_notify[handler_list_id].handler
&& !handler_list_head) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
return (AE_OK);
}
/* Setup notify info and schedule the notify dispatcher */
info = acpi_ut_create_generic_state();
if (!info) {
return (AE_NO_MEMORY);
}
info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
info->notify.node = node;
info->notify.value = (u16)notify_value;
info->notify.handler_list_id = handler_list_id;
info->notify.handler_list_head = handler_list_head;
info->notify.global = &acpi_gbl_global_notify[handler_list_id];
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
node));
status = acpi_os_execute(OSL_NOTIFY_HANDLER,
acpi_ev_notify_dispatch, info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(info);
}
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_ev_notify_dispatch
*
* PARAMETERS: context - To be passed to the notify handler
*
* RETURN: None.
*
* DESCRIPTION: Dispatch a device notification event to a previously
* installed handler.
*
******************************************************************************/
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
{
union acpi_generic_state *info = (union acpi_generic_state *)context;
union acpi_operand_object *handler_obj;
ACPI_FUNCTION_ENTRY();
/* Invoke a global notify handler if installed */
if (info->notify.global->handler) {
info->notify.global->handler(info->notify.node,
info->notify.value,
info->notify.global->context);
}
/* Now invoke the local notify handler(s) if any are installed */
handler_obj = info->notify.handler_list_head;
while (handler_obj) {
handler_obj->notify.handler(info->notify.node,
info->notify.value,
handler_obj->notify.context);
handler_obj =
handler_obj->notify.next[info->notify.handler_list_id];
}
/* All done with the info object */
acpi_ut_delete_generic_state(info);
}
#if (!ACPI_REDUCED_HARDWARE)
/******************************************************************************
*
* FUNCTION: acpi_ev_terminate
*
* PARAMETERS: none
*
* RETURN: none
*
* DESCRIPTION: Disable events and free memory allocated for table storage.
*
******************************************************************************/
void acpi_ev_terminate(void)
{
u32 i;
acpi_status status;
ACPI_FUNCTION_TRACE(ev_terminate);
if (acpi_gbl_events_initialized) {
/*
* Disable all event-related functionality. In all cases, on error,
* print a message but obviously we don't abort.
*/
/* Disable all fixed events */
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
status = acpi_disable_event(i, 0);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not disable fixed event %u",
(u32) i));
}
}
/* Disable all GPEs in all GPE blocks */
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
status = acpi_ev_remove_global_lock_handler();
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not remove Global Lock handler"));
}
acpi_gbl_events_initialized = FALSE;
}
/* Remove SCI handlers */
status = acpi_ev_remove_all_sci_handlers();
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
}
/* Deallocate all handler objects installed within GPE info structs */
status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
/* Return to original mode if necessary */
if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
status = acpi_disable();
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
}
}
return_VOID;
}
#endif /* !ACPI_REDUCED_HARDWARE */
|