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