1 /******************************************************************************
3 * Module Name: evxface - External interfaces for ACPI events
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2004, R. Byron Moore
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
45 #include <acpi/acpi.h>
46 #include <acpi/acnamesp.h>
47 #include <acpi/acevents.h>
48 #include <acpi/acinterp.h>
50 #define _COMPONENT ACPI_EVENTS
51 ACPI_MODULE_NAME ("evxface")
54 /*******************************************************************************
56 * FUNCTION: acpi_install_fixed_event_handler
58 * PARAMETERS: Event - Event type to enable.
59 * Handler - Pointer to the handler function for the
61 * Context - Value passed to the handler on each GPE
65 * DESCRIPTION: Saves the pointer to the handler function and then enables the
68 ******************************************************************************/
71 acpi_install_fixed_event_handler (
73 acpi_event_handler handler,
79 ACPI_FUNCTION_TRACE ("acpi_install_fixed_event_handler");
82 /* Parameter validation */
84 if (event > ACPI_EVENT_MAX) {
85 return_ACPI_STATUS (AE_BAD_PARAMETER);
88 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
89 if (ACPI_FAILURE (status)) {
90 return_ACPI_STATUS (status);
93 /* Don't allow two handlers. */
95 if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
96 status = AE_ALREADY_EXISTS;
100 /* Install the handler before enabling the event */
102 acpi_gbl_fixed_event_handlers[event].handler = handler;
103 acpi_gbl_fixed_event_handlers[event].context = context;
105 status = acpi_enable_event (event, 0);
106 if (ACPI_FAILURE (status)) {
107 ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n"));
109 /* Remove the handler */
111 acpi_gbl_fixed_event_handlers[event].handler = NULL;
112 acpi_gbl_fixed_event_handlers[event].context = NULL;
115 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
116 "Enabled fixed event %X, Handler=%p\n", event, handler));
121 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
122 return_ACPI_STATUS (status);
126 /*******************************************************************************
128 * FUNCTION: acpi_remove_fixed_event_handler
130 * PARAMETERS: Event - Event type to disable.
131 * Handler - Address of the handler
135 * DESCRIPTION: Disables the event and unregisters the event handler.
137 ******************************************************************************/
140 acpi_remove_fixed_event_handler (
142 acpi_event_handler handler)
144 acpi_status status = AE_OK;
147 ACPI_FUNCTION_TRACE ("acpi_remove_fixed_event_handler");
150 /* Parameter validation */
152 if (event > ACPI_EVENT_MAX) {
153 return_ACPI_STATUS (AE_BAD_PARAMETER);
156 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
157 if (ACPI_FAILURE (status)) {
158 return_ACPI_STATUS (status);
161 /* Disable the event before removing the handler */
163 status = acpi_disable_event (event, 0);
165 /* Always Remove the handler */
167 acpi_gbl_fixed_event_handlers[event].handler = NULL;
168 acpi_gbl_fixed_event_handlers[event].context = NULL;
170 if (ACPI_FAILURE (status)) {
171 ACPI_DEBUG_PRINT ((ACPI_DB_WARN,
172 "Could not write to fixed event enable register.\n"));
175 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X.\n", event));
178 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
179 return_ACPI_STATUS (status);
183 /*******************************************************************************
185 * FUNCTION: acpi_install_notify_handler
187 * PARAMETERS: Device - The device for which notifies will be handled
188 * handler_type - The type of handler:
189 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
190 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
191 * Handler - Address of the handler
192 * Context - Value passed to the handler on each GPE
196 * DESCRIPTION: Install a handler for notifies on an ACPI device
198 ******************************************************************************/
201 acpi_install_notify_handler (
204 acpi_notify_handler handler,
207 union acpi_operand_object *obj_desc;
208 union acpi_operand_object *notify_obj;
209 struct acpi_namespace_node *node;
213 ACPI_FUNCTION_TRACE ("acpi_install_notify_handler");
216 /* Parameter validation */
220 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
221 return_ACPI_STATUS (AE_BAD_PARAMETER);
224 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
225 if (ACPI_FAILURE (status)) {
226 return_ACPI_STATUS (status);
229 /* Convert and validate the device handle */
231 node = acpi_ns_map_handle_to_node (device);
233 status = AE_BAD_PARAMETER;
234 goto unlock_and_exit;
239 * Registering a notify handler on the root object indicates that the
240 * caller wishes to receive notifications for all objects. Note that
241 * only one <external> global handler can be regsitered (per notify type).
243 if (device == ACPI_ROOT_OBJECT) {
244 /* Make sure the handler is not already installed */
246 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
247 acpi_gbl_system_notify.handler) ||
248 ((handler_type == ACPI_DEVICE_NOTIFY) &&
249 acpi_gbl_device_notify.handler)) {
250 status = AE_ALREADY_EXISTS;
251 goto unlock_and_exit;
254 if (handler_type == ACPI_SYSTEM_NOTIFY) {
255 acpi_gbl_system_notify.node = node;
256 acpi_gbl_system_notify.handler = handler;
257 acpi_gbl_system_notify.context = context;
259 else /* ACPI_DEVICE_NOTIFY */ {
260 acpi_gbl_device_notify.node = node;
261 acpi_gbl_device_notify.handler = handler;
262 acpi_gbl_device_notify.context = context;
265 /* Global notify handler installed */
270 * Caller will only receive notifications specific to the target object.
271 * Note that only certain object types can receive notifications.
274 /* Notifies allowed on this object? */
276 if (!acpi_ev_is_notify_object (node)) {
278 goto unlock_and_exit;
281 /* Check for an existing internal object */
283 obj_desc = acpi_ns_get_attached_object (node);
285 /* Object exists - make sure there's no handler */
287 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
288 obj_desc->common_notify.system_notify) ||
289 ((handler_type == ACPI_DEVICE_NOTIFY) &&
290 obj_desc->common_notify.device_notify)) {
291 status = AE_ALREADY_EXISTS;
292 goto unlock_and_exit;
296 /* Create a new object */
298 obj_desc = acpi_ut_create_internal_object (node->type);
300 status = AE_NO_MEMORY;
301 goto unlock_and_exit;
304 /* Attach new object to the Node */
306 status = acpi_ns_attach_object (device, obj_desc, node->type);
308 /* Remove local reference to the object */
310 acpi_ut_remove_reference (obj_desc);
312 if (ACPI_FAILURE (status)) {
313 goto unlock_and_exit;
317 /* Install the handler */
319 notify_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_NOTIFY);
321 status = AE_NO_MEMORY;
322 goto unlock_and_exit;
325 notify_obj->notify.node = node;
326 notify_obj->notify.handler = handler;
327 notify_obj->notify.context = context;
329 if (handler_type == ACPI_SYSTEM_NOTIFY) {
330 obj_desc->common_notify.system_notify = notify_obj;
332 else /* ACPI_DEVICE_NOTIFY */ {
333 obj_desc->common_notify.device_notify = notify_obj;
339 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
340 return_ACPI_STATUS (status);
344 /*******************************************************************************
346 * FUNCTION: acpi_remove_notify_handler
348 * PARAMETERS: Device - The device for which notifies will be handled
349 * handler_type - The type of handler:
350 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
351 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
352 * Handler - Address of the handler
355 * DESCRIPTION: Remove a handler for notifies on an ACPI device
357 ******************************************************************************/
360 acpi_remove_notify_handler (
363 acpi_notify_handler handler)
365 union acpi_operand_object *notify_obj;
366 union acpi_operand_object *obj_desc;
367 struct acpi_namespace_node *node;
371 ACPI_FUNCTION_TRACE ("acpi_remove_notify_handler");
374 /* Parameter validation */
378 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
379 return_ACPI_STATUS (AE_BAD_PARAMETER);
382 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
383 if (ACPI_FAILURE (status)) {
384 return_ACPI_STATUS (status);
387 /* Convert and validate the device handle */
389 node = acpi_ns_map_handle_to_node (device);
391 status = AE_BAD_PARAMETER;
392 goto unlock_and_exit;
398 if (device == ACPI_ROOT_OBJECT) {
399 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n"));
401 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
402 !acpi_gbl_system_notify.handler) ||
403 ((handler_type == ACPI_DEVICE_NOTIFY) &&
404 !acpi_gbl_device_notify.handler)) {
405 status = AE_NOT_EXIST;
406 goto unlock_and_exit;
409 if (handler_type == ACPI_SYSTEM_NOTIFY) {
410 acpi_gbl_system_notify.node = NULL;
411 acpi_gbl_system_notify.handler = NULL;
412 acpi_gbl_system_notify.context = NULL;
415 acpi_gbl_device_notify.node = NULL;
416 acpi_gbl_device_notify.handler = NULL;
417 acpi_gbl_device_notify.context = NULL;
425 /* Notifies allowed on this object? */
427 if (!acpi_ev_is_notify_object (node)) {
429 goto unlock_and_exit;
432 /* Check for an existing internal object */
434 obj_desc = acpi_ns_get_attached_object (node);
436 status = AE_NOT_EXIST;
437 goto unlock_and_exit;
440 /* Object exists - make sure there's an existing handler */
442 if (handler_type == ACPI_SYSTEM_NOTIFY) {
443 notify_obj = obj_desc->common_notify.system_notify;
446 notify_obj = obj_desc->common_notify.device_notify;
450 (notify_obj->notify.handler != handler)) {
451 status = AE_BAD_PARAMETER;
452 goto unlock_and_exit;
455 /* Remove the handler */
457 if (handler_type == ACPI_SYSTEM_NOTIFY) {
458 obj_desc->common_notify.system_notify = NULL;
461 obj_desc->common_notify.device_notify = NULL;
464 acpi_ut_remove_reference (notify_obj);
469 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
470 return_ACPI_STATUS (status);
474 /*******************************************************************************
476 * FUNCTION: acpi_install_gpe_handler
478 * PARAMETERS: gpe_number - The GPE number within the GPE block
479 * gpe_block - GPE block (NULL == FADT GPEs)
480 * Type - Whether this GPE should be treated as an
481 * edge- or level-triggered interrupt.
482 * Handler - Address of the handler
483 * Context - Value passed to the handler on each GPE
487 * DESCRIPTION: Install a handler for a General Purpose Event.
489 ******************************************************************************/
492 acpi_install_gpe_handler (
493 acpi_handle gpe_device,
496 acpi_gpe_handler handler,
500 struct acpi_gpe_event_info *gpe_event_info;
503 ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler");
506 /* Parameter validation */
509 return_ACPI_STATUS (AE_BAD_PARAMETER);
512 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
513 if (ACPI_FAILURE (status)) {
514 return_ACPI_STATUS (status);
517 /* Ensure that we have a valid GPE number */
519 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
520 if (!gpe_event_info) {
521 status = AE_BAD_PARAMETER;
522 goto unlock_and_exit;
525 /* Make sure that there isn't a handler there already */
527 if (gpe_event_info->handler) {
528 status = AE_ALREADY_EXISTS;
529 goto unlock_and_exit;
532 /* Install the handler */
534 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
535 gpe_event_info->handler = handler;
536 gpe_event_info->context = context;
537 gpe_event_info->flags = (u8) type;
538 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
540 /* Clear the GPE (of stale events), the enable it */
542 status = acpi_hw_clear_gpe (gpe_event_info);
543 if (ACPI_FAILURE (status)) {
544 goto unlock_and_exit;
547 status = acpi_hw_enable_gpe (gpe_event_info);
551 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
552 return_ACPI_STATUS (status);
556 /*******************************************************************************
558 * FUNCTION: acpi_remove_gpe_handler
560 * PARAMETERS: gpe_number - The event to remove a handler
561 * gpe_block - GPE block (NULL == FADT GPEs)
562 * Handler - Address of the handler
566 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
568 ******************************************************************************/
571 acpi_remove_gpe_handler (
572 acpi_handle gpe_device,
574 acpi_gpe_handler handler)
577 struct acpi_gpe_event_info *gpe_event_info;
580 ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler");
583 /* Parameter validation */
586 return_ACPI_STATUS (AE_BAD_PARAMETER);
589 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
590 if (ACPI_FAILURE (status)) {
591 return_ACPI_STATUS (status);
594 /* Ensure that we have a valid GPE number */
596 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
597 if (!gpe_event_info) {
598 status = AE_BAD_PARAMETER;
599 goto unlock_and_exit;
602 /* Disable the GPE before removing the handler */
604 status = acpi_hw_disable_gpe (gpe_event_info);
605 if (ACPI_FAILURE (status)) {
606 goto unlock_and_exit;
609 /* Make sure that the installed handler is the same */
611 if (gpe_event_info->handler != handler) {
612 (void) acpi_hw_enable_gpe (gpe_event_info);
613 status = AE_BAD_PARAMETER;
614 goto unlock_and_exit;
617 /* Remove the handler */
619 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
620 gpe_event_info->handler = NULL;
621 gpe_event_info->context = NULL;
622 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
626 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
627 return_ACPI_STATUS (status);
631 /*******************************************************************************
633 * FUNCTION: acpi_acquire_global_lock
635 * PARAMETERS: Timeout - How long the caller is willing to wait
636 * out_handle - A handle to the lock if acquired
640 * DESCRIPTION: Acquire the ACPI Global Lock
642 ******************************************************************************/
645 acpi_acquire_global_lock (
653 return (AE_BAD_PARAMETER);
656 status = acpi_ex_enter_interpreter ();
657 if (ACPI_FAILURE (status)) {
661 status = acpi_ev_acquire_global_lock (timeout);
662 acpi_ex_exit_interpreter ();
664 if (ACPI_SUCCESS (status)) {
665 acpi_gbl_global_lock_handle++;
666 *handle = acpi_gbl_global_lock_handle;
673 /*******************************************************************************
675 * FUNCTION: acpi_release_global_lock
677 * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
681 * DESCRIPTION: Release the ACPI Global Lock
683 ******************************************************************************/
686 acpi_release_global_lock (
692 if (handle != acpi_gbl_global_lock_handle) {
693 return (AE_NOT_ACQUIRED);
696 status = acpi_ev_release_global_lock ();