1 /******************************************************************************
2 *
3 * Module Name: evxface - External interfaces for ACPI events
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2004, R. Byron Moore
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
45 #include <acpi/acpi.h>
46 #include <acpi/acnamesp.h>
47 #include <acpi/acevents.h>
48 #include <acpi/acinterp.h>
49
50 #define _COMPONENT ACPI_EVENTS
51 ACPI_MODULE_NAME ("evxface")
52
53
54 /*******************************************************************************
55 *
56 * FUNCTION: acpi_install_fixed_event_handler
57 *
58 * PARAMETERS: Event - Event type to enable.
59 * Handler - Pointer to the handler function for the
60 * event
61 * Context - Value passed to the handler on each GPE
62 *
63 * RETURN: Status
64 *
65 * DESCRIPTION: Saves the pointer to the handler function and then enables the
66 * event.
67 *
68 ******************************************************************************/
69
70 acpi_status
acpi_install_fixed_event_handler(u32 event,acpi_event_handler handler,void * context)71 acpi_install_fixed_event_handler (
72 u32 event,
73 acpi_event_handler handler,
74 void *context)
75 {
76 acpi_status status;
77
78
79 ACPI_FUNCTION_TRACE ("acpi_install_fixed_event_handler");
80
81
82 /* Parameter validation */
83
84 if (event > ACPI_EVENT_MAX) {
85 return_ACPI_STATUS (AE_BAD_PARAMETER);
86 }
87
88 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
89 if (ACPI_FAILURE (status)) {
90 return_ACPI_STATUS (status);
91 }
92
93 /* Don't allow two handlers. */
94
95 if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
96 status = AE_ALREADY_EXISTS;
97 goto cleanup;
98 }
99
100 /* Install the handler before enabling the event */
101
102 acpi_gbl_fixed_event_handlers[event].handler = handler;
103 acpi_gbl_fixed_event_handlers[event].context = context;
104
105 status = acpi_enable_event (event, 0);
106 if (ACPI_FAILURE (status)) {
107 ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n"));
108
109 /* Remove the handler */
110
111 acpi_gbl_fixed_event_handlers[event].handler = NULL;
112 acpi_gbl_fixed_event_handlers[event].context = NULL;
113 }
114 else {
115 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
116 "Enabled fixed event %X, Handler=%p\n", event, handler));
117 }
118
119
120 cleanup:
121 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
122 return_ACPI_STATUS (status);
123 }
124
125
126 /*******************************************************************************
127 *
128 * FUNCTION: acpi_remove_fixed_event_handler
129 *
130 * PARAMETERS: Event - Event type to disable.
131 * Handler - Address of the handler
132 *
133 * RETURN: Status
134 *
135 * DESCRIPTION: Disables the event and unregisters the event handler.
136 *
137 ******************************************************************************/
138
139 acpi_status
acpi_remove_fixed_event_handler(u32 event,acpi_event_handler handler)140 acpi_remove_fixed_event_handler (
141 u32 event,
142 acpi_event_handler handler)
143 {
144 acpi_status status = AE_OK;
145
146
147 ACPI_FUNCTION_TRACE ("acpi_remove_fixed_event_handler");
148
149
150 /* Parameter validation */
151
152 if (event > ACPI_EVENT_MAX) {
153 return_ACPI_STATUS (AE_BAD_PARAMETER);
154 }
155
156 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
157 if (ACPI_FAILURE (status)) {
158 return_ACPI_STATUS (status);
159 }
160
161 /* Disable the event before removing the handler */
162
163 status = acpi_disable_event (event, 0);
164
165 /* Always Remove the handler */
166
167 acpi_gbl_fixed_event_handlers[event].handler = NULL;
168 acpi_gbl_fixed_event_handlers[event].context = NULL;
169
170 if (ACPI_FAILURE (status)) {
171 ACPI_DEBUG_PRINT ((ACPI_DB_WARN,
172 "Could not write to fixed event enable register.\n"));
173 }
174 else {
175 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X.\n", event));
176 }
177
178 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
179 return_ACPI_STATUS (status);
180 }
181
182
183 /*******************************************************************************
184 *
185 * FUNCTION: acpi_install_notify_handler
186 *
187 * PARAMETERS: Device - The device for which notifies will be handled
188 * handler_type - The type of handler:
189 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
190 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
191 * Handler - Address of the handler
192 * Context - Value passed to the handler on each GPE
193 *
194 * RETURN: Status
195 *
196 * DESCRIPTION: Install a handler for notifies on an ACPI device
197 *
198 ******************************************************************************/
199
200 acpi_status
acpi_install_notify_handler(acpi_handle device,u32 handler_type,acpi_notify_handler handler,void * context)201 acpi_install_notify_handler (
202 acpi_handle device,
203 u32 handler_type,
204 acpi_notify_handler handler,
205 void *context)
206 {
207 union acpi_operand_object *obj_desc;
208 union acpi_operand_object *notify_obj;
209 struct acpi_namespace_node *node;
210 acpi_status status;
211
212
213 ACPI_FUNCTION_TRACE ("acpi_install_notify_handler");
214
215
216 /* Parameter validation */
217
218 if ((!device) ||
219 (!handler) ||
220 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
221 return_ACPI_STATUS (AE_BAD_PARAMETER);
222 }
223
224 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
225 if (ACPI_FAILURE (status)) {
226 return_ACPI_STATUS (status);
227 }
228
229 /* Convert and validate the device handle */
230
231 node = acpi_ns_map_handle_to_node (device);
232 if (!node) {
233 status = AE_BAD_PARAMETER;
234 goto unlock_and_exit;
235 }
236
237 /*
238 * Root Object:
239 * Registering a notify handler on the root object indicates that the
240 * caller wishes to receive notifications for all objects. Note that
241 * only one <external> global handler can be regsitered (per notify type).
242 */
243 if (device == ACPI_ROOT_OBJECT) {
244 /* Make sure the handler is not already installed */
245
246 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
247 acpi_gbl_system_notify.handler) ||
248 ((handler_type == ACPI_DEVICE_NOTIFY) &&
249 acpi_gbl_device_notify.handler)) {
250 status = AE_ALREADY_EXISTS;
251 goto unlock_and_exit;
252 }
253
254 if (handler_type == ACPI_SYSTEM_NOTIFY) {
255 acpi_gbl_system_notify.node = node;
256 acpi_gbl_system_notify.handler = handler;
257 acpi_gbl_system_notify.context = context;
258 }
259 else /* ACPI_DEVICE_NOTIFY */ {
260 acpi_gbl_device_notify.node = node;
261 acpi_gbl_device_notify.handler = handler;
262 acpi_gbl_device_notify.context = context;
263 }
264
265 /* Global notify handler installed */
266 }
267
268 /*
269 * All Other Objects:
270 * Caller will only receive notifications specific to the target object.
271 * Note that only certain object types can receive notifications.
272 */
273 else {
274 /* Notifies allowed on this object? */
275
276 if (!acpi_ev_is_notify_object (node)) {
277 status = AE_TYPE;
278 goto unlock_and_exit;
279 }
280
281 /* Check for an existing internal object */
282
283 obj_desc = acpi_ns_get_attached_object (node);
284 if (obj_desc) {
285 /* Object exists - make sure there's no handler */
286
287 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
288 obj_desc->common_notify.system_notify) ||
289 ((handler_type == ACPI_DEVICE_NOTIFY) &&
290 obj_desc->common_notify.device_notify)) {
291 status = AE_ALREADY_EXISTS;
292 goto unlock_and_exit;
293 }
294 }
295 else {
296 /* Create a new object */
297
298 obj_desc = acpi_ut_create_internal_object (node->type);
299 if (!obj_desc) {
300 status = AE_NO_MEMORY;
301 goto unlock_and_exit;
302 }
303
304 /* Attach new object to the Node */
305
306 status = acpi_ns_attach_object (device, obj_desc, node->type);
307
308 /* Remove local reference to the object */
309
310 acpi_ut_remove_reference (obj_desc);
311
312 if (ACPI_FAILURE (status)) {
313 goto unlock_and_exit;
314 }
315 }
316
317 /* Install the handler */
318
319 notify_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_NOTIFY);
320 if (!notify_obj) {
321 status = AE_NO_MEMORY;
322 goto unlock_and_exit;
323 }
324
325 notify_obj->notify.node = node;
326 notify_obj->notify.handler = handler;
327 notify_obj->notify.context = context;
328
329 if (handler_type == ACPI_SYSTEM_NOTIFY) {
330 obj_desc->common_notify.system_notify = notify_obj;
331 }
332 else /* ACPI_DEVICE_NOTIFY */ {
333 obj_desc->common_notify.device_notify = notify_obj;
334 }
335 }
336
337
338 unlock_and_exit:
339 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
340 return_ACPI_STATUS (status);
341 }
342
343
344 /*******************************************************************************
345 *
346 * FUNCTION: acpi_remove_notify_handler
347 *
348 * PARAMETERS: Device - The device for which notifies will be handled
349 * handler_type - The type of handler:
350 * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
351 * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
352 * Handler - Address of the handler
353 * RETURN: Status
354 *
355 * DESCRIPTION: Remove a handler for notifies on an ACPI device
356 *
357 ******************************************************************************/
358
359 acpi_status
acpi_remove_notify_handler(acpi_handle device,u32 handler_type,acpi_notify_handler handler)360 acpi_remove_notify_handler (
361 acpi_handle device,
362 u32 handler_type,
363 acpi_notify_handler handler)
364 {
365 union acpi_operand_object *notify_obj;
366 union acpi_operand_object *obj_desc;
367 struct acpi_namespace_node *node;
368 acpi_status status;
369
370
371 ACPI_FUNCTION_TRACE ("acpi_remove_notify_handler");
372
373
374 /* Parameter validation */
375
376 if ((!device) ||
377 (!handler) ||
378 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
379 return_ACPI_STATUS (AE_BAD_PARAMETER);
380 }
381
382 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
383 if (ACPI_FAILURE (status)) {
384 return_ACPI_STATUS (status);
385 }
386
387 /* Convert and validate the device handle */
388
389 node = acpi_ns_map_handle_to_node (device);
390 if (!node) {
391 status = AE_BAD_PARAMETER;
392 goto unlock_and_exit;
393 }
394
395 /*
396 * Root Object
397 */
398 if (device == ACPI_ROOT_OBJECT) {
399 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n"));
400
401 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
402 !acpi_gbl_system_notify.handler) ||
403 ((handler_type == ACPI_DEVICE_NOTIFY) &&
404 !acpi_gbl_device_notify.handler)) {
405 status = AE_NOT_EXIST;
406 goto unlock_and_exit;
407 }
408
409 if (handler_type == ACPI_SYSTEM_NOTIFY) {
410 acpi_gbl_system_notify.node = NULL;
411 acpi_gbl_system_notify.handler = NULL;
412 acpi_gbl_system_notify.context = NULL;
413 }
414 else {
415 acpi_gbl_device_notify.node = NULL;
416 acpi_gbl_device_notify.handler = NULL;
417 acpi_gbl_device_notify.context = NULL;
418 }
419 }
420
421 /*
422 * All Other Objects
423 */
424 else {
425 /* Notifies allowed on this object? */
426
427 if (!acpi_ev_is_notify_object (node)) {
428 status = AE_TYPE;
429 goto unlock_and_exit;
430 }
431
432 /* Check for an existing internal object */
433
434 obj_desc = acpi_ns_get_attached_object (node);
435 if (!obj_desc) {
436 status = AE_NOT_EXIST;
437 goto unlock_and_exit;
438 }
439
440 /* Object exists - make sure there's an existing handler */
441
442 if (handler_type == ACPI_SYSTEM_NOTIFY) {
443 notify_obj = obj_desc->common_notify.system_notify;
444 }
445 else {
446 notify_obj = obj_desc->common_notify.device_notify;
447 }
448
449 if ((!notify_obj) ||
450 (notify_obj->notify.handler != handler)) {
451 status = AE_BAD_PARAMETER;
452 goto unlock_and_exit;
453 }
454
455 /* Remove the handler */
456
457 if (handler_type == ACPI_SYSTEM_NOTIFY) {
458 obj_desc->common_notify.system_notify = NULL;
459 }
460 else {
461 obj_desc->common_notify.device_notify = NULL;
462 }
463
464 acpi_ut_remove_reference (notify_obj);
465 }
466
467
468 unlock_and_exit:
469 (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
470 return_ACPI_STATUS (status);
471 }
472
473
474 /*******************************************************************************
475 *
476 * FUNCTION: acpi_install_gpe_handler
477 *
478 * PARAMETERS: gpe_number - The GPE number within the GPE block
479 * gpe_block - GPE block (NULL == FADT GPEs)
480 * Type - Whether this GPE should be treated as an
481 * edge- or level-triggered interrupt.
482 * Handler - Address of the handler
483 * Context - Value passed to the handler on each GPE
484 *
485 * RETURN: Status
486 *
487 * DESCRIPTION: Install a handler for a General Purpose Event.
488 *
489 ******************************************************************************/
490
491 acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,u32 gpe_number,u32 type,acpi_gpe_handler handler,void * context)492 acpi_install_gpe_handler (
493 acpi_handle gpe_device,
494 u32 gpe_number,
495 u32 type,
496 acpi_gpe_handler handler,
497 void *context)
498 {
499 acpi_status status;
500 struct acpi_gpe_event_info *gpe_event_info;
501
502
503 ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler");
504
505
506 /* Parameter validation */
507
508 if (!handler) {
509 return_ACPI_STATUS (AE_BAD_PARAMETER);
510 }
511
512 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
513 if (ACPI_FAILURE (status)) {
514 return_ACPI_STATUS (status);
515 }
516
517 /* Ensure that we have a valid GPE number */
518
519 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
520 if (!gpe_event_info) {
521 status = AE_BAD_PARAMETER;
522 goto unlock_and_exit;
523 }
524
525 /* Make sure that there isn't a handler there already */
526
527 if (gpe_event_info->handler) {
528 status = AE_ALREADY_EXISTS;
529 goto unlock_and_exit;
530 }
531
532 /* Install the handler */
533
534 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
535 gpe_event_info->handler = handler;
536 gpe_event_info->context = context;
537 gpe_event_info->flags = (u8) type;
538 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
539
540 /* Clear the GPE (of stale events), the enable it */
541
542 status = acpi_hw_clear_gpe (gpe_event_info);
543 if (ACPI_FAILURE (status)) {
544 goto unlock_and_exit;
545 }
546
547 status = acpi_hw_enable_gpe (gpe_event_info);
548
549
550 unlock_and_exit:
551 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
552 return_ACPI_STATUS (status);
553 }
554
555
556 /*******************************************************************************
557 *
558 * FUNCTION: acpi_remove_gpe_handler
559 *
560 * PARAMETERS: gpe_number - The event to remove a handler
561 * gpe_block - GPE block (NULL == FADT GPEs)
562 * Handler - Address of the handler
563 *
564 * RETURN: Status
565 *
566 * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
567 *
568 ******************************************************************************/
569
570 acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,u32 gpe_number,acpi_gpe_handler handler)571 acpi_remove_gpe_handler (
572 acpi_handle gpe_device,
573 u32 gpe_number,
574 acpi_gpe_handler handler)
575 {
576 acpi_status status;
577 struct acpi_gpe_event_info *gpe_event_info;
578
579
580 ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler");
581
582
583 /* Parameter validation */
584
585 if (!handler) {
586 return_ACPI_STATUS (AE_BAD_PARAMETER);
587 }
588
589 status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
590 if (ACPI_FAILURE (status)) {
591 return_ACPI_STATUS (status);
592 }
593
594 /* Ensure that we have a valid GPE number */
595
596 gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
597 if (!gpe_event_info) {
598 status = AE_BAD_PARAMETER;
599 goto unlock_and_exit;
600 }
601
602 /* Disable the GPE before removing the handler */
603
604 status = acpi_hw_disable_gpe (gpe_event_info);
605 if (ACPI_FAILURE (status)) {
606 goto unlock_and_exit;
607 }
608
609 /* Make sure that the installed handler is the same */
610
611 if (gpe_event_info->handler != handler) {
612 (void) acpi_hw_enable_gpe (gpe_event_info);
613 status = AE_BAD_PARAMETER;
614 goto unlock_and_exit;
615 }
616
617 /* Remove the handler */
618
619 acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
620 gpe_event_info->handler = NULL;
621 gpe_event_info->context = NULL;
622 acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
623
624
625 unlock_and_exit:
626 (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
627 return_ACPI_STATUS (status);
628 }
629
630
631 /*******************************************************************************
632 *
633 * FUNCTION: acpi_acquire_global_lock
634 *
635 * PARAMETERS: Timeout - How long the caller is willing to wait
636 * out_handle - A handle to the lock if acquired
637 *
638 * RETURN: Status
639 *
640 * DESCRIPTION: Acquire the ACPI Global Lock
641 *
642 ******************************************************************************/
643
644 acpi_status
acpi_acquire_global_lock(u16 timeout,u32 * handle)645 acpi_acquire_global_lock (
646 u16 timeout,
647 u32 *handle)
648 {
649 acpi_status status;
650
651
652 if (!handle) {
653 return (AE_BAD_PARAMETER);
654 }
655
656 status = acpi_ex_enter_interpreter ();
657 if (ACPI_FAILURE (status)) {
658 return (status);
659 }
660
661 status = acpi_ev_acquire_global_lock (timeout);
662 acpi_ex_exit_interpreter ();
663
664 if (ACPI_SUCCESS (status)) {
665 acpi_gbl_global_lock_handle++;
666 *handle = acpi_gbl_global_lock_handle;
667 }
668
669 return (status);
670 }
671
672
673 /*******************************************************************************
674 *
675 * FUNCTION: acpi_release_global_lock
676 *
677 * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
678 *
679 * RETURN: Status
680 *
681 * DESCRIPTION: Release the ACPI Global Lock
682 *
683 ******************************************************************************/
684
685 acpi_status
acpi_release_global_lock(u32 handle)686 acpi_release_global_lock (
687 u32 handle)
688 {
689 acpi_status status;
690
691
692 if (handle != acpi_gbl_global_lock_handle) {
693 return (AE_NOT_ACQUIRED);
694 }
695
696 status = acpi_ev_release_global_lock ();
697 return (status);
698 }
699
700
701