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
,