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