blob: 43b33d19cdf9169b751b275fb9466cc9b6fa2811 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2 *
3 * Module Name: evxface - External interfaces for ACPI events
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2005, R. Byron Moore
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <linux/module.h>
45
46#include <acpi/acpi.h>
47#include <acpi/acnamesp.h>
48#include <acpi/acevents.h>
49#include <acpi/acinterp.h>
50
51#define _COMPONENT ACPI_EVENTS
Len Brown4be44fc2005-08-05 00:44:28 -040052ACPI_MODULE_NAME("evxface")
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54/*******************************************************************************
55 *
56 * FUNCTION: acpi_install_exception_handler
57 *
58 * PARAMETERS: Handler - Pointer to the handler function for the
59 * event
60 *
61 * RETURN: Status
62 *
63 * DESCRIPTION: Saves the pointer to the handler function
64 *
65 ******************************************************************************/
66#ifdef ACPI_FUTURE_USAGE
Len Brown4be44fc2005-08-05 00:44:28 -040067acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068{
Len Brown4be44fc2005-08-05 00:44:28 -040069 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Len Brown4be44fc2005-08-05 00:44:28 -040071 ACPI_FUNCTION_TRACE("acpi_install_exception_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Len Brown4be44fc2005-08-05 00:44:28 -040073 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
74 if (ACPI_FAILURE(status)) {
75 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
77
78 /* Don't allow two handlers. */
79
80 if (acpi_gbl_exception_handler) {
81 status = AE_ALREADY_EXISTS;
82 goto cleanup;
83 }
84
85 /* Install the handler */
86
87 acpi_gbl_exception_handler = handler;
88
Len Brown4be44fc2005-08-05 00:44:28 -040089 cleanup:
90 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
91 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092}
Len Brown4be44fc2005-08-05 00:44:28 -040093#endif /* ACPI_FUTURE_USAGE */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95/*******************************************************************************
96 *
97 * FUNCTION: acpi_install_fixed_event_handler
98 *
99 * PARAMETERS: Event - Event type to enable.
100 * Handler - Pointer to the handler function for the
101 * event
102 * Context - Value passed to the handler on each GPE
103 *
104 * RETURN: Status
105 *
106 * DESCRIPTION: Saves the pointer to the handler function and then enables the
107 * event.
108 *
109 ******************************************************************************/
110
111acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400112acpi_install_fixed_event_handler(u32 event,
113 acpi_event_handler handler, void *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Len Brown4be44fc2005-08-05 00:44:28 -0400115 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Len Brown4be44fc2005-08-05 00:44:28 -0400117 ACPI_FUNCTION_TRACE("acpi_install_fixed_event_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119 /* Parameter validation */
120
121 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400122 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 }
124
Len Brown4be44fc2005-08-05 00:44:28 -0400125 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
126 if (ACPI_FAILURE(status)) {
127 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 }
129
130 /* Don't allow two handlers. */
131
132 if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
133 status = AE_ALREADY_EXISTS;
134 goto cleanup;
135 }
136
137 /* Install the handler before enabling the event */
138
139 acpi_gbl_fixed_event_handlers[event].handler = handler;
140 acpi_gbl_fixed_event_handlers[event].context = context;
141
Len Brown4be44fc2005-08-05 00:44:28 -0400142 status = acpi_clear_event(event);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if (ACPI_SUCCESS(status))
Len Brown4be44fc2005-08-05 00:44:28 -0400144 status = acpi_enable_event(event, 0);
145 if (ACPI_FAILURE(status)) {
146 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
147 "Could not enable fixed event.\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 /* Remove the handler */
150
151 acpi_gbl_fixed_event_handlers[event].handler = NULL;
152 acpi_gbl_fixed_event_handlers[event].context = NULL;
Len Brown4be44fc2005-08-05 00:44:28 -0400153 } else {
154 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
155 "Enabled fixed event %X, Handler=%p\n", event,
156 handler));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
158
Len Brown4be44fc2005-08-05 00:44:28 -0400159 cleanup:
160 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
161 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Len Brown4be44fc2005-08-05 00:44:28 -0400164EXPORT_SYMBOL(acpi_install_fixed_event_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166/*******************************************************************************
167 *
168 * FUNCTION: acpi_remove_fixed_event_handler
169 *
170 * PARAMETERS: Event - Event type to disable.
171 * Handler - Address of the handler
172 *
173 * RETURN: Status
174 *
175 * DESCRIPTION: Disables the event and unregisters the event handler.
176 *
177 ******************************************************************************/
178
179acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400180acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
Len Brown4be44fc2005-08-05 00:44:28 -0400182 acpi_status status = AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Len Brown4be44fc2005-08-05 00:44:28 -0400184 ACPI_FUNCTION_TRACE("acpi_remove_fixed_event_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 /* Parameter validation */
187
188 if (event > ACPI_EVENT_MAX) {
Len Brown4be44fc2005-08-05 00:44:28 -0400189 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
191
Len Brown4be44fc2005-08-05 00:44:28 -0400192 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
193 if (ACPI_FAILURE(status)) {
194 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 }
196
197 /* Disable the event before removing the handler */
198
Len Brown4be44fc2005-08-05 00:44:28 -0400199 status = acpi_disable_event(event, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
201 /* Always Remove the handler */
202
203 acpi_gbl_fixed_event_handlers[event].handler = NULL;
204 acpi_gbl_fixed_event_handlers[event].context = NULL;
205
Len Brown4be44fc2005-08-05 00:44:28 -0400206 if (ACPI_FAILURE(status)) {
207 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
208 "Could not write to fixed event enable register.\n"));
209 } else {
210 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X.\n",
211 event));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 }
213
Len Brown4be44fc2005-08-05 00:44:28 -0400214 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
215 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
Len Brown4be44fc2005-08-05 00:44:28 -0400218EXPORT_SYMBOL(acpi_remove_fixed_event_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220/*******************************************************************************
221 *
222 * FUNCTION: acpi_install_notify_handler
223 *
224 * PARAMETERS: Device - The device for which notifies will be handled
225 * handler_type - The type of handler:
226 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
227 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
228 * ACPI_ALL_NOTIFY: both system and device
229 * Handler - Address of the handler
230 * Context - Value passed to the handler on each GPE
231 *
232 * RETURN: Status
233 *
234 * DESCRIPTION: Install a handler for notifies on an ACPI device
235 *
236 ******************************************************************************/
237
238acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400239acpi_install_notify_handler(acpi_handle device,
240 u32 handler_type,
241 acpi_notify_handler handler, void *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242{
Len Brown4be44fc2005-08-05 00:44:28 -0400243 union acpi_operand_object *obj_desc;
244 union acpi_operand_object *notify_obj;
245 struct acpi_namespace_node *node;
246 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Len Brown4be44fc2005-08-05 00:44:28 -0400248 ACPI_FUNCTION_TRACE("acpi_install_notify_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 /* Parameter validation */
251
Len Brown4be44fc2005-08-05 00:44:28 -0400252 if ((!device) ||
253 (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
254 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 }
256
Len Brown4be44fc2005-08-05 00:44:28 -0400257 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
258 if (ACPI_FAILURE(status)) {
259 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
261
262 /* Convert and validate the device handle */
263
Len Brown4be44fc2005-08-05 00:44:28 -0400264 node = acpi_ns_map_handle_to_node(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 if (!node) {
266 status = AE_BAD_PARAMETER;
267 goto unlock_and_exit;
268 }
269
270 /*
271 * Root Object:
272 * Registering a notify handler on the root object indicates that the
273 * caller wishes to receive notifications for all objects. Note that
274 * only one <external> global handler can be regsitered (per notify type).
275 */
276 if (device == ACPI_ROOT_OBJECT) {
277 /* Make sure the handler is not already installed */
278
279 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
Len Brown4be44fc2005-08-05 00:44:28 -0400280 acpi_gbl_system_notify.handler) ||
281 ((handler_type & ACPI_DEVICE_NOTIFY) &&
282 acpi_gbl_device_notify.handler)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 status = AE_ALREADY_EXISTS;
284 goto unlock_and_exit;
285 }
286
287 if (handler_type & ACPI_SYSTEM_NOTIFY) {
Len Brown4be44fc2005-08-05 00:44:28 -0400288 acpi_gbl_system_notify.node = node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 acpi_gbl_system_notify.handler = handler;
290 acpi_gbl_system_notify.context = context;
291 }
292
293 if (handler_type & ACPI_DEVICE_NOTIFY) {
Len Brown4be44fc2005-08-05 00:44:28 -0400294 acpi_gbl_device_notify.node = node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 acpi_gbl_device_notify.handler = handler;
296 acpi_gbl_device_notify.context = context;
297 }
298
299 /* Global notify handler installed */
300 }
301
302 /*
303 * All Other Objects:
304 * Caller will only receive notifications specific to the target object.
305 * Note that only certain object types can receive notifications.
306 */
307 else {
308 /* Notifies allowed on this object? */
309
Len Brown4be44fc2005-08-05 00:44:28 -0400310 if (!acpi_ev_is_notify_object(node)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 status = AE_TYPE;
312 goto unlock_and_exit;
313 }
314
315 /* Check for an existing internal object */
316
Len Brown4be44fc2005-08-05 00:44:28 -0400317 obj_desc = acpi_ns_get_attached_object(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if (obj_desc) {
319 /* Object exists - make sure there's no handler */
320
321 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
Len Brown4be44fc2005-08-05 00:44:28 -0400322 obj_desc->common_notify.system_notify) ||
323 ((handler_type & ACPI_DEVICE_NOTIFY) &&
324 obj_desc->common_notify.device_notify)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 status = AE_ALREADY_EXISTS;
326 goto unlock_and_exit;
327 }
Len Brown4be44fc2005-08-05 00:44:28 -0400328 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 /* Create a new object */
330
Len Brown4be44fc2005-08-05 00:44:28 -0400331 obj_desc = acpi_ut_create_internal_object(node->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 if (!obj_desc) {
333 status = AE_NO_MEMORY;
334 goto unlock_and_exit;
335 }
336
337 /* Attach new object to the Node */
338
Len Brown4be44fc2005-08-05 00:44:28 -0400339 status =
340 acpi_ns_attach_object(device, obj_desc, node->type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 /* Remove local reference to the object */
343
Len Brown4be44fc2005-08-05 00:44:28 -0400344 acpi_ut_remove_reference(obj_desc);
345 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 goto unlock_and_exit;
347 }
348 }
349
350 /* Install the handler */
351
Len Brown4be44fc2005-08-05 00:44:28 -0400352 notify_obj =
353 acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 if (!notify_obj) {
355 status = AE_NO_MEMORY;
356 goto unlock_and_exit;
357 }
358
Len Brown4be44fc2005-08-05 00:44:28 -0400359 notify_obj->notify.node = node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 notify_obj->notify.handler = handler;
361 notify_obj->notify.context = context;
362
363 if (handler_type & ACPI_SYSTEM_NOTIFY) {
364 obj_desc->common_notify.system_notify = notify_obj;
365 }
366
367 if (handler_type & ACPI_DEVICE_NOTIFY) {
368 obj_desc->common_notify.device_notify = notify_obj;
369 }
370
371 if (handler_type == ACPI_ALL_NOTIFY) {
372 /* Extra ref if installed in both */
373
Len Brown4be44fc2005-08-05 00:44:28 -0400374 acpi_ut_add_reference(notify_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 }
376 }
377
Len Brown4be44fc2005-08-05 00:44:28 -0400378 unlock_and_exit:
379 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
380 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382
Len Brown4be44fc2005-08-05 00:44:28 -0400383EXPORT_SYMBOL(acpi_install_notify_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385/*******************************************************************************
386 *
387 * FUNCTION: acpi_remove_notify_handler
388 *
389 * PARAMETERS: Device - The device for which notifies will be handled
390 * handler_type - The type of handler:
391 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
392 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
393 * ACPI_ALL_NOTIFY: both system and device
394 * Handler - Address of the handler
395 *
396 * RETURN: Status
397 *
398 * DESCRIPTION: Remove a handler for notifies on an ACPI device
399 *
400 ******************************************************************************/
401
402acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400403acpi_remove_notify_handler(acpi_handle device,
404 u32 handler_type, acpi_notify_handler handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405{
Len Brown4be44fc2005-08-05 00:44:28 -0400406 union acpi_operand_object *notify_obj;
407 union acpi_operand_object *obj_desc;
408 struct acpi_namespace_node *node;
409 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Len Brown4be44fc2005-08-05 00:44:28 -0400411 ACPI_FUNCTION_TRACE("acpi_remove_notify_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413 /* Parameter validation */
414
Len Brown4be44fc2005-08-05 00:44:28 -0400415 if ((!device) ||
416 (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
417 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419
Len Brown4be44fc2005-08-05 00:44:28 -0400420 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
421 if (ACPI_FAILURE(status)) {
422 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 }
424
425 /* Convert and validate the device handle */
426
Len Brown4be44fc2005-08-05 00:44:28 -0400427 node = acpi_ns_map_handle_to_node(device);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 if (!node) {
429 status = AE_BAD_PARAMETER;
430 goto unlock_and_exit;
431 }
432
433 /* Root Object */
434
435 if (device == ACPI_ROOT_OBJECT) {
Len Brown4be44fc2005-08-05 00:44:28 -0400436 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
437 "Removing notify handler for ROOT object.\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438
439 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
Len Brown4be44fc2005-08-05 00:44:28 -0400440 !acpi_gbl_system_notify.handler) ||
441 ((handler_type & ACPI_DEVICE_NOTIFY) &&
442 !acpi_gbl_device_notify.handler)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 status = AE_NOT_EXIST;
444 goto unlock_and_exit;
445 }
446
447 /* Make sure all deferred tasks are completed */
448
Len Brown4be44fc2005-08-05 00:44:28 -0400449 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 acpi_os_wait_events_complete(NULL);
Len Brown4be44fc2005-08-05 00:44:28 -0400451 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
452 if (ACPI_FAILURE(status)) {
453 return_ACPI_STATUS(status);
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 if (handler_type & ACPI_SYSTEM_NOTIFY) {
Len Brown4be44fc2005-08-05 00:44:28 -0400457 acpi_gbl_system_notify.node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 acpi_gbl_system_notify.handler = NULL;
459 acpi_gbl_system_notify.context = NULL;
460 }
461
462 if (handler_type & ACPI_DEVICE_NOTIFY) {
Len Brown4be44fc2005-08-05 00:44:28 -0400463 acpi_gbl_device_notify.node = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 acpi_gbl_device_notify.handler = NULL;
465 acpi_gbl_device_notify.context = NULL;
466 }
467 }
468
469 /* All Other Objects */
470
471 else {
472 /* Notifies allowed on this object? */
473
Len Brown4be44fc2005-08-05 00:44:28 -0400474 if (!acpi_ev_is_notify_object(node)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 status = AE_TYPE;
476 goto unlock_and_exit;
477 }
478
479 /* Check for an existing internal object */
480
Len Brown4be44fc2005-08-05 00:44:28 -0400481 obj_desc = acpi_ns_get_attached_object(node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (!obj_desc) {
483 status = AE_NOT_EXIST;
484 goto unlock_and_exit;
485 }
486
487 /* Object exists - make sure there's an existing handler */
488
489 if (handler_type & ACPI_SYSTEM_NOTIFY) {
490 notify_obj = obj_desc->common_notify.system_notify;
491 if ((!notify_obj) ||
Len Brown4be44fc2005-08-05 00:44:28 -0400492 (notify_obj->notify.handler != handler)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 status = AE_BAD_PARAMETER;
494 goto unlock_and_exit;
495 }
496 /* Make sure all deferred tasks are completed */
497
Len Brown4be44fc2005-08-05 00:44:28 -0400498 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 acpi_os_wait_events_complete(NULL);
Len Brown4be44fc2005-08-05 00:44:28 -0400500 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
501 if (ACPI_FAILURE(status)) {
502 return_ACPI_STATUS(status);
503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 /* Remove the handler */
506 obj_desc->common_notify.system_notify = NULL;
Len Brown4be44fc2005-08-05 00:44:28 -0400507 acpi_ut_remove_reference(notify_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 }
509
510 if (handler_type & ACPI_DEVICE_NOTIFY) {
511 notify_obj = obj_desc->common_notify.device_notify;
512 if ((!notify_obj) ||
Len Brown4be44fc2005-08-05 00:44:28 -0400513 (notify_obj->notify.handler != handler)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 status = AE_BAD_PARAMETER;
515 goto unlock_and_exit;
516 }
517 /* Make sure all deferred tasks are completed */
518
Len Brown4be44fc2005-08-05 00:44:28 -0400519 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 acpi_os_wait_events_complete(NULL);
Len Brown4be44fc2005-08-05 00:44:28 -0400521 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
522 if (ACPI_FAILURE(status)) {
523 return_ACPI_STATUS(status);
524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 /* Remove the handler */
527 obj_desc->common_notify.device_notify = NULL;
Len Brown4be44fc2005-08-05 00:44:28 -0400528 acpi_ut_remove_reference(notify_obj);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
530 }
531
Len Brown4be44fc2005-08-05 00:44:28 -0400532 unlock_and_exit:
533 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
534 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
Len Brown4be44fc2005-08-05 00:44:28 -0400537EXPORT_SYMBOL(acpi_remove_notify_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539/*******************************************************************************
540 *
541 * FUNCTION: acpi_install_gpe_handler
542 *
Robert Moore44f6c012005-04-18 22:49:35 -0400543 * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
544 * defined GPEs)
545 * gpe_number - The GPE number within the GPE block
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 * Type - Whether this GPE should be treated as an
547 * edge- or level-triggered interrupt.
548 * Address - Address of the handler
549 * Context - Value passed to the handler on each GPE
550 *
551 * RETURN: Status
552 *
553 * DESCRIPTION: Install a handler for a General Purpose Event.
554 *
555 ******************************************************************************/
556
557acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400558acpi_install_gpe_handler(acpi_handle gpe_device,
559 u32 gpe_number,
560 u32 type, acpi_event_handler address, void *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
Len Brown4be44fc2005-08-05 00:44:28 -0400562 struct acpi_gpe_event_info *gpe_event_info;
563 struct acpi_handler_info *handler;
564 acpi_status status;
565 u32 flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566
Len Brown4be44fc2005-08-05 00:44:28 -0400567 ACPI_FUNCTION_TRACE("acpi_install_gpe_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 /* Parameter validation */
570
571 if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400572 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 }
574
Len Brown4be44fc2005-08-05 00:44:28 -0400575 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
576 if (ACPI_FAILURE(status)) {
577 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579
580 /* Ensure that we have a valid GPE number */
581
Len Brown4be44fc2005-08-05 00:44:28 -0400582 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (!gpe_event_info) {
584 status = AE_BAD_PARAMETER;
585 goto unlock_and_exit;
586 }
587
588 /* Make sure that there isn't a handler there already */
589
Len Brown4be44fc2005-08-05 00:44:28 -0400590 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
591 ACPI_GPE_DISPATCH_HANDLER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 status = AE_ALREADY_EXISTS;
593 goto unlock_and_exit;
594 }
595
596 /* Allocate and init handler object */
597
Len Brown4be44fc2005-08-05 00:44:28 -0400598 handler = ACPI_MEM_CALLOCATE(sizeof(struct acpi_handler_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 if (!handler) {
600 status = AE_NO_MEMORY;
601 goto unlock_and_exit;
602 }
603
Len Brown4be44fc2005-08-05 00:44:28 -0400604 handler->address = address;
605 handler->context = context;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 handler->method_node = gpe_event_info->dispatch.method_node;
607
608 /* Disable the GPE before installing the handler */
609
Len Brown4be44fc2005-08-05 00:44:28 -0400610 status = acpi_ev_disable_gpe(gpe_event_info);
611 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 goto unlock_and_exit;
613 }
614
615 /* Install the handler */
616
Len Brown4be44fc2005-08-05 00:44:28 -0400617 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 gpe_event_info->dispatch.handler = handler;
619
620 /* Setup up dispatch flags to indicate handler (vs. method) */
621
Len Brown4be44fc2005-08-05 00:44:28 -0400622 gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
624
Len Brown4be44fc2005-08-05 00:44:28 -0400625 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
Len Brown4be44fc2005-08-05 00:44:28 -0400627 unlock_and_exit:
628 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
629 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Len Brown4be44fc2005-08-05 00:44:28 -0400632EXPORT_SYMBOL(acpi_install_gpe_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634/*******************************************************************************
635 *
636 * FUNCTION: acpi_remove_gpe_handler
637 *
Robert Moore44f6c012005-04-18 22:49:35 -0400638 * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
639 * defined GPEs)
640 * gpe_number - The event to remove a handler
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 * Address - Address of the handler
642 *
643 * RETURN: Status
644 *
645 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
646 *
647 ******************************************************************************/
648
649acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400650acpi_remove_gpe_handler(acpi_handle gpe_device,
651 u32 gpe_number, acpi_event_handler address)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Len Brown4be44fc2005-08-05 00:44:28 -0400653 struct acpi_gpe_event_info *gpe_event_info;
654 struct acpi_handler_info *handler;
655 acpi_status status;
656 u32 flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Len Brown4be44fc2005-08-05 00:44:28 -0400658 ACPI_FUNCTION_TRACE("acpi_remove_gpe_handler");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 /* Parameter validation */
661
662 if (!address) {
Len Brown4be44fc2005-08-05 00:44:28 -0400663 return_ACPI_STATUS(AE_BAD_PARAMETER);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
665
Len Brown4be44fc2005-08-05 00:44:28 -0400666 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
667 if (ACPI_FAILURE(status)) {
668 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670
671 /* Ensure that we have a valid GPE number */
672
Len Brown4be44fc2005-08-05 00:44:28 -0400673 gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (!gpe_event_info) {
675 status = AE_BAD_PARAMETER;
676 goto unlock_and_exit;
677 }
678
679 /* Make sure that a handler is indeed installed */
680
Len Brown4be44fc2005-08-05 00:44:28 -0400681 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
682 ACPI_GPE_DISPATCH_HANDLER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 status = AE_NOT_EXIST;
684 goto unlock_and_exit;
685 }
686
687 /* Make sure that the installed handler is the same */
688
689 if (gpe_event_info->dispatch.handler->address != address) {
690 status = AE_BAD_PARAMETER;
691 goto unlock_and_exit;
692 }
693
694 /* Disable the GPE before removing the handler */
695
Len Brown4be44fc2005-08-05 00:44:28 -0400696 status = acpi_ev_disable_gpe(gpe_event_info);
697 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 goto unlock_and_exit;
699 }
700
701 /* Make sure all deferred tasks are completed */
702
Len Brown4be44fc2005-08-05 00:44:28 -0400703 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 acpi_os_wait_events_complete(NULL);
Len Brown4be44fc2005-08-05 00:44:28 -0400705 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
706 if (ACPI_FAILURE(status)) {
707 return_ACPI_STATUS(status);
708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 /* Remove the handler */
711
Len Brown4be44fc2005-08-05 00:44:28 -0400712 flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 handler = gpe_event_info->dispatch.handler;
714
715 /* Restore Method node (if any), set dispatch flags */
716
717 gpe_event_info->dispatch.method_node = handler->method_node;
Len Brown4be44fc2005-08-05 00:44:28 -0400718 gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (handler->method_node) {
720 gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
721 }
Len Brown4be44fc2005-08-05 00:44:28 -0400722 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 /* Now we can free the handler object */
725
Len Brown4be44fc2005-08-05 00:44:28 -0400726 ACPI_MEM_FREE(handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Len Brown4be44fc2005-08-05 00:44:28 -0400728 unlock_and_exit:
729 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
730 return_ACPI_STATUS(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Len Brown4be44fc2005-08-05 00:44:28 -0400733EXPORT_SYMBOL(acpi_remove_gpe_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735/*******************************************************************************
736 *
737 * FUNCTION: acpi_acquire_global_lock
738 *
739 * PARAMETERS: Timeout - How long the caller is willing to wait
Robert Moore44f6c012005-04-18 22:49:35 -0400740 * Handle - Where the handle to the lock is returned
741 * (if acquired)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 *
743 * RETURN: Status
744 *
745 * DESCRIPTION: Acquire the ACPI Global Lock
746 *
747 ******************************************************************************/
748
Len Brown4be44fc2005-08-05 00:44:28 -0400749acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
Len Brown4be44fc2005-08-05 00:44:28 -0400751 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 if (!handle) {
754 return (AE_BAD_PARAMETER);
755 }
756
Len Brown4be44fc2005-08-05 00:44:28 -0400757 status = acpi_ex_enter_interpreter();
758 if (ACPI_FAILURE(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 return (status);
760 }
761
Len Brown4be44fc2005-08-05 00:44:28 -0400762 status = acpi_ev_acquire_global_lock(timeout);
763 acpi_ex_exit_interpreter();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Len Brown4be44fc2005-08-05 00:44:28 -0400765 if (ACPI_SUCCESS(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 acpi_gbl_global_lock_handle++;
767 *handle = acpi_gbl_global_lock_handle;
768 }
769
770 return (status);
771}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Len Brown4be44fc2005-08-05 00:44:28 -0400773EXPORT_SYMBOL(acpi_acquire_global_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775/*******************************************************************************
776 *
777 * FUNCTION: acpi_release_global_lock
778 *
779 * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
780 *
781 * RETURN: Status
782 *
Robert Moore44f6c012005-04-18 22:49:35 -0400783 * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 *
785 ******************************************************************************/
786
Len Brown4be44fc2005-08-05 00:44:28 -0400787acpi_status acpi_release_global_lock(u32 handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788{
Len Brown4be44fc2005-08-05 00:44:28 -0400789 acpi_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 if (handle != acpi_gbl_global_lock_handle) {
792 return (AE_NOT_ACQUIRED);
793 }
794
Len Brown4be44fc2005-08-05 00:44:28 -0400795 status = acpi_ev_release_global_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return (status);
797}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Len Brown4be44fc2005-08-05 00:44:28 -0400799EXPORT_SYMBOL(acpi_release_global_lock);