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 * ACPI_ALL_NOTIFY: both system and device
192 * Handler - Address of the handler
193 * Context - Value passed to the handler on each GPE
197 * DESCRIPTION: Install a handler for notifies on an ACPI device
199 ******************************************************************************/
202 acpi_install_notify_handler (
205 acpi_notify_handler handler,
208 union acpi_operand_object *obj_desc;
209 union acpi_operand_object *notify_obj;
210 struct acpi_namespace_node *node;
214 ACPI_FUNCTION_TRACE ("acpi_install_notify_handler");
217 /* Parameter validation */
221 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
222 return_ACPI_STATUS (AE_BAD_PARAMETER);
225 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
226 if (ACPI_FAILURE (status)) {
227 return_ACPI_STATUS (status);
230 /* Convert and validate the device handle */
232 node = acpi_ns_map_handle_to_node (device);
234 status = AE_BAD_PARAMETER;
235 goto unlock_and_exit;
240 * Registering a notify handler on the root object indicates that the
241 * caller wishes to receive notifications for all objects. Note that
242 * only one <external> global handler can be regsitered (per notify type).
244 if (device == ACPI_ROOT_OBJECT) {
245 /* Make sure the handler is not already installed */
247 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
248 acpi_gbl_system_notify.handler) ||
249 ((handler_type & ACPI_DEVICE_NOTIFY) &&
250 acpi_gbl_device_notify.handler)) {
251 status = AE_ALREADY_EXISTS;
252 goto unlock_and_exit;
255 if (handler_type & ACPI_SYSTEM_NOTIFY) {
256 acpi_gbl_system_notify.node = node;
257 acpi_gbl_system_notify.handler = handler;
258 acpi_gbl_system_notify.context = context;
261 if (handler_type & ACPI_DEVICE_NOTIFY) {
262 acpi_gbl_device_notify.node = node;
263 acpi_gbl_device_notify.handler = handler;
264 acpi_gbl_device_notify.context = context;
267 /* Global notify handler installed */
272 * Caller will only receive notifications specific to the target object.
273 * Note that only certain object types can receive notifications.
276 /* Notifies allowed on this object? */
278 if (!acpi_ev_is_notify_object (node)) {
280 goto unlock_and_exit;
283 /* Check for an existing internal object */
285 obj_desc = acpi_ns_get_attached_object (node);
287 /* Object exists - make sure there's no handler */
289 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
290 obj_desc->common_notify.system_notify) ||
291 ((handler_type & ACPI_DEVICE_NOTIFY) &&
292 obj_desc->common_notify.device_notify)) {
293 status = AE_ALREADY_EXISTS;
294 goto unlock_and_exit;
298 /* Create a new object */
300 obj_desc = acpi_ut_create_internal_object (node->type);
302 status = AE_NO_MEMORY;
303 goto unlock_and_exit;
306 /* Attach new object to the Node */
308 status = acpi_ns_attach_object (device, obj_desc, node->type);
310 /* Remove local reference to the object */
312 acpi_ut_remove_reference (obj_desc);
313 if (ACPI_FAILURE (status)) {
314 goto unlock_and_exit;
318 /* Install the handler */
320 notify_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_NOTIFY);
322 status = AE_NO_MEMORY;
323 goto unlock_and_exit;
326 notify_obj->notify.node = node;
327 notify_obj->notify.handler = handler;
328 notify_obj->notify.context = context;
330 if (handler_type & ACPI_SYSTEM_NOTIFY) {
331 obj_desc->common_notify.system_notify = notify_obj;
334 if (handler_type & ACPI_DEVICE_NOTIFY) {
335 obj_desc->common_notify.device_notify = notify_obj;
338 if (handler_type == ACPI_ALL_NOTIFY) {
339 /* Extra ref if installed in both */
341 acpi_ut_add_reference (notify_obj);
347 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
348 return_ACPI_STATUS (status);
352 /*******************************************************************************
354 * FUNCTION: acpi_remove_notify_handler
356 * PARAMETERS: Device - The device for which notifies will be handled
357 * handler_type - The type of handler:
358 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
359 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
360 * ACPI_ALL_NOTIFY: both system and device
361 * Handler - Address of the handler
365 * DESCRIPTION: Remove a handler for notifies on an ACPI device
367 ******************************************************************************/
370 acpi_remove_notify_handler (
373 acpi_notify_handler handler)
375 union acpi_operand_object *notify_obj;
376 union acpi_operand_object *obj_desc;
377 struct acpi_namespace_node *node;
381 ACPI_FUNCTION_TRACE ("acpi_remove_notify_handler");
384 /* Parameter validation */
388 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
389 return_ACPI_STATUS (AE_BAD_PARAMETER);
392 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
393 if (ACPI_FAILURE (status)) {
394 return_ACPI_STATUS (status);
397 /* Convert and validate the device handle */
399 node = acpi_ns_map_handle_to_node (device);
401 status = AE_BAD_PARAMETER;
402 goto unlock_and_exit;
407 if (device == ACPI_ROOT_OBJECT) {
408 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n"));
410 if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
411 !acpi_gbl_system_notify.handler) ||
412 ((handler_type & ACPI_DEVICE_NOTIFY) &&
413 !acpi_gbl_device_notify.handler)) {
414 status = AE_NOT_EXIST;
415 goto unlock_and_exit;
418 /* Make sure all deferred tasks are completed */
420 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
421 acpi_os_wait_events_complete(NULL);
422 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
423 if (ACPI_FAILURE (status)) {
424 return_ACPI_STATUS (status);
427 if (handler_type & ACPI_SYSTEM_NOTIFY) {
428 acpi_gbl_system_notify.node = NULL;
429 acpi_gbl_system_notify.handler = NULL;
430 acpi_gbl_system_notify.context = NULL;
433 if (handler_type & ACPI_DEVICE_NOTIFY) {
434 acpi_gbl_device_notify.node = NULL;
435 acpi_gbl_device_notify.handler = NULL;
436 acpi_gbl_device_notify.context = NULL;
440 /* All Other Objects */
443 /* Notifies allowed on this object? */
445 if (!acpi_ev_is_notify_object (node)) {
447 goto unlock_and_exit;
450 /* Check for an existing internal object */
452 obj_desc = acpi_ns_get_attached_object (node);
454 status = AE_NOT_EXIST;
455 goto unlock_and_exit;
458 /* Object exists - make sure there's an existing handler */
460 if (handler_type & ACPI_SYSTEM_NOTIFY) {
461 notify_obj = obj_desc->common_notify.system_notify;
463 (notify_obj->notify.handler != handler)) {
464 status = AE_BAD_PARAMETER;
465 goto unlock_and_exit;
467 /* Make sure all deferred tasks are completed */
469 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
470 acpi_os_wait_events_complete(NULL);
471 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
472 if (ACPI_FAILURE (status)) {
473 return_ACPI_STATUS (status);
476 /* Remove the handler */
477 obj_desc->common_notify.system_notify = NULL;
478 acpi_ut_remove_reference (notify_obj);
481 if (handler_type & ACPI_DEVICE_NOTIFY) {
482 notify_obj = obj_desc->common_notify.device_notify;
484 (notify_obj->notify.handler != handler)) {
485 status = AE_BAD_PARAMETER;
486 goto unlock_and_exit;
488 /* Make sure all deferred tasks are completed */
490 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
491 acpi_os_wait_events_complete(NULL);
492 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
493 if (ACPI_FAILURE (status)) {
494 return_ACPI_STATUS (status);
497 /* Remove the handler */
498 obj_desc->common_notify.device_notify = NULL;
499 acpi_ut_remove_reference (notify_obj);
505 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
506 return_ACPI_STATUS (status);
510 /*******************************************************************************
512 * FUNCTION: acpi_install_gpe_handler
514 * PARAMETERS: gpe_number - The GPE number within the GPE block
515 * gpe_block - GPE block (NULL == FADT GPEs)
516 * Type - Whether this GPE should be treated as an
517 * edge- or level-triggered interrupt.
518 * Address - Address of the handler
519 * Context - Value passed to the handler on each GPE
523 * DESCRIPTION: Install a handler for a General Purpose Event.
525 ******************************************************************************/
528 acpi_install_gpe_handler (
529 acpi_handle gpe_device,
532 acpi_event_handler address,
535 struct acpi_gpe_event_info *gpe_event_info;
536 struct acpi_handler_info *handler;
540 ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler");
543 /* Parameter validation */
545 if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
546 return_ACPI_STATUS (AE_BAD_PARAMETER);
549 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
550 if (ACPI_FAILURE (status)) {
551 return_ACPI_STATUS (status);
554 /* Ensure that we have a valid GPE number */
556 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
557 if (!gpe_event_info) {
558 status = AE_BAD_PARAMETER;
559 goto unlock_and_exit;
562 /* Make sure that there isn't a handler there already */
564 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) {
565 status = AE_ALREADY_EXISTS;
566 goto unlock_and_exit;
569 /* Allocate and init handler object */
571 handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info));
573 status = AE_NO_MEMORY;
574 goto unlock_and_exit;
577 handler->address = address;
578 handler->context = context;
579 handler->method_node = gpe_event_info->dispatch.method_node;
581 /* Disable the GPE before installing the handler */
583 status = acpi_ev_disable_gpe (gpe_event_info);
584 if (ACPI_FAILURE (status)) {
585 goto unlock_and_exit;
588 /* Install the handler */
590 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
591 gpe_event_info->dispatch.handler = handler;
593 /* Setup up dispatch flags to indicate handler (vs. method) */
595 gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */
596 gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
598 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
602 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
603 return_ACPI_STATUS (status);
607 /*******************************************************************************
609 * FUNCTION: acpi_remove_gpe_handler
611 * PARAMETERS: gpe_number - The event to remove a handler
612 * gpe_block - GPE block (NULL == FADT GPEs)
613 * Address - Address of the handler
617 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
619 ******************************************************************************/
622 acpi_remove_gpe_handler (
623 acpi_handle gpe_device,
625 acpi_event_handler address)
627 struct acpi_gpe_event_info *gpe_event_info;
628 struct acpi_handler_info *handler;
632 ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler");
635 /* Parameter validation */
638 return_ACPI_STATUS (AE_BAD_PARAMETER);
641 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
642 if (ACPI_FAILURE (status)) {
643 return_ACPI_STATUS (status);
646 /* Ensure that we have a valid GPE number */
648 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
649 if (!gpe_event_info) {
650 status = AE_BAD_PARAMETER;
651 goto unlock_and_exit;
654 /* Make sure that a handler is indeed installed */
656 if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) {
657 status = AE_NOT_EXIST;
658 goto unlock_and_exit;
661 /* Make sure that the installed handler is the same */
663 if (gpe_event_info->dispatch.handler->address != address) {
664 status = AE_BAD_PARAMETER;
665 goto unlock_and_exit;
668 /* Disable the GPE before removing the handler */
670 status = acpi_ev_disable_gpe (gpe_event_info);
671 if (ACPI_FAILURE (status)) {
672 goto unlock_and_exit;
675 /* Make sure all deferred tasks are completed */
677 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
678 acpi_os_wait_events_complete(NULL);
679 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
680 if (ACPI_FAILURE (status)) {
681 return_ACPI_STATUS (status);
684 /* Remove the handler */
686 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
687 handler = gpe_event_info->dispatch.handler;
689 /* Restore Method node (if any), set dispatch flags */
691 gpe_event_info->dispatch.method_node = handler->method_node;
692 gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */
693 if (handler->method_node) {
694 gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
696 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
698 /* Now we can free the handler object */
700 ACPI_MEM_FREE (handler);
704 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
705 return_ACPI_STATUS (status);
709 /*******************************************************************************
711 * FUNCTION: acpi_acquire_global_lock
713 * PARAMETERS: Timeout - How long the caller is willing to wait
714 * out_handle - A handle to the lock if acquired
718 * DESCRIPTION: Acquire the ACPI Global Lock
720 ******************************************************************************/
723 acpi_acquire_global_lock (
731 return (AE_BAD_PARAMETER);
734 status = acpi_ex_enter_interpreter ();
735 if (ACPI_FAILURE (status)) {
739 status = acpi_ev_acquire_global_lock (timeout);
740 acpi_ex_exit_interpreter ();
742 if (ACPI_SUCCESS (status)) {
743 acpi_gbl_global_lock_handle++;
744 *handle = acpi_gbl_global_lock_handle;
751 /*******************************************************************************
753 * FUNCTION: acpi_release_global_lock
755 * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
759 * DESCRIPTION: Release the ACPI Global Lock
761 ******************************************************************************/
764 acpi_release_global_lock (
770 if (handle != acpi_gbl_global_lock_handle) {
771 return (AE_NOT_ACQUIRED);
774 status = acpi_ev_release_global_lock ();