Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-serial
[linux-2.6] / drivers / acpi / events / evevent.c
1 /******************************************************************************
2  *
3  * Module Name: evevent - Fixed Event handling and dispatch
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2006, 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 #include <acpi/acpi.h>
45 #include <acpi/acevents.h>
46
47 #define _COMPONENT          ACPI_EVENTS
48 ACPI_MODULE_NAME("evevent")
49
50 /* Local prototypes */
51 static acpi_status acpi_ev_fixed_event_initialize(void);
52
53 static u32 acpi_ev_fixed_event_dispatch(u32 event);
54
55 /*******************************************************************************
56  *
57  * FUNCTION:    acpi_ev_initialize_events
58  *
59  * PARAMETERS:  None
60  *
61  * RETURN:      Status
62  *
63  * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE)
64  *
65  ******************************************************************************/
66
67 acpi_status acpi_ev_initialize_events(void)
68 {
69         acpi_status status;
70
71         ACPI_FUNCTION_TRACE(ev_initialize_events);
72
73         /* Make sure we have ACPI tables */
74
75         if (!acpi_gbl_DSDT) {
76                 ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
77                 return_ACPI_STATUS(AE_NO_ACPI_TABLES);
78         }
79
80         /*
81          * Initialize the Fixed and General Purpose Events. This is done prior to
82          * enabling SCIs to prevent interrupts from occurring before the handlers are
83          * installed.
84          */
85         status = acpi_ev_fixed_event_initialize();
86         if (ACPI_FAILURE(status)) {
87                 ACPI_EXCEPTION((AE_INFO, status,
88                                 "Unable to initialize fixed events"));
89                 return_ACPI_STATUS(status);
90         }
91
92         status = acpi_ev_gpe_initialize();
93         if (ACPI_FAILURE(status)) {
94                 ACPI_EXCEPTION((AE_INFO, status,
95                                 "Unable to initialize general purpose events"));
96                 return_ACPI_STATUS(status);
97         }
98
99         return_ACPI_STATUS(status);
100 }
101
102 /*******************************************************************************
103  *
104  * FUNCTION:    acpi_ev_install_fadt_gpes
105  *
106  * PARAMETERS:  None
107  *
108  * RETURN:      Status
109  *
110  * DESCRIPTION: Completes initialization of the FADT-defined GPE blocks
111  *              (0 and 1). This causes the _PRW methods to be run, so the HW
112  *              must be fully initialized at this point, including global lock
113  *              support.
114  *
115  ******************************************************************************/
116
117 acpi_status acpi_ev_install_fadt_gpes(void)
118 {
119         acpi_status status;
120
121         ACPI_FUNCTION_TRACE(ev_install_fadt_gpes);
122
123         /* Namespace must be locked */
124
125         status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
126         if (ACPI_FAILURE(status)) {
127                 return (status);
128         }
129
130         /* FADT GPE Block 0 */
131
132         (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
133                                            acpi_gbl_gpe_fadt_blocks[0]);
134
135         /* FADT GPE Block 1 */
136
137         (void)acpi_ev_initialize_gpe_block(acpi_gbl_fadt_gpe_device,
138                                            acpi_gbl_gpe_fadt_blocks[1]);
139
140         (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
141         return_ACPI_STATUS(AE_OK);
142 }
143
144 /*******************************************************************************
145  *
146  * FUNCTION:    acpi_ev_install_xrupt_handlers
147  *
148  * PARAMETERS:  None
149  *
150  * RETURN:      Status
151  *
152  * DESCRIPTION: Install interrupt handlers for the SCI and Global Lock
153  *
154  ******************************************************************************/
155
156 acpi_status acpi_ev_install_xrupt_handlers(void)
157 {
158         acpi_status status;
159
160         ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers);
161
162         /* Install the SCI handler */
163
164         status = acpi_ev_install_sci_handler();
165         if (ACPI_FAILURE(status)) {
166                 ACPI_EXCEPTION((AE_INFO, status,
167                                 "Unable to install System Control Interrupt handler"));
168                 return_ACPI_STATUS(status);
169         }
170
171         /* Install the handler for the Global Lock */
172
173         status = acpi_ev_init_global_lock_handler();
174         if (ACPI_FAILURE(status)) {
175                 ACPI_EXCEPTION((AE_INFO, status,
176                                 "Unable to initialize Global Lock handler"));
177                 return_ACPI_STATUS(status);
178         }
179
180         acpi_gbl_events_initialized = TRUE;
181         return_ACPI_STATUS(status);
182 }
183
184 /*******************************************************************************
185  *
186  * FUNCTION:    acpi_ev_fixed_event_initialize
187  *
188  * PARAMETERS:  None
189  *
190  * RETURN:      Status
191  *
192  * DESCRIPTION: Install the fixed event handlers and enable the fixed events.
193  *
194  ******************************************************************************/
195
196 static acpi_status acpi_ev_fixed_event_initialize(void)
197 {
198         acpi_native_uint i;
199         acpi_status status;
200
201         /*
202          * Initialize the structure that keeps track of fixed event handlers
203          * and enable the fixed events.
204          */
205         for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
206                 acpi_gbl_fixed_event_handlers[i].handler = NULL;
207                 acpi_gbl_fixed_event_handlers[i].context = NULL;
208
209                 /* Enable the fixed event */
210
211                 if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
212                         status =
213                             acpi_set_register(acpi_gbl_fixed_event_info[i].
214                                               enable_register_id, 0,
215                                               ACPI_MTX_LOCK);
216                         if (ACPI_FAILURE(status)) {
217                                 return (status);
218                         }
219                 }
220         }
221
222         return (AE_OK);
223 }
224
225 /*******************************************************************************
226  *
227  * FUNCTION:    acpi_ev_fixed_event_detect
228  *
229  * PARAMETERS:  None
230  *
231  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
232  *
233  * DESCRIPTION: Checks the PM status register for active fixed events
234  *
235  ******************************************************************************/
236
237 u32 acpi_ev_fixed_event_detect(void)
238 {
239         u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
240         u32 fixed_status;
241         u32 fixed_enable;
242         acpi_native_uint i;
243
244         ACPI_FUNCTION_NAME(ev_fixed_event_detect);
245
246         /*
247          * Read the fixed feature status and enable registers, as all the cases
248          * depend on their values.  Ignore errors here.
249          */
250         (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
251                                     ACPI_REGISTER_PM1_STATUS, &fixed_status);
252         (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
253                                     ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
254
255         ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
256                           "Fixed Event Block: Enable %08X Status %08X\n",
257                           fixed_enable, fixed_status));
258
259         /*
260          * Check for all possible Fixed Events and dispatch those that are active
261          */
262         for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
263
264                 /* Both the status and enable bits must be on for this event */
265
266                 if ((fixed_status & acpi_gbl_fixed_event_info[i].
267                      status_bit_mask)
268                     && (fixed_enable & acpi_gbl_fixed_event_info[i].
269                         enable_bit_mask)) {
270
271                         /* Found an active (signalled) event */
272
273                         int_status |= acpi_ev_fixed_event_dispatch((u32) i);
274                 }
275         }
276
277         return (int_status);
278 }
279
280 /*******************************************************************************
281  *
282  * FUNCTION:    acpi_ev_fixed_event_dispatch
283  *
284  * PARAMETERS:  Event               - Event type
285  *
286  * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
287  *
288  * DESCRIPTION: Clears the status bit for the requested event, calls the
289  *              handler that previously registered for the event.
290  *
291  ******************************************************************************/
292
293 static u32 acpi_ev_fixed_event_dispatch(u32 event)
294 {
295
296         ACPI_FUNCTION_ENTRY();
297
298         /* Clear the status bit */
299
300         (void)acpi_set_register(acpi_gbl_fixed_event_info[event].
301                                 status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
302
303         /*
304          * Make sure we've got a handler.  If not, report an error.
305          * The event is disabled to prevent further interrupts.
306          */
307         if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
308                 (void)acpi_set_register(acpi_gbl_fixed_event_info[event].
309                                         enable_register_id, 0,
310                                         ACPI_MTX_DO_NOT_LOCK);
311
312                 ACPI_ERROR((AE_INFO,
313                             "No installed handler for fixed event [%08X]",
314                             event));
315
316                 return (ACPI_INTERRUPT_NOT_HANDLED);
317         }
318
319         /* Invoke the Fixed Event handler */
320
321         return ((acpi_gbl_fixed_event_handlers[event].
322                  handler) (acpi_gbl_fixed_event_handlers[event].context));
323 }