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
29 #define _COMPONENT ACPI_EVENTS
30 MODULE_NAME ("evmisc")
33 /**************************************************************************
35 * FUNCTION: Acpi_ev_queue_notify_request
41 * DESCRIPTION: Dispatch a device notification event to a previously
44 *************************************************************************/
47 acpi_ev_queue_notify_request (
48 ACPI_NAMESPACE_NODE
*node
,
51 ACPI_OPERAND_OBJECT
*obj_desc
;
52 ACPI_OPERAND_OBJECT
*handler_obj
= NULL
;
53 ACPI_GENERIC_STATE
*notify_info
;
54 ACPI_STATUS status
= AE_OK
;
58 * For value 1 (Ejection Request), some device method may need to be run.
59 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
60 * For value 0x80 (Status Change) on the power button or sleep button,
61 * initiate soft-off or sleep operation?
64 switch (notify_value
) {
83 * Get the notify object attached to the device Node
86 obj_desc
= acpi_ns_get_attached_object ((ACPI_HANDLE
) node
);
89 /* We have the notify object, Get the right handler */
92 case ACPI_TYPE_DEVICE
:
93 if (notify_value
<= MAX_SYS_NOTIFY
) {
94 handler_obj
= obj_desc
->device
.sys_handler
;
97 handler_obj
= obj_desc
->device
.drv_handler
;
101 case ACPI_TYPE_THERMAL
:
102 if (notify_value
<= MAX_SYS_NOTIFY
) {
103 handler_obj
= obj_desc
->thermal_zone
.sys_handler
;
106 handler_obj
= obj_desc
->thermal_zone
.drv_handler
;
113 /* If there is any handler to run, schedule the dispatcher */
115 if ((acpi_gbl_sys_notify
.handler
&& (notify_value
<= MAX_SYS_NOTIFY
)) ||
116 (acpi_gbl_drv_notify
.handler
&& (notify_value
> MAX_SYS_NOTIFY
)) ||
119 notify_info
= acpi_cm_create_generic_state ();
121 return (AE_NO_MEMORY
);
124 notify_info
->notify
.node
= node
;
125 notify_info
->notify
.value
= (u16
) notify_value
;
126 notify_info
->notify
.handler_obj
= handler_obj
;
128 status
= acpi_os_queue_for_execution (OSD_PRIORITY_HIGH
,
129 acpi_ev_notify_dispatch
, notify_info
);
130 if (ACPI_FAILURE (status
)) {
131 acpi_cm_delete_generic_state (notify_info
);
136 /* There is no per-device notify handler for this device */
145 /**************************************************************************
147 * FUNCTION: Acpi_ev_notify_dispatch
153 * DESCRIPTION: Dispatch a device notification event to a previously
156 *************************************************************************/
159 acpi_ev_notify_dispatch (
162 ACPI_GENERIC_STATE
*notify_info
= (ACPI_GENERIC_STATE
*) context
;
163 NOTIFY_HANDLER global_handler
= NULL
;
164 void *global_context
= NULL
;
165 ACPI_OPERAND_OBJECT
*handler_obj
;
169 * We will invoke a global notify handler if installed.
170 * This is done _before_ we invoke the per-device handler attached to the device.
173 if (notify_info
->notify
.value
<= MAX_SYS_NOTIFY
) {
174 /* Global system notification handler */
176 if (acpi_gbl_sys_notify
.handler
) {
177 global_handler
= acpi_gbl_sys_notify
.handler
;
178 global_context
= acpi_gbl_sys_notify
.context
;
183 /* Global driver notification handler */
185 if (acpi_gbl_drv_notify
.handler
) {
186 global_handler
= acpi_gbl_drv_notify
.handler
;
187 global_context
= acpi_gbl_drv_notify
.context
;
192 /* Invoke the system handler first, if present */
194 if (global_handler
) {
195 global_handler (notify_info
->notify
.node
, notify_info
->notify
.value
, global_context
);
198 /* Now invoke the per-device handler, if present */
200 handler_obj
= notify_info
->notify
.handler_obj
;
202 handler_obj
->notify_handler
.handler (notify_info
->notify
.node
, notify_info
->notify
.value
,
203 handler_obj
->notify_handler
.context
);
207 /* All done with the info object */
209 acpi_cm_delete_generic_state (notify_info
);
213 /***************************************************************************
215 * FUNCTION: Acpi_ev_global_lock_thread
219 * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
220 * Global Lock. Simply signal all threads that are waiting
223 **************************************************************************/
226 acpi_ev_global_lock_thread (
230 /* Signal threads that are waiting for the lock */
232 if (acpi_gbl_global_lock_thread_count
) {
233 /* Send sufficient units to the semaphore */
235 acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore
,
236 acpi_gbl_global_lock_thread_count
);
241 /***************************************************************************
243 * FUNCTION: Acpi_ev_global_lock_handler
247 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
248 * release interrupt occurs. Grab the global lock and queue
249 * the global lock thread for execution
251 **************************************************************************/
254 acpi_ev_global_lock_handler (
262 * Attempt to get the lock
263 * If we don't get it now, it will be marked pending and we will
264 * take another interrupt when it becomes free.
267 global_lock
= acpi_gbl_FACS
->global_lock
;
268 ACPI_ACQUIRE_GLOBAL_LOCK (global_lock
, acquired
);
270 /* Got the lock, now wake all threads waiting for it */
272 acpi_gbl_global_lock_acquired
= TRUE
;
274 /* Run the Global Lock thread which will signal all waiting threads */
276 acpi_os_queue_for_execution (OSD_PRIORITY_HIGH
, acpi_ev_global_lock_thread
,
280 return (INTERRUPT_HANDLED
);
284 /***************************************************************************
286 * FUNCTION: Acpi_ev_init_global_lock_handler
290 * DESCRIPTION: Install a handler for the global lock release event
292 **************************************************************************/
295 acpi_ev_init_global_lock_handler (void)
300 acpi_gbl_global_lock_present
= TRUE
;
301 status
= acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL
,
302 acpi_ev_global_lock_handler
, NULL
);
305 * If the global lock does not exist on this platform, the attempt
306 * to enable GBL_STS will fail (the GBL_EN bit will not stick)
307 * Map to AE_OK, but mark global lock as not present.
308 * Any attempt to actually use the global lock will be flagged
311 if (status
== AE_NO_HARDWARE_RESPONSE
) {
312 acpi_gbl_global_lock_present
= FALSE
;
320 /***************************************************************************
322 * FUNCTION: Acpi_ev_acquire_global_lock
326 * DESCRIPTION: Attempt to gain ownership of the Global Lock.
328 **************************************************************************/
331 acpi_ev_acquire_global_lock(void)
333 ACPI_STATUS status
= AE_OK
;
338 /* Make sure that we actually have a global lock */
340 if (!acpi_gbl_global_lock_present
) {
341 return (AE_NO_GLOBAL_LOCK
);
344 /* One more thread wants the global lock */
346 acpi_gbl_global_lock_thread_count
++;
349 /* If we (OS side) have the hardware lock already, we are done */
351 if (acpi_gbl_global_lock_acquired
) {
355 /* Only if the FACS is valid */
357 if (!acpi_gbl_FACS
) {
362 /* We must acquire the actual hardware lock */
364 global_lock
= acpi_gbl_FACS
->global_lock
;
365 ACPI_ACQUIRE_GLOBAL_LOCK (global_lock
, acquired
);
367 /* We got the lock */
369 acpi_gbl_global_lock_acquired
= TRUE
;
376 * Did not get the lock. The pending bit was set above, and we must now
377 * wait until we get the global lock released interrupt.
381 * Acquire the global lock semaphore first.
382 * Since this wait will block, we must release the interpreter
385 status
= acpi_aml_system_wait_semaphore (acpi_gbl_global_lock_semaphore
,
392 /***************************************************************************
394 * FUNCTION: Acpi_ev_release_global_lock
396 * DESCRIPTION: Releases ownership of the Global Lock.
398 **************************************************************************/
401 acpi_ev_release_global_lock (void)
407 if (!acpi_gbl_global_lock_thread_count
) {
408 REPORT_WARNING(("Global Lock has not be acquired, cannot release\n"));
412 /* One fewer thread has the global lock */
414 acpi_gbl_global_lock_thread_count
--;
416 /* Have all threads released the lock? */
418 if (!acpi_gbl_global_lock_thread_count
) {
420 * No more threads holding lock, we can do the actual hardware
424 global_lock
= acpi_gbl_FACS
->global_lock
;
425 ACPI_RELEASE_GLOBAL_LOCK (global_lock
, pending
);
426 acpi_gbl_global_lock_acquired
= FALSE
;
429 * If the pending bit was set, we must write GBL_RLS to the control
433 acpi_hw_register_bit_access (ACPI_WRITE
, ACPI_MTX_LOCK
,