1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Module Name: evxface - External interfaces for ACPI events
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun *****************************************************************************/
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define EXPORT_ACPI_INTERFACES
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <acpi/acpi.h>
13*4882a593Smuzhiyun #include "accommon.h"
14*4882a593Smuzhiyun #include "acnamesp.h"
15*4882a593Smuzhiyun #include "acevents.h"
16*4882a593Smuzhiyun #include "acinterp.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define _COMPONENT ACPI_EVENTS
19*4882a593Smuzhiyun ACPI_MODULE_NAME("evxface")
20*4882a593Smuzhiyun #if (!ACPI_REDUCED_HARDWARE)
21*4882a593Smuzhiyun /* Local prototypes */
22*4882a593Smuzhiyun static acpi_status
23*4882a593Smuzhiyun acpi_ev_install_gpe_handler(acpi_handle gpe_device,
24*4882a593Smuzhiyun u32 gpe_number,
25*4882a593Smuzhiyun u32 type,
26*4882a593Smuzhiyun u8 is_raw_handler,
27*4882a593Smuzhiyun acpi_gpe_handler address, void *context);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #endif
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /*******************************************************************************
33*4882a593Smuzhiyun *
34*4882a593Smuzhiyun * FUNCTION: acpi_install_notify_handler
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * PARAMETERS: device - The device for which notifies will be handled
37*4882a593Smuzhiyun * handler_type - The type of handler:
38*4882a593Smuzhiyun * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
39*4882a593Smuzhiyun * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
40*4882a593Smuzhiyun * ACPI_ALL_NOTIFY: Both System and Device
41*4882a593Smuzhiyun * handler - Address of the handler
42*4882a593Smuzhiyun * context - Value passed to the handler on each GPE
43*4882a593Smuzhiyun *
44*4882a593Smuzhiyun * RETURN: Status
45*4882a593Smuzhiyun *
46*4882a593Smuzhiyun * DESCRIPTION: Install a handler for notifications on an ACPI Device,
47*4882a593Smuzhiyun * thermal_zone, or Processor object.
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * NOTES: The Root namespace object may have only one handler for each
50*4882a593Smuzhiyun * type of notify (System/Device). Device/Thermal/Processor objects
51*4882a593Smuzhiyun * may have one device notify handler, and multiple system notify
52*4882a593Smuzhiyun * handlers.
53*4882a593Smuzhiyun *
54*4882a593Smuzhiyun ******************************************************************************/
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun acpi_status
acpi_install_notify_handler(acpi_handle device,u32 handler_type,acpi_notify_handler handler,void * context)57*4882a593Smuzhiyun acpi_install_notify_handler(acpi_handle device,
58*4882a593Smuzhiyun u32 handler_type,
59*4882a593Smuzhiyun acpi_notify_handler handler, void *context)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct acpi_namespace_node *node =
62*4882a593Smuzhiyun ACPI_CAST_PTR(struct acpi_namespace_node, device);
63*4882a593Smuzhiyun union acpi_operand_object *obj_desc;
64*4882a593Smuzhiyun union acpi_operand_object *handler_obj;
65*4882a593Smuzhiyun acpi_status status;
66*4882a593Smuzhiyun u32 i;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* Parameter validation */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if ((!device) || (!handler) || (!handler_type) ||
73*4882a593Smuzhiyun (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
74*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
78*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
79*4882a593Smuzhiyun return_ACPI_STATUS(status);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /*
83*4882a593Smuzhiyun * Root Object:
84*4882a593Smuzhiyun * Registering a notify handler on the root object indicates that the
85*4882a593Smuzhiyun * caller wishes to receive notifications for all objects. Note that
86*4882a593Smuzhiyun * only one global handler can be registered per notify type.
87*4882a593Smuzhiyun * Ensure that a handler is not already installed.
88*4882a593Smuzhiyun */
89*4882a593Smuzhiyun if (device == ACPI_ROOT_OBJECT) {
90*4882a593Smuzhiyun for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
91*4882a593Smuzhiyun if (handler_type & (i + 1)) {
92*4882a593Smuzhiyun if (acpi_gbl_global_notify[i].handler) {
93*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
94*4882a593Smuzhiyun goto unlock_and_exit;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun acpi_gbl_global_notify[i].handler = handler;
98*4882a593Smuzhiyun acpi_gbl_global_notify[i].context = context;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun goto unlock_and_exit; /* Global notify handler installed, all done */
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /*
106*4882a593Smuzhiyun * All Other Objects:
107*4882a593Smuzhiyun * Caller will only receive notifications specific to the target
108*4882a593Smuzhiyun * object. Note that only certain object types are allowed to
109*4882a593Smuzhiyun * receive notifications.
110*4882a593Smuzhiyun */
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Are Notifies allowed on this object? */
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (!acpi_ev_is_notify_object(node)) {
115*4882a593Smuzhiyun status = AE_TYPE;
116*4882a593Smuzhiyun goto unlock_and_exit;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /* Check for an existing internal object, might not exist */
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun obj_desc = acpi_ns_get_attached_object(node);
122*4882a593Smuzhiyun if (!obj_desc) {
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* Create a new object */
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun obj_desc = acpi_ut_create_internal_object(node->type);
127*4882a593Smuzhiyun if (!obj_desc) {
128*4882a593Smuzhiyun status = AE_NO_MEMORY;
129*4882a593Smuzhiyun goto unlock_and_exit;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* Attach new object to the Node, remove local reference */
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun status = acpi_ns_attach_object(device, obj_desc, node->type);
135*4882a593Smuzhiyun acpi_ut_remove_reference(obj_desc);
136*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
137*4882a593Smuzhiyun goto unlock_and_exit;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* Ensure that the handler is not already installed in the lists */
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
144*4882a593Smuzhiyun if (handler_type & (i + 1)) {
145*4882a593Smuzhiyun handler_obj = obj_desc->common_notify.notify_list[i];
146*4882a593Smuzhiyun while (handler_obj) {
147*4882a593Smuzhiyun if (handler_obj->notify.handler == handler) {
148*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
149*4882a593Smuzhiyun goto unlock_and_exit;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun handler_obj = handler_obj->notify.next[i];
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Create and populate a new notify handler object */
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
160*4882a593Smuzhiyun if (!handler_obj) {
161*4882a593Smuzhiyun status = AE_NO_MEMORY;
162*4882a593Smuzhiyun goto unlock_and_exit;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun handler_obj->notify.node = node;
166*4882a593Smuzhiyun handler_obj->notify.handler_type = handler_type;
167*4882a593Smuzhiyun handler_obj->notify.handler = handler;
168*4882a593Smuzhiyun handler_obj->notify.context = context;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* Install the handler at the list head(s) */
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
173*4882a593Smuzhiyun if (handler_type & (i + 1)) {
174*4882a593Smuzhiyun handler_obj->notify.next[i] =
175*4882a593Smuzhiyun obj_desc->common_notify.notify_list[i];
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun obj_desc->common_notify.notify_list[i] = handler_obj;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* Add an extra reference if handler was installed in both lists */
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (handler_type == ACPI_ALL_NOTIFY) {
184*4882a593Smuzhiyun acpi_ut_add_reference(handler_obj);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun unlock_and_exit:
188*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
189*4882a593Smuzhiyun return_ACPI_STATUS(status);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)192*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /*******************************************************************************
195*4882a593Smuzhiyun *
196*4882a593Smuzhiyun * FUNCTION: acpi_remove_notify_handler
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * PARAMETERS: device - The device for which the handler is installed
199*4882a593Smuzhiyun * handler_type - The type of handler:
200*4882a593Smuzhiyun * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
201*4882a593Smuzhiyun * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
202*4882a593Smuzhiyun * ACPI_ALL_NOTIFY: Both System and Device
203*4882a593Smuzhiyun * handler - Address of the handler
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * RETURN: Status
206*4882a593Smuzhiyun *
207*4882a593Smuzhiyun * DESCRIPTION: Remove a handler for notifies on an ACPI device
208*4882a593Smuzhiyun *
209*4882a593Smuzhiyun ******************************************************************************/
210*4882a593Smuzhiyun acpi_status
211*4882a593Smuzhiyun acpi_remove_notify_handler(acpi_handle device,
212*4882a593Smuzhiyun u32 handler_type, acpi_notify_handler handler)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun struct acpi_namespace_node *node =
215*4882a593Smuzhiyun ACPI_CAST_PTR(struct acpi_namespace_node, device);
216*4882a593Smuzhiyun union acpi_operand_object *obj_desc;
217*4882a593Smuzhiyun union acpi_operand_object *handler_obj;
218*4882a593Smuzhiyun union acpi_operand_object *previous_handler_obj;
219*4882a593Smuzhiyun acpi_status status = AE_OK;
220*4882a593Smuzhiyun u32 i;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* Parameter validation */
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if ((!device) || (!handler) || (!handler_type) ||
227*4882a593Smuzhiyun (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
228*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* Root Object. Global handlers are removed here */
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (device == ACPI_ROOT_OBJECT) {
234*4882a593Smuzhiyun for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
235*4882a593Smuzhiyun if (handler_type & (i + 1)) {
236*4882a593Smuzhiyun status =
237*4882a593Smuzhiyun acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
238*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
239*4882a593Smuzhiyun return_ACPI_STATUS(status);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun if (!acpi_gbl_global_notify[i].handler ||
243*4882a593Smuzhiyun (acpi_gbl_global_notify[i].handler !=
244*4882a593Smuzhiyun handler)) {
245*4882a593Smuzhiyun status = AE_NOT_EXIST;
246*4882a593Smuzhiyun goto unlock_and_exit;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun ACPI_DEBUG_PRINT((ACPI_DB_INFO,
250*4882a593Smuzhiyun "Removing global notify handler\n"));
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun acpi_gbl_global_notify[i].handler = NULL;
253*4882a593Smuzhiyun acpi_gbl_global_notify[i].context = NULL;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* Make sure all deferred notify tasks are completed */
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun acpi_os_wait_events_complete();
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun return_ACPI_STATUS(AE_OK);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* All other objects: Are Notifies allowed on this object? */
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if (!acpi_ev_is_notify_object(node)) {
269*4882a593Smuzhiyun return_ACPI_STATUS(AE_TYPE);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* Must have an existing internal object */
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun obj_desc = acpi_ns_get_attached_object(node);
275*4882a593Smuzhiyun if (!obj_desc) {
276*4882a593Smuzhiyun return_ACPI_STATUS(AE_NOT_EXIST);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Internal object exists. Find the handler and remove it */
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
282*4882a593Smuzhiyun if (handler_type & (i + 1)) {
283*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
284*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
285*4882a593Smuzhiyun return_ACPI_STATUS(status);
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun handler_obj = obj_desc->common_notify.notify_list[i];
289*4882a593Smuzhiyun previous_handler_obj = NULL;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /* Attempt to find the handler in the handler list */
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun while (handler_obj &&
294*4882a593Smuzhiyun (handler_obj->notify.handler != handler)) {
295*4882a593Smuzhiyun previous_handler_obj = handler_obj;
296*4882a593Smuzhiyun handler_obj = handler_obj->notify.next[i];
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (!handler_obj) {
300*4882a593Smuzhiyun status = AE_NOT_EXIST;
301*4882a593Smuzhiyun goto unlock_and_exit;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* Remove the handler object from the list */
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (previous_handler_obj) { /* Handler is not at the list head */
307*4882a593Smuzhiyun previous_handler_obj->notify.next[i] =
308*4882a593Smuzhiyun handler_obj->notify.next[i];
309*4882a593Smuzhiyun } else { /* Handler is at the list head */
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun obj_desc->common_notify.notify_list[i] =
312*4882a593Smuzhiyun handler_obj->notify.next[i];
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Make sure all deferred notify tasks are completed */
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun acpi_os_wait_events_complete();
320*4882a593Smuzhiyun acpi_ut_remove_reference(handler_obj);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return_ACPI_STATUS(status);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun unlock_and_exit:
327*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
328*4882a593Smuzhiyun return_ACPI_STATUS(status);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)331*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /*******************************************************************************
334*4882a593Smuzhiyun *
335*4882a593Smuzhiyun * FUNCTION: acpi_install_exception_handler
336*4882a593Smuzhiyun *
337*4882a593Smuzhiyun * PARAMETERS: handler - Pointer to the handler function for the
338*4882a593Smuzhiyun * event
339*4882a593Smuzhiyun *
340*4882a593Smuzhiyun * RETURN: Status
341*4882a593Smuzhiyun *
342*4882a593Smuzhiyun * DESCRIPTION: Saves the pointer to the handler function
343*4882a593Smuzhiyun *
344*4882a593Smuzhiyun ******************************************************************************/
345*4882a593Smuzhiyun #ifdef ACPI_FUTURE_USAGE
346*4882a593Smuzhiyun acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun acpi_status status;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
353*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
354*4882a593Smuzhiyun return_ACPI_STATUS(status);
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* Don't allow two handlers. */
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (acpi_gbl_exception_handler) {
360*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
361*4882a593Smuzhiyun goto cleanup;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* Install the handler */
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun acpi_gbl_exception_handler = handler;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun cleanup:
369*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
370*4882a593Smuzhiyun return_ACPI_STATUS(status);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)373*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
374*4882a593Smuzhiyun #endif
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun #if (!ACPI_REDUCED_HARDWARE)
377*4882a593Smuzhiyun /*******************************************************************************
378*4882a593Smuzhiyun *
379*4882a593Smuzhiyun * FUNCTION: acpi_install_sci_handler
380*4882a593Smuzhiyun *
381*4882a593Smuzhiyun * PARAMETERS: address - Address of the handler
382*4882a593Smuzhiyun * context - Value passed to the handler on each SCI
383*4882a593Smuzhiyun *
384*4882a593Smuzhiyun * RETURN: Status
385*4882a593Smuzhiyun *
386*4882a593Smuzhiyun * DESCRIPTION: Install a handler for a System Control Interrupt.
387*4882a593Smuzhiyun *
388*4882a593Smuzhiyun ******************************************************************************/
389*4882a593Smuzhiyun acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun struct acpi_sci_handler_info *new_sci_handler;
392*4882a593Smuzhiyun struct acpi_sci_handler_info *sci_handler;
393*4882a593Smuzhiyun acpi_cpu_flags flags;
394*4882a593Smuzhiyun acpi_status status;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_sci_handler);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (!address) {
399*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun /* Allocate and init a handler object */
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info));
405*4882a593Smuzhiyun if (!new_sci_handler) {
406*4882a593Smuzhiyun return_ACPI_STATUS(AE_NO_MEMORY);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun new_sci_handler->address = address;
410*4882a593Smuzhiyun new_sci_handler->context = context;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
413*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
414*4882a593Smuzhiyun goto exit;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* Lock list during installation */
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
420*4882a593Smuzhiyun sci_handler = acpi_gbl_sci_handler_list;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun /* Ensure handler does not already exist */
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun while (sci_handler) {
425*4882a593Smuzhiyun if (address == sci_handler->address) {
426*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
427*4882a593Smuzhiyun goto unlock_and_exit;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun sci_handler = sci_handler->next;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun /* Install the new handler into the global list (at head) */
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun new_sci_handler->next = acpi_gbl_sci_handler_list;
436*4882a593Smuzhiyun acpi_gbl_sci_handler_list = new_sci_handler;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun unlock_and_exit:
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
441*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun exit:
444*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
445*4882a593Smuzhiyun ACPI_FREE(new_sci_handler);
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun return_ACPI_STATUS(status);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)450*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /*******************************************************************************
453*4882a593Smuzhiyun *
454*4882a593Smuzhiyun * FUNCTION: acpi_remove_sci_handler
455*4882a593Smuzhiyun *
456*4882a593Smuzhiyun * PARAMETERS: address - Address of the handler
457*4882a593Smuzhiyun *
458*4882a593Smuzhiyun * RETURN: Status
459*4882a593Smuzhiyun *
460*4882a593Smuzhiyun * DESCRIPTION: Remove a handler for a System Control Interrupt.
461*4882a593Smuzhiyun *
462*4882a593Smuzhiyun ******************************************************************************/
463*4882a593Smuzhiyun acpi_status acpi_remove_sci_handler(acpi_sci_handler address)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct acpi_sci_handler_info *prev_sci_handler;
466*4882a593Smuzhiyun struct acpi_sci_handler_info *next_sci_handler;
467*4882a593Smuzhiyun acpi_cpu_flags flags;
468*4882a593Smuzhiyun acpi_status status;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_remove_sci_handler);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (!address) {
473*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
477*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
478*4882a593Smuzhiyun return_ACPI_STATUS(status);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun /* Remove the SCI handler with lock */
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun prev_sci_handler = NULL;
486*4882a593Smuzhiyun next_sci_handler = acpi_gbl_sci_handler_list;
487*4882a593Smuzhiyun while (next_sci_handler) {
488*4882a593Smuzhiyun if (next_sci_handler->address == address) {
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun /* Unlink and free the SCI handler info block */
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun if (prev_sci_handler) {
493*4882a593Smuzhiyun prev_sci_handler->next = next_sci_handler->next;
494*4882a593Smuzhiyun } else {
495*4882a593Smuzhiyun acpi_gbl_sci_handler_list =
496*4882a593Smuzhiyun next_sci_handler->next;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
500*4882a593Smuzhiyun ACPI_FREE(next_sci_handler);
501*4882a593Smuzhiyun goto unlock_and_exit;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun prev_sci_handler = next_sci_handler;
505*4882a593Smuzhiyun next_sci_handler = next_sci_handler->next;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
509*4882a593Smuzhiyun status = AE_NOT_EXIST;
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun unlock_and_exit:
512*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
513*4882a593Smuzhiyun return_ACPI_STATUS(status);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)516*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*******************************************************************************
519*4882a593Smuzhiyun *
520*4882a593Smuzhiyun * FUNCTION: acpi_install_global_event_handler
521*4882a593Smuzhiyun *
522*4882a593Smuzhiyun * PARAMETERS: handler - Pointer to the global event handler function
523*4882a593Smuzhiyun * context - Value passed to the handler on each event
524*4882a593Smuzhiyun *
525*4882a593Smuzhiyun * RETURN: Status
526*4882a593Smuzhiyun *
527*4882a593Smuzhiyun * DESCRIPTION: Saves the pointer to the handler function. The global handler
528*4882a593Smuzhiyun * is invoked upon each incoming GPE and Fixed Event. It is
529*4882a593Smuzhiyun * invoked at interrupt level at the time of the event dispatch.
530*4882a593Smuzhiyun * Can be used to update event counters, etc.
531*4882a593Smuzhiyun *
532*4882a593Smuzhiyun ******************************************************************************/
533*4882a593Smuzhiyun acpi_status
534*4882a593Smuzhiyun acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun acpi_status status;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun /* Parameter validation */
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (!handler) {
543*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
547*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
548*4882a593Smuzhiyun return_ACPI_STATUS(status);
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /* Don't allow two handlers. */
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (acpi_gbl_global_event_handler) {
554*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
555*4882a593Smuzhiyun goto cleanup;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun acpi_gbl_global_event_handler = handler;
559*4882a593Smuzhiyun acpi_gbl_global_event_handler_context = context;
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun cleanup:
562*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
563*4882a593Smuzhiyun return_ACPI_STATUS(status);
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)566*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun /*******************************************************************************
569*4882a593Smuzhiyun *
570*4882a593Smuzhiyun * FUNCTION: acpi_install_fixed_event_handler
571*4882a593Smuzhiyun *
572*4882a593Smuzhiyun * PARAMETERS: event - Event type to enable.
573*4882a593Smuzhiyun * handler - Pointer to the handler function for the
574*4882a593Smuzhiyun * event
575*4882a593Smuzhiyun * context - Value passed to the handler on each GPE
576*4882a593Smuzhiyun *
577*4882a593Smuzhiyun * RETURN: Status
578*4882a593Smuzhiyun *
579*4882a593Smuzhiyun * DESCRIPTION: Saves the pointer to the handler function and then enables the
580*4882a593Smuzhiyun * event.
581*4882a593Smuzhiyun *
582*4882a593Smuzhiyun ******************************************************************************/
583*4882a593Smuzhiyun acpi_status
584*4882a593Smuzhiyun acpi_install_fixed_event_handler(u32 event,
585*4882a593Smuzhiyun acpi_event_handler handler, void *context)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun acpi_status status;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun /* Parameter validation */
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (event > ACPI_EVENT_MAX) {
594*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
598*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
599*4882a593Smuzhiyun return_ACPI_STATUS(status);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /* Do not allow multiple handlers */
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (acpi_gbl_fixed_event_handlers[event].handler) {
605*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
606*4882a593Smuzhiyun goto cleanup;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /* Install the handler before enabling the event */
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].handler = handler;
612*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].context = context;
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun status = acpi_clear_event(event);
615*4882a593Smuzhiyun if (ACPI_SUCCESS(status))
616*4882a593Smuzhiyun status = acpi_enable_event(event, 0);
617*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
618*4882a593Smuzhiyun ACPI_WARNING((AE_INFO,
619*4882a593Smuzhiyun "Could not enable fixed event - %s (%u)",
620*4882a593Smuzhiyun acpi_ut_get_event_name(event), event));
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun /* Remove the handler */
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].handler = NULL;
625*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].context = NULL;
626*4882a593Smuzhiyun } else {
627*4882a593Smuzhiyun ACPI_DEBUG_PRINT((ACPI_DB_INFO,
628*4882a593Smuzhiyun "Enabled fixed event %s (%X), Handler=%p\n",
629*4882a593Smuzhiyun acpi_ut_get_event_name(event), event,
630*4882a593Smuzhiyun handler));
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun cleanup:
634*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
635*4882a593Smuzhiyun return_ACPI_STATUS(status);
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)638*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun /*******************************************************************************
641*4882a593Smuzhiyun *
642*4882a593Smuzhiyun * FUNCTION: acpi_remove_fixed_event_handler
643*4882a593Smuzhiyun *
644*4882a593Smuzhiyun * PARAMETERS: event - Event type to disable.
645*4882a593Smuzhiyun * handler - Address of the handler
646*4882a593Smuzhiyun *
647*4882a593Smuzhiyun * RETURN: Status
648*4882a593Smuzhiyun *
649*4882a593Smuzhiyun * DESCRIPTION: Disables the event and unregisters the event handler.
650*4882a593Smuzhiyun *
651*4882a593Smuzhiyun ******************************************************************************/
652*4882a593Smuzhiyun acpi_status
653*4882a593Smuzhiyun acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun acpi_status status = AE_OK;
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun /* Parameter validation */
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun if (event > ACPI_EVENT_MAX) {
662*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
666*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
667*4882a593Smuzhiyun return_ACPI_STATUS(status);
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun /* Disable the event before removing the handler */
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun status = acpi_disable_event(event, 0);
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun /* Always Remove the handler */
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].handler = NULL;
677*4882a593Smuzhiyun acpi_gbl_fixed_event_handlers[event].context = NULL;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
680*4882a593Smuzhiyun ACPI_WARNING((AE_INFO,
681*4882a593Smuzhiyun "Could not disable fixed event - %s (%u)",
682*4882a593Smuzhiyun acpi_ut_get_event_name(event), event));
683*4882a593Smuzhiyun } else {
684*4882a593Smuzhiyun ACPI_DEBUG_PRINT((ACPI_DB_INFO,
685*4882a593Smuzhiyun "Disabled fixed event - %s (%X)\n",
686*4882a593Smuzhiyun acpi_ut_get_event_name(event), event));
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
690*4882a593Smuzhiyun return_ACPI_STATUS(status);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)693*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun /*******************************************************************************
696*4882a593Smuzhiyun *
697*4882a593Smuzhiyun * FUNCTION: acpi_ev_install_gpe_handler
698*4882a593Smuzhiyun *
699*4882a593Smuzhiyun * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
700*4882a593Smuzhiyun * defined GPEs)
701*4882a593Smuzhiyun * gpe_number - The GPE number within the GPE block
702*4882a593Smuzhiyun * type - Whether this GPE should be treated as an
703*4882a593Smuzhiyun * edge- or level-triggered interrupt.
704*4882a593Smuzhiyun * is_raw_handler - Whether this GPE should be handled using
705*4882a593Smuzhiyun * the special GPE handler mode.
706*4882a593Smuzhiyun * address - Address of the handler
707*4882a593Smuzhiyun * context - Value passed to the handler on each GPE
708*4882a593Smuzhiyun *
709*4882a593Smuzhiyun * RETURN: Status
710*4882a593Smuzhiyun *
711*4882a593Smuzhiyun * DESCRIPTION: Internal function to install a handler for a General Purpose
712*4882a593Smuzhiyun * Event.
713*4882a593Smuzhiyun *
714*4882a593Smuzhiyun ******************************************************************************/
715*4882a593Smuzhiyun static acpi_status
716*4882a593Smuzhiyun acpi_ev_install_gpe_handler(acpi_handle gpe_device,
717*4882a593Smuzhiyun u32 gpe_number,
718*4882a593Smuzhiyun u32 type,
719*4882a593Smuzhiyun u8 is_raw_handler,
720*4882a593Smuzhiyun acpi_gpe_handler address, void *context)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun struct acpi_gpe_event_info *gpe_event_info;
723*4882a593Smuzhiyun struct acpi_gpe_handler_info *handler;
724*4882a593Smuzhiyun acpi_status status;
725*4882a593Smuzhiyun acpi_cpu_flags flags;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(ev_install_gpe_handler);
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun /* Parameter validation */
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) {
732*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
736*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
737*4882a593Smuzhiyun return_ACPI_STATUS(status);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun /* Allocate and init handler object (before lock) */
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
743*4882a593Smuzhiyun if (!handler) {
744*4882a593Smuzhiyun status = AE_NO_MEMORY;
745*4882a593Smuzhiyun goto unlock_and_exit;
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun /* Ensure that we have a valid GPE number */
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
753*4882a593Smuzhiyun if (!gpe_event_info) {
754*4882a593Smuzhiyun status = AE_BAD_PARAMETER;
755*4882a593Smuzhiyun goto free_and_exit;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /* Make sure that there isn't a handler there already */
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
761*4882a593Smuzhiyun ACPI_GPE_DISPATCH_HANDLER) ||
762*4882a593Smuzhiyun (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
763*4882a593Smuzhiyun ACPI_GPE_DISPATCH_RAW_HANDLER)) {
764*4882a593Smuzhiyun status = AE_ALREADY_EXISTS;
765*4882a593Smuzhiyun goto free_and_exit;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun handler->address = address;
769*4882a593Smuzhiyun handler->context = context;
770*4882a593Smuzhiyun handler->method_node = gpe_event_info->dispatch.method_node;
771*4882a593Smuzhiyun handler->original_flags = (u8)(gpe_event_info->flags &
772*4882a593Smuzhiyun (ACPI_GPE_XRUPT_TYPE_MASK |
773*4882a593Smuzhiyun ACPI_GPE_DISPATCH_MASK));
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /*
776*4882a593Smuzhiyun * If the GPE is associated with a method, it may have been enabled
777*4882a593Smuzhiyun * automatically during initialization, in which case it has to be
778*4882a593Smuzhiyun * disabled now to avoid spurious execution of the handler.
779*4882a593Smuzhiyun */
780*4882a593Smuzhiyun if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
781*4882a593Smuzhiyun ACPI_GPE_DISPATCH_METHOD) ||
782*4882a593Smuzhiyun (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
783*4882a593Smuzhiyun ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) {
784*4882a593Smuzhiyun handler->originally_enabled = TRUE;
785*4882a593Smuzhiyun (void)acpi_ev_remove_gpe_reference(gpe_event_info);
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun /* Sanity check of original type against new type */
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun if (type !=
790*4882a593Smuzhiyun (u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
791*4882a593Smuzhiyun ACPI_WARNING((AE_INFO,
792*4882a593Smuzhiyun "GPE type mismatch (level/edge)"));
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun /* Install the handler */
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun gpe_event_info->dispatch.handler = handler;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun /* Setup up dispatch flags to indicate handler (vs. method/notify) */
801*4882a593Smuzhiyun
802*4882a593Smuzhiyun gpe_event_info->flags &=
803*4882a593Smuzhiyun ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
804*4882a593Smuzhiyun gpe_event_info->flags |=
805*4882a593Smuzhiyun (u8)(type |
806*4882a593Smuzhiyun (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER :
807*4882a593Smuzhiyun ACPI_GPE_DISPATCH_HANDLER));
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun unlock_and_exit:
812*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
813*4882a593Smuzhiyun return_ACPI_STATUS(status);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun free_and_exit:
816*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
817*4882a593Smuzhiyun ACPI_FREE(handler);
818*4882a593Smuzhiyun goto unlock_and_exit;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun /*******************************************************************************
822*4882a593Smuzhiyun *
823*4882a593Smuzhiyun * FUNCTION: acpi_install_gpe_handler
824*4882a593Smuzhiyun *
825*4882a593Smuzhiyun * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
826*4882a593Smuzhiyun * defined GPEs)
827*4882a593Smuzhiyun * gpe_number - The GPE number within the GPE block
828*4882a593Smuzhiyun * type - Whether this GPE should be treated as an
829*4882a593Smuzhiyun * edge- or level-triggered interrupt.
830*4882a593Smuzhiyun * address - Address of the handler
831*4882a593Smuzhiyun * context - Value passed to the handler on each GPE
832*4882a593Smuzhiyun *
833*4882a593Smuzhiyun * RETURN: Status
834*4882a593Smuzhiyun *
835*4882a593Smuzhiyun * DESCRIPTION: Install a handler for a General Purpose Event.
836*4882a593Smuzhiyun *
837*4882a593Smuzhiyun ******************************************************************************/
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,u32 gpe_number,u32 type,acpi_gpe_handler address,void * context)840*4882a593Smuzhiyun acpi_install_gpe_handler(acpi_handle gpe_device,
841*4882a593Smuzhiyun u32 gpe_number,
842*4882a593Smuzhiyun u32 type, acpi_gpe_handler address, void *context)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun acpi_status status;
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
849*4882a593Smuzhiyun FALSE, address, context);
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun return_ACPI_STATUS(status);
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)854*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun /*******************************************************************************
857*4882a593Smuzhiyun *
858*4882a593Smuzhiyun * FUNCTION: acpi_install_gpe_raw_handler
859*4882a593Smuzhiyun *
860*4882a593Smuzhiyun * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
861*4882a593Smuzhiyun * defined GPEs)
862*4882a593Smuzhiyun * gpe_number - The GPE number within the GPE block
863*4882a593Smuzhiyun * type - Whether this GPE should be treated as an
864*4882a593Smuzhiyun * edge- or level-triggered interrupt.
865*4882a593Smuzhiyun * address - Address of the handler
866*4882a593Smuzhiyun * context - Value passed to the handler on each GPE
867*4882a593Smuzhiyun *
868*4882a593Smuzhiyun * RETURN: Status
869*4882a593Smuzhiyun *
870*4882a593Smuzhiyun * DESCRIPTION: Install a handler for a General Purpose Event.
871*4882a593Smuzhiyun *
872*4882a593Smuzhiyun ******************************************************************************/
873*4882a593Smuzhiyun acpi_status
874*4882a593Smuzhiyun acpi_install_gpe_raw_handler(acpi_handle gpe_device,
875*4882a593Smuzhiyun u32 gpe_number,
876*4882a593Smuzhiyun u32 type, acpi_gpe_handler address, void *context)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun acpi_status status;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler);
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
883*4882a593Smuzhiyun TRUE, address, context);
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun return_ACPI_STATUS(status);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)888*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun /*******************************************************************************
891*4882a593Smuzhiyun *
892*4882a593Smuzhiyun * FUNCTION: acpi_remove_gpe_handler
893*4882a593Smuzhiyun *
894*4882a593Smuzhiyun * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
895*4882a593Smuzhiyun * defined GPEs)
896*4882a593Smuzhiyun * gpe_number - The event to remove a handler
897*4882a593Smuzhiyun * address - Address of the handler
898*4882a593Smuzhiyun *
899*4882a593Smuzhiyun * RETURN: Status
900*4882a593Smuzhiyun *
901*4882a593Smuzhiyun * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
902*4882a593Smuzhiyun *
903*4882a593Smuzhiyun ******************************************************************************/
904*4882a593Smuzhiyun acpi_status
905*4882a593Smuzhiyun acpi_remove_gpe_handler(acpi_handle gpe_device,
906*4882a593Smuzhiyun u32 gpe_number, acpi_gpe_handler address)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun struct acpi_gpe_event_info *gpe_event_info;
909*4882a593Smuzhiyun struct acpi_gpe_handler_info *handler;
910*4882a593Smuzhiyun acpi_status status;
911*4882a593Smuzhiyun acpi_cpu_flags flags;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* Parameter validation */
916*4882a593Smuzhiyun
917*4882a593Smuzhiyun if (!address) {
918*4882a593Smuzhiyun return_ACPI_STATUS(AE_BAD_PARAMETER);
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
922*4882a593Smuzhiyun if (ACPI_FAILURE(status)) {
923*4882a593Smuzhiyun return_ACPI_STATUS(status);
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun /* Ensure that we have a valid GPE number */
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
931*4882a593Smuzhiyun if (!gpe_event_info) {
932*4882a593Smuzhiyun status = AE_BAD_PARAMETER;
933*4882a593Smuzhiyun goto unlock_and_exit;
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun /* Make sure that a handler is indeed installed */
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
939*4882a593Smuzhiyun ACPI_GPE_DISPATCH_HANDLER) &&
940*4882a593Smuzhiyun (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
941*4882a593Smuzhiyun ACPI_GPE_DISPATCH_RAW_HANDLER)) {
942*4882a593Smuzhiyun status = AE_NOT_EXIST;
943*4882a593Smuzhiyun goto unlock_and_exit;
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun /* Make sure that the installed handler is the same */
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun if (gpe_event_info->dispatch.handler->address != address) {
949*4882a593Smuzhiyun status = AE_BAD_PARAMETER;
950*4882a593Smuzhiyun goto unlock_and_exit;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun /* Remove the handler */
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun handler = gpe_event_info->dispatch.handler;
956*4882a593Smuzhiyun gpe_event_info->dispatch.handler = NULL;
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun /* Restore Method node (if any), set dispatch flags */
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun gpe_event_info->dispatch.method_node = handler->method_node;
961*4882a593Smuzhiyun gpe_event_info->flags &=
962*4882a593Smuzhiyun ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
963*4882a593Smuzhiyun gpe_event_info->flags |= handler->original_flags;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun /*
966*4882a593Smuzhiyun * If the GPE was previously associated with a method and it was
967*4882a593Smuzhiyun * enabled, it should be enabled at this point to restore the
968*4882a593Smuzhiyun * post-initialization configuration.
969*4882a593Smuzhiyun */
970*4882a593Smuzhiyun if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
971*4882a593Smuzhiyun ACPI_GPE_DISPATCH_METHOD) ||
972*4882a593Smuzhiyun (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
973*4882a593Smuzhiyun ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
974*4882a593Smuzhiyun (void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
975*4882a593Smuzhiyun if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun /* Poll edge triggered GPEs to handle existing events */
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
980*4882a593Smuzhiyun (void)acpi_ev_detect_gpe(gpe_device, gpe_event_info,
981*4882a593Smuzhiyun gpe_number);
982*4882a593Smuzhiyun flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
987*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun /* Make sure all deferred GPE tasks are completed */
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun acpi_os_wait_events_complete();
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun /* Now we can free the handler object */
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun ACPI_FREE(handler);
996*4882a593Smuzhiyun return_ACPI_STATUS(status);
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun unlock_and_exit:
999*4882a593Smuzhiyun acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
1002*4882a593Smuzhiyun return_ACPI_STATUS(status);
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)1005*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun /*******************************************************************************
1008*4882a593Smuzhiyun *
1009*4882a593Smuzhiyun * FUNCTION: acpi_acquire_global_lock
1010*4882a593Smuzhiyun *
1011*4882a593Smuzhiyun * PARAMETERS: timeout - How long the caller is willing to wait
1012*4882a593Smuzhiyun * handle - Where the handle to the lock is returned
1013*4882a593Smuzhiyun * (if acquired)
1014*4882a593Smuzhiyun *
1015*4882a593Smuzhiyun * RETURN: Status
1016*4882a593Smuzhiyun *
1017*4882a593Smuzhiyun * DESCRIPTION: Acquire the ACPI Global Lock
1018*4882a593Smuzhiyun *
1019*4882a593Smuzhiyun * Note: Allows callers with the same thread ID to acquire the global lock
1020*4882a593Smuzhiyun * multiple times. In other words, externally, the behavior of the global lock
1021*4882a593Smuzhiyun * is identical to an AML mutex. On the first acquire, a new handle is
1022*4882a593Smuzhiyun * returned. On any subsequent calls to acquire by the same thread, the same
1023*4882a593Smuzhiyun * handle is returned.
1024*4882a593Smuzhiyun *
1025*4882a593Smuzhiyun ******************************************************************************/
1026*4882a593Smuzhiyun acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun acpi_status status;
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun if (!handle) {
1031*4882a593Smuzhiyun return (AE_BAD_PARAMETER);
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun /* Must lock interpreter to prevent race conditions */
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun acpi_ex_enter_interpreter();
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun status = acpi_ex_acquire_mutex_object(timeout,
1039*4882a593Smuzhiyun acpi_gbl_global_lock_mutex,
1040*4882a593Smuzhiyun acpi_os_get_thread_id());
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun if (ACPI_SUCCESS(status)) {
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun /* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun *handle = acpi_gbl_global_lock_handle;
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun acpi_ex_exit_interpreter();
1050*4882a593Smuzhiyun return (status);
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun
ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)1053*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun /*******************************************************************************
1056*4882a593Smuzhiyun *
1057*4882a593Smuzhiyun * FUNCTION: acpi_release_global_lock
1058*4882a593Smuzhiyun *
1059*4882a593Smuzhiyun * PARAMETERS: handle - Returned from acpi_acquire_global_lock
1060*4882a593Smuzhiyun *
1061*4882a593Smuzhiyun * RETURN: Status
1062*4882a593Smuzhiyun *
1063*4882a593Smuzhiyun * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
1064*4882a593Smuzhiyun *
1065*4882a593Smuzhiyun ******************************************************************************/
1066*4882a593Smuzhiyun acpi_status acpi_release_global_lock(u32 handle)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun acpi_status status;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun if (!handle || (handle != acpi_gbl_global_lock_handle)) {
1071*4882a593Smuzhiyun return (AE_NOT_ACQUIRED);
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
1075*4882a593Smuzhiyun return (status);
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
1079*4882a593Smuzhiyun #endif /* !ACPI_REDUCED_HARDWARE */
1080