ACPICA: Implement simplified Table Manager
[deliverable/linux.git] / drivers / acpi / events / evmisc.c
CommitLineData
1da177e4
LT
1/******************************************************************************
2 *
3 * Module Name: evmisc - Miscellaneous event manager support functions
4 *
5 *****************************************************************************/
6
7/*
4a90c7e8 8 * Copyright (C) 2000 - 2006, R. Byron Moore
1da177e4
LT
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
25 *
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.
29 *
30 * NO WARRANTY
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.
42 */
43
44#include <acpi/acpi.h>
45#include <acpi/acevents.h>
46#include <acpi/acnamesp.h>
47#include <acpi/acinterp.h>
48
49#define _COMPONENT ACPI_EVENTS
4be44fcd 50ACPI_MODULE_NAME("evmisc")
1da177e4 51
4119532c 52/* Names for Notify() values, used for debug output */
44f6c012 53#ifdef ACPI_DEBUG_OUTPUT
4be44fcd 54static const char *acpi_notify_value_names[] = {
44f6c012
RM
55 "Bus Check",
56 "Device Check",
57 "Device Wake",
4119532c 58 "Eject Request",
44f6c012
RM
59 "Device Check Light",
60 "Frequency Mismatch",
61 "Bus Mode Mismatch",
62 "Power Fault"
63};
64#endif
65
f3d2e786
BM
66/* Pointer to FACS needed for the Global Lock */
67
68static struct acpi_table_facs *facs = NULL;
69
44f6c012
RM
70/* Local prototypes */
71
4be44fcd 72static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
44f6c012 73
4be44fcd 74static u32 acpi_ev_global_lock_handler(void *context);
44f6c012 75
1da177e4
LT
76/*******************************************************************************
77 *
78 * FUNCTION: acpi_ev_is_notify_object
79 *
80 * PARAMETERS: Node - Node to check
81 *
82 * RETURN: TRUE if notifies allowed on this object
83 *
84 * DESCRIPTION: Check type of node for a object that supports notifies.
85 *
86 * TBD: This could be replaced by a flag bit in the node.
87 *
88 ******************************************************************************/
89
4be44fcd 90u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
1da177e4
LT
91{
92 switch (node->type) {
93 case ACPI_TYPE_DEVICE:
94 case ACPI_TYPE_PROCESSOR:
95 case ACPI_TYPE_POWER:
96 case ACPI_TYPE_THERMAL:
97 /*
98 * These are the ONLY objects that can receive ACPI notifications
99 */
100 return (TRUE);
101
102 default:
103 return (FALSE);
104 }
105}
106
1da177e4
LT
107/*******************************************************************************
108 *
109 * FUNCTION: acpi_ev_queue_notify_request
110 *
111 * PARAMETERS: Node - NS node for the notified object
112 * notify_value - Value from the Notify() request
113 *
114 * RETURN: Status
115 *
116 * DESCRIPTION: Dispatch a device notification event to a previously
117 * installed handler.
118 *
119 ******************************************************************************/
120
1da177e4 121acpi_status
4be44fcd
LB
122acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
123 u32 notify_value)
1da177e4 124{
4be44fcd
LB
125 union acpi_operand_object *obj_desc;
126 union acpi_operand_object *handler_obj = NULL;
127 union acpi_generic_state *notify_info;
128 acpi_status status = AE_OK;
1da177e4 129
b229cf92 130 ACPI_FUNCTION_NAME(ev_queue_notify_request);
1da177e4
LT
131
132 /*
133 * For value 3 (Ejection Request), some device method may need to be run.
44f6c012
RM
134 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
135 * to be run.
1da177e4 136 * For value 0x80 (Status Change) on the power button or sleep button,
44f6c012 137 * initiate soft-off or sleep operation?
1da177e4 138 */
4be44fcd
LB
139 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
140 "Dispatching Notify(%X) on node %p\n", notify_value,
141 node));
1da177e4
LT
142
143 if (notify_value <= 7) {
4be44fcd
LB
144 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
145 acpi_notify_value_names[notify_value]));
146 } else {
147 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
148 "Notify value: 0x%2.2X **Device Specific**\n",
149 notify_value));
1da177e4
LT
150 }
151
152 /* Get the notify object attached to the NS Node */
153
4be44fcd 154 obj_desc = acpi_ns_get_attached_object(node);
1da177e4 155 if (obj_desc) {
52fc0b02 156
1da177e4
LT
157 /* We have the notify object, Get the right handler */
158
159 switch (node->type) {
160 case ACPI_TYPE_DEVICE:
161 case ACPI_TYPE_THERMAL:
162 case ACPI_TYPE_PROCESSOR:
163 case ACPI_TYPE_POWER:
164
165 if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
4be44fcd
LB
166 handler_obj =
167 obj_desc->common_notify.system_notify;
168 } else {
169 handler_obj =
170 obj_desc->common_notify.device_notify;
1da177e4
LT
171 }
172 break;
173
174 default:
175 /* All other types are not supported */
176 return (AE_TYPE);
177 }
178 }
179
180 /* If there is any handler to run, schedule the dispatcher */
181
4be44fcd
LB
182 if ((acpi_gbl_system_notify.handler
183 && (notify_value <= ACPI_MAX_SYS_NOTIFY))
184 || (acpi_gbl_device_notify.handler
185 && (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
186 notify_info = acpi_ut_create_generic_state();
1da177e4
LT
187 if (!notify_info) {
188 return (AE_NO_MEMORY);
189 }
190
61686124
BM
191 notify_info->common.descriptor_type =
192 ACPI_DESC_TYPE_STATE_NOTIFY;
4be44fcd
LB
193 notify_info->notify.node = node;
194 notify_info->notify.value = (u16) notify_value;
1da177e4
LT
195 notify_info->notify.handler_obj = handler_obj;
196
4119532c
BM
197 status =
198 acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
199 notify_info);
4be44fcd
LB
200 if (ACPI_FAILURE(status)) {
201 acpi_ut_delete_generic_state(notify_info);
1da177e4
LT
202 }
203 }
204
205 if (!handler_obj) {
206 /*
207 * There is no per-device notify handler for this device.
208 * This may or may not be a problem.
209 */
4be44fcd
LB
210 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
211 "No notify handler for Notify(%4.4s, %X) node %p\n",
212 acpi_ut_get_node_name(node), notify_value,
213 node));
1da177e4
LT
214 }
215
216 return (status);
217}
218
1da177e4
LT
219/*******************************************************************************
220 *
221 * FUNCTION: acpi_ev_notify_dispatch
222 *
44f6c012 223 * PARAMETERS: Context - To be passed to the notify handler
1da177e4
LT
224 *
225 * RETURN: None.
226 *
227 * DESCRIPTION: Dispatch a device notification event to a previously
228 * installed handler.
229 *
230 ******************************************************************************/
231
4be44fcd 232static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
1da177e4 233{
4be44fcd
LB
234 union acpi_generic_state *notify_info =
235 (union acpi_generic_state *)context;
236 acpi_notify_handler global_handler = NULL;
237 void *global_context = NULL;
238 union acpi_operand_object *handler_obj;
1da177e4 239
4be44fcd 240 ACPI_FUNCTION_ENTRY();
1da177e4
LT
241
242 /*
243 * We will invoke a global notify handler if installed.
44f6c012
RM
244 * This is done _before_ we invoke the per-device handler attached
245 * to the device.
1da177e4
LT
246 */
247 if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
52fc0b02 248
1da177e4
LT
249 /* Global system notification handler */
250
251 if (acpi_gbl_system_notify.handler) {
252 global_handler = acpi_gbl_system_notify.handler;
253 global_context = acpi_gbl_system_notify.context;
254 }
4be44fcd 255 } else {
1da177e4
LT
256 /* Global driver notification handler */
257
258 if (acpi_gbl_device_notify.handler) {
259 global_handler = acpi_gbl_device_notify.handler;
260 global_context = acpi_gbl_device_notify.context;
261 }
262 }
263
264 /* Invoke the system handler first, if present */
265
266 if (global_handler) {
4be44fcd
LB
267 global_handler(notify_info->notify.node,
268 notify_info->notify.value, global_context);
1da177e4
LT
269 }
270
271 /* Now invoke the per-device handler, if present */
272
273 handler_obj = notify_info->notify.handler_obj;
274 if (handler_obj) {
4be44fcd
LB
275 handler_obj->notify.handler(notify_info->notify.node,
276 notify_info->notify.value,
277 handler_obj->notify.context);
1da177e4
LT
278 }
279
280 /* All done with the info object */
281
4be44fcd 282 acpi_ut_delete_generic_state(notify_info);
1da177e4
LT
283}
284
1da177e4
LT
285/*******************************************************************************
286 *
287 * FUNCTION: acpi_ev_global_lock_handler
288 *
289 * PARAMETERS: Context - From thread interface, not used
290 *
a72d4756 291 * RETURN: ACPI_INTERRUPT_HANDLED
1da177e4
LT
292 *
293 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
a72d4756
BM
294 * release interrupt occurs. Attempt to acquire the global lock,
295 * if successful, signal the thread waiting for the lock.
296 *
297 * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
298 * this is not possible for some reason, a separate thread will have to be
299 * scheduled to do this.
1da177e4
LT
300 *
301 ******************************************************************************/
302
4be44fcd 303static u32 acpi_ev_global_lock_handler(void *context)
1da177e4 304{
4be44fcd 305 u8 acquired = FALSE;
1da177e4
LT
306
307 /*
c81da666
BM
308 * Attempt to get the lock.
309 *
1da177e4
LT
310 * If we don't get it now, it will be marked pending and we will
311 * take another interrupt when it becomes free.
312 */
f3d2e786 313 ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
1da177e4 314 if (acquired) {
52fc0b02 315
1da177e4 316 /* Got the lock, now wake all threads waiting for it */
c81da666 317
1da177e4 318 acpi_gbl_global_lock_acquired = TRUE;
a72d4756
BM
319 /* Send a unit to the semaphore */
320
321 if (ACPI_FAILURE(acpi_os_signal_semaphore(
322 acpi_gbl_global_lock_semaphore, 1))) {
323 ACPI_ERROR((AE_INFO,
324 "Could not signal Global Lock semaphore"));
325 }
1da177e4
LT
326 }
327
328 return (ACPI_INTERRUPT_HANDLED);
329}
330
1da177e4
LT
331/*******************************************************************************
332 *
333 * FUNCTION: acpi_ev_init_global_lock_handler
334 *
335 * PARAMETERS: None
336 *
337 * RETURN: Status
338 *
339 * DESCRIPTION: Install a handler for the global lock release event
340 *
341 ******************************************************************************/
342
4be44fcd 343acpi_status acpi_ev_init_global_lock_handler(void)
1da177e4 344{
4be44fcd 345 acpi_status status;
1da177e4 346
b229cf92 347 ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
1da177e4 348
f3d2e786
BM
349 status =
350 acpi_get_table(ACPI_SIG_FACS, 0,
351 (struct acpi_table_header **)&facs);
352 if (ACPI_FAILURE(status)) {
353 return_ACPI_STATUS(status);
354 }
355
1da177e4 356 acpi_gbl_global_lock_present = TRUE;
4be44fcd
LB
357 status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
358 acpi_ev_global_lock_handler,
359 NULL);
1da177e4
LT
360
361 /*
362 * If the global lock does not exist on this platform, the attempt
363 * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick)
364 * Map to AE_OK, but mark global lock as not present.
365 * Any attempt to actually use the global lock will be flagged
366 * with an error.
367 */
368 if (status == AE_NO_HARDWARE_RESPONSE) {
b8e4d893
BM
369 ACPI_ERROR((AE_INFO,
370 "No response from Global Lock hardware, disabling lock"));
0c9938cc 371
1da177e4
LT
372 acpi_gbl_global_lock_present = FALSE;
373 status = AE_OK;
374 }
375
4be44fcd 376 return_ACPI_STATUS(status);
1da177e4
LT
377}
378
1da177e4
LT
379/******************************************************************************
380 *
381 * FUNCTION: acpi_ev_acquire_global_lock
382 *
383 * PARAMETERS: Timeout - Max time to wait for the lock, in millisec.
384 *
385 * RETURN: Status
386 *
387 * DESCRIPTION: Attempt to gain ownership of the Global Lock.
388 *
c81da666
BM
389 * MUTEX: Interpreter must be locked
390 *
391 * Note: The original implementation allowed multiple threads to "acquire" the
392 * Global Lock, and the OS would hold the lock until the last thread had
393 * released it. However, this could potentially starve the BIOS out of the
394 * lock, especially in the case where there is a tight handshake between the
395 * Embedded Controller driver and the BIOS. Therefore, this implementation
396 * allows only one thread to acquire the HW Global Lock at a time, and makes
397 * the global lock appear as a standard mutex on the OS side.
398 *
1da177e4
LT
399 *****************************************************************************/
400
4be44fcd 401acpi_status acpi_ev_acquire_global_lock(u16 timeout)
1da177e4 402{
4be44fcd
LB
403 acpi_status status = AE_OK;
404 u8 acquired = FALSE;
1da177e4 405
b229cf92 406 ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
1da177e4 407
c81da666
BM
408 /*
409 * Only one thread can acquire the GL at a time, the global_lock_mutex
410 * enforces this. This interface releases the interpreter if we must wait.
411 */
412 status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
413 if (ACPI_FAILURE(status)) {
414 return_ACPI_STATUS(status);
1da177e4 415 }
1da177e4 416
44f6c012 417 /*
c81da666
BM
418 * Make sure that a global lock actually exists. If not, just treat
419 * the lock as a standard mutex.
44f6c012 420 */
c81da666
BM
421 if (!acpi_gbl_global_lock_present) {
422 acpi_gbl_global_lock_acquired = TRUE;
4be44fcd 423 return_ACPI_STATUS(AE_OK);
1da177e4
LT
424 }
425
c81da666 426 /* Attempt to acquire the actual hardware lock */
1da177e4 427
f3d2e786 428 ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
1da177e4 429 if (acquired) {
52fc0b02 430
4be44fcd 431 /* We got the lock */
1da177e4 432
4be44fcd 433 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
c81da666 434 "Acquired hardware Global Lock\n"));
1da177e4
LT
435
436 acpi_gbl_global_lock_acquired = TRUE;
4be44fcd 437 return_ACPI_STATUS(AE_OK);
1da177e4
LT
438 }
439
440 /*
c81da666 441 * Did not get the lock. The pending bit was set above, and we must now
1da177e4
LT
442 * wait until we get the global lock released interrupt.
443 */
c81da666 444 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
1da177e4
LT
445
446 /*
c81da666
BM
447 * Wait for handshake with the global lock interrupt handler.
448 * This interface releases the interpreter if we must wait.
1da177e4 449 */
c81da666
BM
450 status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
451 ACPI_WAIT_FOREVER);
f3d2e786 452
4be44fcd 453 return_ACPI_STATUS(status);
1da177e4
LT
454}
455
1da177e4
LT
456/*******************************************************************************
457 *
458 * FUNCTION: acpi_ev_release_global_lock
459 *
460 * PARAMETERS: None
461 *
462 * RETURN: Status
463 *
464 * DESCRIPTION: Releases ownership of the Global Lock.
465 *
466 ******************************************************************************/
467
4be44fcd 468acpi_status acpi_ev_release_global_lock(void)
1da177e4 469{
4be44fcd
LB
470 u8 pending = FALSE;
471 acpi_status status = AE_OK;
1da177e4 472
b229cf92 473 ACPI_FUNCTION_TRACE(ev_release_global_lock);
1da177e4 474
a72d4756 475 /* Lock must be already acquired */
c81da666
BM
476
477 if (!acpi_gbl_global_lock_acquired) {
b8e4d893 478 ACPI_WARNING((AE_INFO,
c81da666 479 "Cannot release the ACPI Global Lock, it has not been acquired"));
4be44fcd 480 return_ACPI_STATUS(AE_NOT_ACQUIRED);
1da177e4
LT
481 }
482
c81da666 483 if (acpi_gbl_global_lock_present) {
1da177e4 484
c81da666 485 /* Allow any thread to release the lock */
52fc0b02 486
f3d2e786 487 ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
1da177e4 488
c81da666
BM
489 /*
490 * If the pending bit was set, we must write GBL_RLS to the control
491 * register
492 */
493 if (pending) {
494 status =
495 acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
496 1, ACPI_MTX_LOCK);
497 }
498
499 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
500 "Released hardware Global Lock\n"));
1da177e4
LT
501 }
502
1da177e4
LT
503 acpi_gbl_global_lock_acquired = FALSE;
504
c81da666 505 /* Release the local GL mutex */
1da177e4 506
c81da666 507 acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
4be44fcd 508 return_ACPI_STATUS(status);
1da177e4
LT
509}
510
1da177e4
LT
511/******************************************************************************
512 *
513 * FUNCTION: acpi_ev_terminate
514 *
515 * PARAMETERS: none
516 *
517 * RETURN: none
518 *
519 * DESCRIPTION: Disable events and free memory allocated for table storage.
520 *
521 ******************************************************************************/
522
4be44fcd 523void acpi_ev_terminate(void)
1da177e4 524{
4be44fcd
LB
525 acpi_native_uint i;
526 acpi_status status;
1da177e4 527
b229cf92 528 ACPI_FUNCTION_TRACE(ev_terminate);
1da177e4
LT
529
530 if (acpi_gbl_events_initialized) {
531 /*
532 * Disable all event-related functionality.
533 * In all cases, on error, print a message but obviously we don't abort.
534 */
535
536 /* Disable all fixed events */
537
538 for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
4be44fcd
LB
539 status = acpi_disable_event((u32) i, 0);
540 if (ACPI_FAILURE(status)) {
b8e4d893
BM
541 ACPI_ERROR((AE_INFO,
542 "Could not disable fixed event %d",
543 (u32) i));
1da177e4
LT
544 }
545 }
546
547 /* Disable all GPEs in all GPE blocks */
548
4be44fcd 549 status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
1da177e4
LT
550
551 /* Remove SCI handler */
552
4be44fcd 553 status = acpi_ev_remove_sci_handler();
1da177e4 554 if (ACPI_FAILURE(status)) {
b8e4d893 555 ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
1da177e4
LT
556 }
557 }
558
559 /* Deallocate all handler objects installed within GPE info structs */
560
4be44fcd 561 status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers);
1da177e4
LT
562
563 /* Return to original mode if necessary */
564
565 if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
4be44fcd
LB
566 status = acpi_disable();
567 if (ACPI_FAILURE(status)) {
b229cf92 568 ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
1da177e4
LT
569 }
570 }
571 return_VOID;
572}
This page took 0.169001 seconds and 5 git commands to generate.