1 /******************************************************************************
3 * Module Name: evmisc - ACPI device notification handler dispatch
4 * and ACPI Global Lock support
7 *****************************************************************************/
10 * Copyright (C) 2000, 2001 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #define _COMPONENT ACPI_EVENTS
34 MODULE_NAME ("evmisc")
37 /**************************************************************************
39 * FUNCTION: Acpi_ev_queue_notify_request
45 * DESCRIPTION: Dispatch a device notification event to a previously
48 *************************************************************************/
51 acpi_ev_queue_notify_request (
52 ACPI_NAMESPACE_NODE *node,
55 ACPI_OPERAND_OBJECT *obj_desc;
56 ACPI_OPERAND_OBJECT *handler_obj = NULL;
57 ACPI_GENERIC_STATE *notify_info;
58 ACPI_STATUS status = AE_OK;
62 * For value 1 (Ejection Request), some device method may need to be run.
63 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
64 * For value 0x80 (Status Change) on the power button or sleep button,
65 * initiate soft-off or sleep operation?
68 switch (notify_value) {
87 * Get the notify object attached to the device Node
90 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
93 /* We have the notify object, Get the right handler */
96 case ACPI_TYPE_DEVICE:
97 if (notify_value <= MAX_SYS_NOTIFY) {
98 handler_obj = obj_desc->device.sys_handler;
101 handler_obj = obj_desc->device.drv_handler;
105 case ACPI_TYPE_THERMAL:
106 if (notify_value <= MAX_SYS_NOTIFY) {
107 handler_obj = obj_desc->thermal_zone.sys_handler;
110 handler_obj = obj_desc->thermal_zone.drv_handler;
117 /* If there is any handler to run, schedule the dispatcher */
119 if ((acpi_gbl_sys_notify.handler && (notify_value <= MAX_SYS_NOTIFY)) ||
120 (acpi_gbl_drv_notify.handler && (notify_value > MAX_SYS_NOTIFY)) ||
123 notify_info = acpi_cm_create_generic_state ();
125 return (AE_NO_MEMORY);
128 notify_info->notify.node = node;
129 notify_info->notify.value = (u16) notify_value;
130 notify_info->notify.handler_obj = handler_obj;
132 status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
133 acpi_ev_notify_dispatch, notify_info);
134 if (ACPI_FAILURE (status)) {
135 acpi_cm_delete_generic_state (notify_info);
140 /* There is no per-device notify handler for this device */
149 /**************************************************************************
151 * FUNCTION: Acpi_ev_notify_dispatch
157 * DESCRIPTION: Dispatch a device notification event to a previously
160 *************************************************************************/
163 acpi_ev_notify_dispatch (
166 ACPI_GENERIC_STATE *notify_info = (ACPI_GENERIC_STATE *) context;
167 NOTIFY_HANDLER global_handler = NULL;
168 void *global_context = NULL;
169 ACPI_OPERAND_OBJECT *handler_obj;
173 * We will invoke a global notify handler if installed.
174 * This is done _before_ we invoke the per-device handler attached to the device.
177 if (notify_info->notify.value <= MAX_SYS_NOTIFY) {
178 /* Global system notification handler */
180 if (acpi_gbl_sys_notify.handler) {
181 global_handler = acpi_gbl_sys_notify.handler;
182 global_context = acpi_gbl_sys_notify.context;
187 /* Global driver notification handler */
189 if (acpi_gbl_drv_notify.handler) {
190 global_handler = acpi_gbl_drv_notify.handler;
191 global_context = acpi_gbl_drv_notify.context;
196 /* Invoke the system handler first, if present */
198 if (global_handler) {
199 global_handler (notify_info->notify.node, notify_info->notify.value, global_context);
202 /* Now invoke the per-device handler, if present */
204 handler_obj = notify_info->notify.handler_obj;
206 handler_obj->notify_handler.handler (notify_info->notify.node, notify_info->notify.value,
207 handler_obj->notify_handler.context);
211 /* All done with the info object */
213 acpi_cm_delete_generic_state (notify_info);
217 /***************************************************************************
219 * FUNCTION: Acpi_ev_global_lock_thread
223 * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
224 * Global Lock. Simply signal all threads that are waiting
227 **************************************************************************/
230 acpi_ev_global_lock_thread (
234 /* Signal threads that are waiting for the lock */
236 if (acpi_gbl_global_lock_thread_count) {
237 /* Send sufficient units to the semaphore */
239 acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
240 acpi_gbl_global_lock_thread_count);
245 /***************************************************************************
247 * FUNCTION: Acpi_ev_global_lock_handler
251 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
252 * release interrupt occurs. Grab the global lock and queue
253 * the global lock thread for execution
255 **************************************************************************/
258 acpi_ev_global_lock_handler (
266 * Attempt to get the lock
267 * If we don't get it now, it will be marked pending and we will
268 * take another interrupt when it becomes free.
271 global_lock = acpi_gbl_FACS->global_lock;
272 ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
274 /* Got the lock, now wake all threads waiting for it */
276 acpi_gbl_global_lock_acquired = TRUE;
278 /* Run the Global Lock thread which will signal all waiting threads */
280 acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_global_lock_thread,
284 return (INTERRUPT_HANDLED);
288 /***************************************************************************
290 * FUNCTION: Acpi_ev_init_global_lock_handler
294 * DESCRIPTION: Install a handler for the global lock release event
296 **************************************************************************/
299 acpi_ev_init_global_lock_handler (void)
304 acpi_gbl_global_lock_present = TRUE;
305 status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
306 acpi_ev_global_lock_handler, NULL);
309 * If the global lock does not exist on this platform, the attempt
310 * to enable GBL_STS will fail (the GBL_EN bit will not stick)
311 * Map to AE_OK, but mark global lock as not present.
312 * Any attempt to actually use the global lock will be flagged
315 if (status == AE_NO_HARDWARE_RESPONSE) {
316 acpi_gbl_global_lock_present = FALSE;
324 /***************************************************************************
326 * FUNCTION: Acpi_ev_acquire_global_lock
330 * DESCRIPTION: Attempt to gain ownership of the Global Lock.
332 **************************************************************************/
335 acpi_ev_acquire_global_lock(void)
337 ACPI_STATUS status = AE_OK;
342 /* Make sure that we actually have a global lock */
344 if (!acpi_gbl_global_lock_present) {
345 return (AE_NO_GLOBAL_LOCK);
348 /* One more thread wants the global lock */
350 acpi_gbl_global_lock_thread_count++;
353 /* If we (OS side) have the hardware lock already, we are done */
355 if (acpi_gbl_global_lock_acquired) {
359 /* Only if the FACS is valid */
361 if (!acpi_gbl_FACS) {
366 /* We must acquire the actual hardware lock */
368 global_lock = acpi_gbl_FACS->global_lock;
369 ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
371 /* We got the lock */
373 acpi_gbl_global_lock_acquired = TRUE;
380 * Did not get the lock. The pending bit was set above, and we must now
381 * wait until we get the global lock released interrupt.
385 * Acquire the global lock semaphore first.
386 * Since this wait will block, we must release the interpreter
389 status = acpi_aml_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
396 /***************************************************************************
398 * FUNCTION: Acpi_ev_release_global_lock
400 * DESCRIPTION: Releases ownership of the Global Lock.
402 **************************************************************************/
405 acpi_ev_release_global_lock (void)
411 if (!acpi_gbl_global_lock_thread_count) {
412 REPORT_WARNING(("Global Lock has not be acquired, cannot release\n"));
416 /* One fewer thread has the global lock */
418 acpi_gbl_global_lock_thread_count--;
420 /* Have all threads released the lock? */
422 if (!acpi_gbl_global_lock_thread_count) {
424 * No more threads holding lock, we can do the actual hardware
428 global_lock = acpi_gbl_FACS->global_lock;
429 ACPI_RELEASE_GLOBAL_LOCK (global_lock, pending);
430 acpi_gbl_global_lock_acquired = FALSE;
433 * If the pending bit was set, we must write GBL_RLS to the control
437 acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK,