1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
4 * Module Name: evmisc - Miscellaneous event manager support functions
6 * Copyright (C) 2000 - 2020, Intel Corp.
8 *****************************************************************************/
10 #include <acpi/acpi.h>
15 #define _COMPONENT ACPI_EVENTS
16 ACPI_MODULE_NAME("evmisc")
18 /* Local prototypes */
19 static void ACPI_SYSTEM_XFACE
acpi_ev_notify_dispatch(void *context
);
21 /*******************************************************************************
23 * FUNCTION: acpi_ev_is_notify_object
25 * PARAMETERS: node - Node to check
27 * RETURN: TRUE if notifies allowed on this object
29 * DESCRIPTION: Check type of node for a object that supports notifies.
31 * TBD: This could be replaced by a flag bit in the node.
33 ******************************************************************************/
35 u8
acpi_ev_is_notify_object(struct acpi_namespace_node
*node
)
39 case ACPI_TYPE_DEVICE
:
40 case ACPI_TYPE_PROCESSOR
:
41 case ACPI_TYPE_THERMAL
:
43 * These are the ONLY objects that can receive ACPI notifications
53 /*******************************************************************************
55 * FUNCTION: acpi_ev_queue_notify_request
57 * PARAMETERS: node - NS node for the notified object
58 * notify_value - Value from the Notify() request
62 * DESCRIPTION: Dispatch a device notification event to a previously
65 ******************************************************************************/
68 acpi_ev_queue_notify_request(struct acpi_namespace_node
*node
, u32 notify_value
)
70 union acpi_operand_object
*obj_desc
;
71 union acpi_operand_object
*handler_list_head
= NULL
;
72 union acpi_generic_state
*info
;
73 u8 handler_list_id
= 0;
74 acpi_status status
= AE_OK
;
76 ACPI_FUNCTION_NAME(ev_queue_notify_request
);
78 /* Are Notifies allowed on this object? */
80 if (!acpi_ev_is_notify_object(node
)) {
84 /* Get the correct notify list type (System or Device) */
86 if (notify_value
<= ACPI_MAX_SYS_NOTIFY
) {
87 handler_list_id
= ACPI_SYSTEM_HANDLER_LIST
;
89 handler_list_id
= ACPI_DEVICE_HANDLER_LIST
;
92 /* Get the notify object attached to the namespace Node */
94 obj_desc
= acpi_ns_get_attached_object(node
);
97 /* We have an attached object, Get the correct handler list */
100 obj_desc
->common_notify
.notify_list
[handler_list_id
];
104 * If there is no notify handler (Global or Local)
105 * for this object, just ignore the notify
107 if (!acpi_gbl_global_notify
[handler_list_id
].handler
108 && !handler_list_head
) {
109 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
110 "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
111 acpi_ut_get_node_name(node
), notify_value
,
117 /* Setup notify info and schedule the notify dispatcher */
119 info
= acpi_ut_create_generic_state();
121 return (AE_NO_MEMORY
);
124 info
->common
.descriptor_type
= ACPI_DESC_TYPE_STATE_NOTIFY
;
126 info
->notify
.node
= node
;
127 info
->notify
.value
= (u16
)notify_value
;
128 info
->notify
.handler_list_id
= handler_list_id
;
129 info
->notify
.handler_list_head
= handler_list_head
;
130 info
->notify
.global
= &acpi_gbl_global_notify
[handler_list_id
];
132 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
133 "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
134 acpi_ut_get_node_name(node
),
135 acpi_ut_get_type_name(node
->type
), notify_value
,
136 acpi_ut_get_notify_name(notify_value
, ACPI_TYPE_ANY
),
139 status
= acpi_os_execute(OSL_NOTIFY_HANDLER
,
140 acpi_ev_notify_dispatch
, info
);
141 if (ACPI_FAILURE(status
)) {
142 acpi_ut_delete_generic_state(info
);
148 /*******************************************************************************
150 * FUNCTION: acpi_ev_notify_dispatch
152 * PARAMETERS: context - To be passed to the notify handler
156 * DESCRIPTION: Dispatch a device notification event to a previously
159 ******************************************************************************/
161 static void ACPI_SYSTEM_XFACE
acpi_ev_notify_dispatch(void *context
)
163 union acpi_generic_state
*info
= (union acpi_generic_state
*)context
;
164 union acpi_operand_object
*handler_obj
;
166 ACPI_FUNCTION_ENTRY();
168 /* Invoke a global notify handler if installed */
170 if (info
->notify
.global
->handler
) {
171 info
->notify
.global
->handler(info
->notify
.node
,
173 info
->notify
.global
->context
);
176 /* Now invoke the local notify handler(s) if any are installed */
178 handler_obj
= info
->notify
.handler_list_head
;
179 while (handler_obj
) {
180 handler_obj
->notify
.handler(info
->notify
.node
,
182 handler_obj
->notify
.context
);
185 handler_obj
->notify
.next
[info
->notify
.handler_list_id
];
188 /* All done with the info object */
190 acpi_ut_delete_generic_state(info
);
193 #if (!ACPI_REDUCED_HARDWARE)
194 /******************************************************************************
196 * FUNCTION: acpi_ev_terminate
202 * DESCRIPTION: Disable events and free memory allocated for table storage.
204 ******************************************************************************/
206 void acpi_ev_terminate(void)
211 ACPI_FUNCTION_TRACE(ev_terminate
);
213 if (acpi_gbl_events_initialized
) {
215 * Disable all event-related functionality. In all cases, on error,
216 * print a message but obviously we don't abort.
219 /* Disable all fixed events */
221 for (i
= 0; i
< ACPI_NUM_FIXED_EVENTS
; i
++) {
222 status
= acpi_disable_event(i
, 0);
223 if (ACPI_FAILURE(status
)) {
225 "Could not disable fixed event %u",
230 /* Disable all GPEs in all GPE blocks */
232 status
= acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block
, NULL
);
233 if (ACPI_FAILURE(status
)) {
234 ACPI_EXCEPTION((AE_INFO
, status
,
235 "Could not disable GPEs in GPE block"));
238 status
= acpi_ev_remove_global_lock_handler();
239 if (ACPI_FAILURE(status
)) {
240 ACPI_EXCEPTION((AE_INFO
, status
,
241 "Could not remove Global Lock handler"));
244 acpi_gbl_events_initialized
= FALSE
;
247 /* Remove SCI handlers */
249 status
= acpi_ev_remove_all_sci_handlers();
250 if (ACPI_FAILURE(status
)) {
251 ACPI_ERROR((AE_INFO
, "Could not remove SCI handler"));
254 /* Deallocate all handler objects installed within GPE info structs */
256 status
= acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers
, NULL
);
257 if (ACPI_FAILURE(status
)) {
258 ACPI_EXCEPTION((AE_INFO
, status
,
259 "Could not delete GPE handlers"));
262 /* Return to original mode if necessary */
264 if (acpi_gbl_original_mode
== ACPI_SYS_MODE_LEGACY
) {
265 status
= acpi_disable();
266 if (ACPI_FAILURE(status
)) {
267 ACPI_WARNING((AE_INFO
, "AcpiDisable failed"));
273 #endif /* !ACPI_REDUCED_HARDWARE */