:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / events / evxface.c
1 /******************************************************************************
2  *
3  * Module Name: evxface - External interfaces for ACPI events
4  *              $Revision$
5  *
6  *****************************************************************************/
7
8 /*
9  *  Copyright (C) 2000, 2001 R. Byron Moore
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25
26
27 #include "acpi.h"
28 #include "achware.h"
29 #include "acnamesp.h"
30 #include "acevents.h"
31 #include "amlcode.h"
32 #include "acinterp.h"
33
34 #define _COMPONENT          ACPI_EVENTS
35          MODULE_NAME         ("evxface")
36
37
38 /******************************************************************************
39  *
40  * FUNCTION:    Acpi_install_fixed_event_handler
41  *
42  * PARAMETERS:  Event           - Event type to enable.
43  *              Handler         - Pointer to the handler function for the
44  *                                event
45  *              Context         - Value passed to the handler on each GPE
46  *
47  * RETURN:      Status
48  *
49  * DESCRIPTION: Saves the pointer to the handler function and then enables the
50  *              event.
51  *
52  ******************************************************************************/
53
54 ACPI_STATUS
55 acpi_install_fixed_event_handler (
56         u32                     event,
57         FIXED_EVENT_HANDLER     handler,
58         void                    *context)
59 {
60         ACPI_STATUS             status;
61
62
63         /* Parameter validation */
64
65         if (event >= NUM_FIXED_EVENTS) {
66                 return (AE_BAD_PARAMETER);
67         }
68
69         acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
70
71         /* Don't allow two handlers. */
72
73         if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
74                 status = AE_EXIST;
75                 goto cleanup;
76         }
77
78
79         /* Install the handler before enabling the event - just in case... */
80
81         acpi_gbl_fixed_event_handlers[event].handler = handler;
82         acpi_gbl_fixed_event_handlers[event].context = context;
83
84         status = acpi_enable_event (event, ACPI_EVENT_FIXED);
85         if (!ACPI_SUCCESS (status)) {
86                 /* Remove the handler */
87
88                 acpi_gbl_fixed_event_handlers[event].handler = NULL;
89                 acpi_gbl_fixed_event_handlers[event].context = NULL;
90         }
91
92
93
94 cleanup:
95         acpi_cm_release_mutex (ACPI_MTX_EVENTS);
96         return (status);
97 }
98
99
100 /******************************************************************************
101  *
102  * FUNCTION:    Acpi_remove_fixed_event_handler
103  *
104  * PARAMETERS:  Event           - Event type to disable.
105  *              Handler         - Address of the handler
106  *
107  * RETURN:      Status
108  *
109  * DESCRIPTION: Disables the event and unregisters the event handler.
110  *
111  ******************************************************************************/
112
113 ACPI_STATUS
114 acpi_remove_fixed_event_handler (
115         u32                     event,
116         FIXED_EVENT_HANDLER     handler)
117 {
118         ACPI_STATUS             status = AE_OK;
119
120
121         /* Parameter validation */
122
123         if (event >= NUM_FIXED_EVENTS) {
124                 return (AE_BAD_PARAMETER);
125         }
126
127         acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
128
129         /* Disable the event before removing the handler - just in case... */
130
131         status = acpi_disable_event(event, ACPI_EVENT_FIXED);
132
133         /* Always Remove the handler */
134
135         acpi_gbl_fixed_event_handlers[event].handler = NULL;
136         acpi_gbl_fixed_event_handlers[event].context = NULL;
137
138
139
140
141         acpi_cm_release_mutex (ACPI_MTX_EVENTS);
142         return (status);
143 }
144
145
146 /******************************************************************************
147  *
148  * FUNCTION:    Acpi_install_notify_handler
149  *
150  * PARAMETERS:  Device          - The device for which notifies will be handled
151  *              Handler_type    - The type of handler:
152  *                                  ACPI_SYSTEM_NOTIFY: System_handler (00-7f)
153  *                                  ACPI_DEVICE_NOTIFY: Driver_handler (80-ff)
154  *              Handler         - Address of the handler
155  *              Context         - Value passed to the handler on each GPE
156  *
157  * RETURN:      Status
158  *
159  * DESCRIPTION: Install a handler for notifies on an ACPI device
160  *
161  ******************************************************************************/
162
163 ACPI_STATUS
164 acpi_install_notify_handler (
165         ACPI_HANDLE             device,
166         u32                     handler_type,
167         NOTIFY_HANDLER          handler,
168         void                    *context)
169 {
170         ACPI_OPERAND_OBJECT     *obj_desc;
171         ACPI_OPERAND_OBJECT     *notify_obj;
172         ACPI_NAMESPACE_NODE     *device_node;
173         ACPI_STATUS             status = AE_OK;
174
175
176         /* Parameter validation */
177
178         if ((!handler) ||
179                 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
180                 return (AE_BAD_PARAMETER);
181         }
182
183         acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
184
185         /* Convert and validate the device handle */
186
187         device_node = acpi_ns_convert_handle_to_entry (device);
188         if (!device_node) {
189                 status = AE_BAD_PARAMETER;
190                 goto unlock_and_exit;
191         }
192
193         /*
194          * Root Object:
195          * ------------
196          * Registering a notify handler on the root object indicates that the
197          * caller wishes to receive notifications for all objects.  Note that
198          * only one <external> global handler can be regsitered (per notify type).
199          */
200         if (device == ACPI_ROOT_OBJECT) {
201                 /* Make sure the handler is not already installed */
202
203                 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
204                           acpi_gbl_sys_notify.handler) ||
205                         ((handler_type == ACPI_DEVICE_NOTIFY) &&
206                           acpi_gbl_drv_notify.handler)) {
207                         status = AE_EXIST;
208                         goto unlock_and_exit;
209                 }
210
211                 if (handler_type == ACPI_SYSTEM_NOTIFY) {
212                         acpi_gbl_sys_notify.node = device_node;
213                         acpi_gbl_sys_notify.handler = handler;
214                         acpi_gbl_sys_notify.context = context;
215                 }
216                 else /* ACPI_DEVICE_NOTIFY */ {
217                         acpi_gbl_drv_notify.node = device_node;
218                         acpi_gbl_drv_notify.handler = handler;
219                         acpi_gbl_drv_notify.context = context;
220                 }
221
222                 /* Global notify handler installed */
223         }
224
225         /*
226          * Other Objects:
227          * --------------
228          * Caller will only receive notifications specific to the target object.
229          * Note that only certain object types can receive notifications.
230          */
231         else {
232                 /*
233                  * These are the ONLY objects that can receive ACPI notifications
234                  */
235                 if ((device_node->type != ACPI_TYPE_DEVICE)    &&
236                         (device_node->type != ACPI_TYPE_PROCESSOR) &&
237                         (device_node->type != ACPI_TYPE_POWER)     &&
238                         (device_node->type != ACPI_TYPE_THERMAL)) {
239                         status = AE_BAD_PARAMETER;
240                         goto unlock_and_exit;
241                 }
242
243                 /* Check for an existing internal object */
244
245                 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node);
246                 if (obj_desc) {
247
248                         /* Object exists - make sure there's no handler */
249
250                         if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
251                                   obj_desc->device.sys_handler) ||
252                                 ((handler_type == ACPI_DEVICE_NOTIFY) &&
253                                   obj_desc->device.drv_handler)) {
254                                 status = AE_EXIST;
255                                 goto unlock_and_exit;
256                         }
257                 }
258
259                 else {
260                         /* Create a new object */
261
262                         obj_desc = acpi_cm_create_internal_object (device_node->type);
263                         if (!obj_desc) {
264                                 status = AE_NO_MEMORY;
265                                 goto unlock_and_exit;
266                         }
267
268                         /* Attach new object to the Node */
269
270                         status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type);
271
272                         if (ACPI_FAILURE (status)) {
273                                 goto unlock_and_exit;
274                         }
275                 }
276
277                 /* Install the handler */
278
279                 notify_obj = acpi_cm_create_internal_object (INTERNAL_TYPE_NOTIFY);
280                 if (!notify_obj) {
281                         status = AE_NO_MEMORY;
282                         goto unlock_and_exit;
283                 }
284
285                 notify_obj->notify_handler.node = device_node;
286                 notify_obj->notify_handler.handler = handler;
287                 notify_obj->notify_handler.context = context;
288
289
290                 if (handler_type == ACPI_SYSTEM_NOTIFY) {
291                         obj_desc->device.sys_handler = notify_obj;
292                 }
293                 else /* ACPI_DEVICE_NOTIFY */ {
294                         obj_desc->device.drv_handler = notify_obj;
295                 }
296         }
297
298 unlock_and_exit:
299         acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
300         return (status);
301 }
302
303
304 /*****************************************************************************
305  *
306  * FUNCTION:    Acpi_remove_notify_handler
307  *
308  * PARAMETERS:  Device          - The device for which notifies will be handled
309  *              Handler_type    - The type of handler:
310  *                                  ACPI_SYSTEM_NOTIFY: System_handler (00-7f)
311  *                                  ACPI_DEVICE_NOTIFY: Driver_handler (80-ff)
312  *              Handler         - Address of the handler
313  * RETURN:      Status
314  *
315  * DESCRIPTION: Remove a handler for notifies on an ACPI device
316  *
317  ******************************************************************************/
318
319 ACPI_STATUS
320 acpi_remove_notify_handler (
321         ACPI_HANDLE             device,
322         u32                     handler_type,
323         NOTIFY_HANDLER          handler)
324 {
325         ACPI_OPERAND_OBJECT     *notify_obj;
326         ACPI_OPERAND_OBJECT     *obj_desc;
327         ACPI_NAMESPACE_NODE     *device_node;
328         ACPI_STATUS             status = AE_OK;
329
330         /* Parameter validation */
331
332         if ((!handler) ||
333                 (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
334                 return (AE_BAD_PARAMETER);
335         }
336
337         acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
338
339         /* Convert and validate the device handle */
340
341         device_node = acpi_ns_convert_handle_to_entry (device);
342         if (!device_node) {
343                 status = AE_BAD_PARAMETER;
344                 goto unlock_and_exit;
345         }
346
347         /*
348          * Root Object:
349          * ------------
350          */
351         if (device == ACPI_ROOT_OBJECT) {
352
353                 if (((handler_type == ACPI_SYSTEM_NOTIFY) &&
354                           !acpi_gbl_sys_notify.handler) ||
355                         ((handler_type == ACPI_DEVICE_NOTIFY) &&
356                           !acpi_gbl_drv_notify.handler)) {
357                         status = AE_NOT_EXIST;
358                         goto unlock_and_exit;
359                 }
360
361                 if (handler_type == ACPI_SYSTEM_NOTIFY) {
362                         acpi_gbl_sys_notify.node = NULL;
363                         acpi_gbl_sys_notify.handler = NULL;
364                         acpi_gbl_sys_notify.context = NULL;
365                 }
366                 else {
367                         acpi_gbl_drv_notify.node = NULL;
368                         acpi_gbl_drv_notify.handler = NULL;
369                         acpi_gbl_drv_notify.context = NULL;
370                 }
371         }
372
373         /*
374          * Other Objects:
375          * --------------
376          */
377         else {
378                 /*
379                  * These are the ONLY objects that can receive ACPI notifications
380                  */
381                 if ((device_node->type != ACPI_TYPE_DEVICE)    &&
382                         (device_node->type != ACPI_TYPE_PROCESSOR) &&
383                         (device_node->type != ACPI_TYPE_POWER)     &&
384                         (device_node->type != ACPI_TYPE_THERMAL)) {
385                         status = AE_BAD_PARAMETER;
386                         goto unlock_and_exit;
387                 }
388
389                 /* Check for an existing internal object */
390
391                 obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node);
392                 if (!obj_desc) {
393                         status = AE_NOT_EXIST;
394                         goto unlock_and_exit;
395                 }
396
397                 /* Object exists - make sure there's an existing handler */
398
399                 if (handler_type == ACPI_SYSTEM_NOTIFY) {
400                         notify_obj = obj_desc->device.sys_handler;
401                 }
402                 else {
403                         notify_obj = obj_desc->device.drv_handler;
404                 }
405
406                 if ((!notify_obj) ||
407                         (notify_obj->notify_handler.handler != handler)) {
408                         status = AE_BAD_PARAMETER;
409                         goto unlock_and_exit;
410                 }
411
412                 /* Remove the handler */
413
414                 if (handler_type == ACPI_SYSTEM_NOTIFY) {
415                         obj_desc->device.sys_handler = NULL;
416                 }
417                 else {
418                         obj_desc->device.drv_handler = NULL;
419                 }
420
421                 acpi_cm_remove_reference (notify_obj);
422         }
423
424
425 unlock_and_exit:
426         acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
427         return (status);
428 }
429
430
431 /******************************************************************************
432  *
433  * FUNCTION:    Acpi_install_gpe_handler
434  *
435  * PARAMETERS:  Gpe_number      - The GPE number.  The numbering scheme is
436  *                                bank 0 first, then bank 1.
437  *              Type            - Whether this GPE should be treated as an
438  *                                edge- or level-triggered interrupt.
439  *              Handler         - Address of the handler
440  *              Context         - Value passed to the handler on each GPE
441  *
442  * RETURN:      Status
443  *
444  * DESCRIPTION: Install a handler for a General Purpose Event.
445  *
446  ******************************************************************************/
447
448 ACPI_STATUS
449 acpi_install_gpe_handler (
450         u32                     gpe_number,
451         u32                     type,
452         GPE_HANDLER             handler,
453         void                    *context)
454 {
455         ACPI_STATUS             status = AE_OK;
456
457         /* Parameter validation */
458
459         if (!handler || (gpe_number > NUM_GPE)) {
460                 return (AE_BAD_PARAMETER);
461         }
462
463         /* Ensure that we have a valid GPE number */
464
465         if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
466                 return (AE_BAD_PARAMETER);
467         }
468
469         acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
470
471         /* Make sure that there isn't a handler there already */
472
473         if (acpi_gbl_gpe_info[gpe_number].handler) {
474                 status = AE_EXIST;
475                 goto cleanup;
476         }
477
478         /* Install the handler */
479
480         acpi_gbl_gpe_info[gpe_number].handler = handler;
481         acpi_gbl_gpe_info[gpe_number].context = context;
482         acpi_gbl_gpe_info[gpe_number].type = (u8) type;
483
484         /* Clear the GPE (of stale events), the enable it */
485
486         acpi_hw_clear_gpe (gpe_number);
487         acpi_hw_enable_gpe (gpe_number);
488
489 cleanup:
490         acpi_cm_release_mutex (ACPI_MTX_EVENTS);
491         return (status);
492 }
493
494
495 /******************************************************************************
496  *
497  * FUNCTION:    Acpi_remove_gpe_handler
498  *
499  * PARAMETERS:  Gpe_number      - The event to remove a handler
500  *              Handler         - Address of the handler
501  *
502  * RETURN:      Status
503  *
504  * DESCRIPTION: Remove a handler for a General Purpose Acpi_event.
505  *
506  ******************************************************************************/
507
508 ACPI_STATUS
509 acpi_remove_gpe_handler (
510         u32                     gpe_number,
511         GPE_HANDLER             handler)
512 {
513         ACPI_STATUS             status = AE_OK;
514
515
516         /* Parameter validation */
517
518         if (!handler || (gpe_number > NUM_GPE)) {
519                 return (AE_BAD_PARAMETER);
520         }
521
522         /* Ensure that we have a valid GPE number */
523
524         if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
525                 return (AE_BAD_PARAMETER);
526         }
527
528         /* Disable the GPE before removing the handler */
529
530         acpi_hw_disable_gpe (gpe_number);
531
532         acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
533
534         /* Make sure that the installed handler is the same */
535
536         if (acpi_gbl_gpe_info[gpe_number].handler != handler) {
537                 acpi_hw_enable_gpe (gpe_number);
538                 status = AE_BAD_PARAMETER;
539                 goto cleanup;
540         }
541
542         /* Remove the handler */
543
544         acpi_gbl_gpe_info[gpe_number].handler = NULL;
545         acpi_gbl_gpe_info[gpe_number].context = NULL;
546
547 cleanup:
548         acpi_cm_release_mutex (ACPI_MTX_EVENTS);
549         return (status);
550 }
551
552
553 /******************************************************************************
554  *
555  * FUNCTION:    Acpi_acquire_global_lock
556  *
557  * PARAMETERS:  Timeout         - How long the caller is willing to wait
558  *              Out_handle      - A handle to the lock if acquired
559  *
560  * RETURN:      Status
561  *
562  * DESCRIPTION: Acquire the ACPI Global Lock
563  *
564  ******************************************************************************/
565 ACPI_STATUS
566 acpi_acquire_global_lock (
567         void)
568 {
569         ACPI_STATUS             status;
570
571
572         status = acpi_aml_enter_interpreter ();
573         if (ACPI_FAILURE (status)) {
574                 return (status);
575         }
576
577         /*
578          * TBD: [Restructure] add timeout param to internal interface, and
579          * perhaps INTERPRETER_LOCKED
580          */
581
582         status = acpi_ev_acquire_global_lock ();
583         acpi_aml_exit_interpreter ();
584
585         return (status);
586 }
587
588
589 /******************************************************************************
590  *
591  * FUNCTION:    Acpi_release_global_lock
592  *
593  * PARAMETERS:  Handle      - Returned from Acpi_acquire_global_lock
594  *
595  * RETURN:      Status
596  *
597  * DESCRIPTION: Release the ACPI Global Lock
598  *
599  ******************************************************************************/
600
601 ACPI_STATUS
602 acpi_release_global_lock (
603         void)
604 {
605         acpi_ev_release_global_lock ();
606         return (AE_OK);
607 }
608
609