ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / acpi / hardware / hwgpe.c
1
2 /******************************************************************************
3  *
4  * Module Name: hwgpe - Low level GPE enable/disable/clear functions
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2004, R. Byron Moore
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44
45 #include <acpi/acpi.h>
46 #include <acpi/acevents.h>
47
48 #define _COMPONENT          ACPI_HARDWARE
49          ACPI_MODULE_NAME    ("hwgpe")
50
51
52 /******************************************************************************
53  *
54  * FUNCTION:    acpi_hw_enable_gpe
55  *
56  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
57  *
58  * RETURN:      Status
59  *
60  * DESCRIPTION: Enable a single GPE.
61  *
62  ******************************************************************************/
63
64 acpi_status
65 acpi_hw_enable_gpe (
66         struct acpi_gpe_event_info      *gpe_event_info)
67 {
68         u32                             in_byte;
69         acpi_status                     status;
70
71
72         ACPI_FUNCTION_ENTRY ();
73
74
75         /*
76          * Read the current value of the register, set the appropriate bit
77          * to enable the GPE, and write out the new register.
78          */
79         status = acpi_hw_low_level_read (8, &in_byte,
80                           &gpe_event_info->register_info->enable_address);
81         if (ACPI_FAILURE (status)) {
82                 return (status);
83         }
84
85         /* Write with the new GPE bit enabled */
86
87         status = acpi_hw_low_level_write (8, (in_byte | gpe_event_info->bit_mask),
88                           &gpe_event_info->register_info->enable_address);
89
90         return (status);
91 }
92
93
94 /******************************************************************************
95  *
96  * FUNCTION:    acpi_hw_enable_gpe_for_wakeup
97  *
98  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
99  *
100  * RETURN:      None
101  *
102  * DESCRIPTION: Keep track of which GPEs the OS has requested not be
103  *              disabled when going to sleep.
104  *
105  ******************************************************************************/
106
107 void
108 acpi_hw_enable_gpe_for_wakeup (
109         struct acpi_gpe_event_info      *gpe_event_info)
110 {
111         struct acpi_gpe_register_info   *gpe_register_info;
112
113
114         ACPI_FUNCTION_ENTRY ();
115
116
117         /* Get the info block for the entire GPE register */
118
119         gpe_register_info = gpe_event_info->register_info;
120         if (!gpe_register_info) {
121                 return;
122         }
123
124         /*
125          * Set the bit so we will not enable this GPE when sleeping (and disable
126          * it upon wake)
127          */
128         gpe_register_info->wake_enable |= gpe_event_info->bit_mask;
129         gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED);
130 }
131
132
133 /******************************************************************************
134  *
135  * FUNCTION:    acpi_hw_disable_gpe
136  *
137  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
138  *
139  * RETURN:      Status
140  *
141  * DESCRIPTION: Disable a single GPE.
142  *
143  ******************************************************************************/
144
145 acpi_status
146 acpi_hw_disable_gpe (
147         struct acpi_gpe_event_info      *gpe_event_info)
148 {
149         u32                             in_byte;
150         acpi_status                     status;
151         struct acpi_gpe_register_info   *gpe_register_info;
152
153
154         ACPI_FUNCTION_ENTRY ();
155
156
157         /* Get the info block for the entire GPE register */
158
159         gpe_register_info = gpe_event_info->register_info;
160         if (!gpe_register_info) {
161                 return (AE_BAD_PARAMETER);
162         }
163
164         /*
165          * Read the current value of the register, clear the appropriate bit,
166          * and write out the new register value to disable the GPE.
167          */
168         status = acpi_hw_low_level_read (8, &in_byte,
169                           &gpe_register_info->enable_address);
170         if (ACPI_FAILURE (status)) {
171                 return (status);
172         }
173
174         /* Write the byte with this GPE bit cleared */
175
176         status = acpi_hw_low_level_write (8, (in_byte & ~(gpe_event_info->bit_mask)),
177                           &gpe_register_info->enable_address);
178         if (ACPI_FAILURE (status)) {
179                 return (status);
180         }
181
182         /* Make sure this GPE is disabled for wake, also */
183
184         acpi_hw_disable_gpe_for_wakeup (gpe_event_info);
185         return (AE_OK);
186 }
187
188
189 /******************************************************************************
190  *
191  * FUNCTION:    acpi_hw_disable_gpe_for_wakeup
192  *
193  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
194  *
195  * RETURN:      None
196  *
197  * DESCRIPTION: Keep track of which GPEs the OS has requested not be
198  *              disabled when going to sleep.
199  *
200  ******************************************************************************/
201
202 void
203 acpi_hw_disable_gpe_for_wakeup (
204         struct acpi_gpe_event_info      *gpe_event_info)
205 {
206         struct acpi_gpe_register_info   *gpe_register_info;
207
208
209         ACPI_FUNCTION_ENTRY ();
210
211
212         /* Get the info block for the entire GPE register */
213
214         gpe_register_info = gpe_event_info->register_info;
215         if (!gpe_register_info) {
216                 return;
217         }
218
219         /* Clear the bit so we will disable this when sleeping */
220
221         gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask);
222 }
223
224
225 /******************************************************************************
226  *
227  * FUNCTION:    acpi_hw_clear_gpe
228  *
229  * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
230  *
231  * RETURN:      status_status
232  *
233  * DESCRIPTION: Clear the status bit for a single GPE.
234  *
235  ******************************************************************************/
236
237 acpi_status
238 acpi_hw_clear_gpe (
239         struct acpi_gpe_event_info      *gpe_event_info)
240 {
241         acpi_status                     status;
242
243
244         ACPI_FUNCTION_ENTRY ();
245
246
247         /*
248          * Write a one to the appropriate bit in the status register to
249          * clear this GPE.
250          */
251         status = acpi_hw_low_level_write (8, gpe_event_info->bit_mask,
252                           &gpe_event_info->register_info->status_address);
253
254         return (status);
255 }
256
257
258 /******************************************************************************
259  *
260  * FUNCTION:    acpi_hw_get_gpe_status
261  *
262  * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
263  *              event_status        - Where the GPE status is returned
264  *
265  * RETURN:      Status
266  *
267  * DESCRIPTION: Return the status of a single GPE.
268  *
269  ******************************************************************************/
270
271 acpi_status
272 acpi_hw_get_gpe_status (
273         struct acpi_gpe_event_info      *gpe_event_info,
274         acpi_event_status               *event_status)
275 {
276         u32                             in_byte;
277         u8                              bit_mask;
278         struct acpi_gpe_register_info   *gpe_register_info;
279         acpi_status                     status;
280         acpi_event_status               local_event_status = 0;
281
282
283         ACPI_FUNCTION_ENTRY ();
284
285
286         if (!event_status) {
287                 return (AE_BAD_PARAMETER);
288         }
289
290         /* Get the info block for the entire GPE register */
291
292         gpe_register_info = gpe_event_info->register_info;
293
294         /* Get the register bitmask for this GPE */
295
296         bit_mask = gpe_event_info->bit_mask;
297
298         /* GPE Enabled? */
299
300         status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address);
301         if (ACPI_FAILURE (status)) {
302                 goto unlock_and_exit;
303         }
304
305         if (bit_mask & in_byte) {
306                 local_event_status |= ACPI_EVENT_FLAG_ENABLED;
307         }
308
309         /* GPE Enabled for wake? */
310
311         if (bit_mask & gpe_register_info->wake_enable) {
312                 local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
313         }
314
315         /* GPE active (set)? */
316
317         status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address);
318         if (ACPI_FAILURE (status)) {
319                 goto unlock_and_exit;
320         }
321
322         if (bit_mask & in_byte) {
323                 local_event_status |= ACPI_EVENT_FLAG_SET;
324         }
325
326         /* Set return value */
327
328         (*event_status) = local_event_status;
329
330
331 unlock_and_exit:
332         return (status);
333 }
334
335
336 /******************************************************************************
337  *
338  * FUNCTION:    acpi_hw_disable_gpe_block
339  *
340  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
341  *              gpe_block           - Gpe Block info
342  *
343  * RETURN:      Status
344  *
345  * DESCRIPTION: Disable all GPEs within a GPE block
346  *
347  ******************************************************************************/
348
349 acpi_status
350 acpi_hw_disable_gpe_block (
351         struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
352         struct acpi_gpe_block_info      *gpe_block)
353 {
354         u32                             i;
355         acpi_status                     status;
356
357
358         /* Examine each GPE Register within the block */
359
360         for (i = 0; i < gpe_block->register_count; i++) {
361                 /* Disable all GPEs in this register */
362
363                 status = acpi_hw_low_level_write (8, 0x00,
364                                  &gpe_block->register_info[i].enable_address);
365                 if (ACPI_FAILURE (status)) {
366                         return (status);
367                 }
368         }
369
370         return (AE_OK);
371 }
372
373
374 /******************************************************************************
375  *
376  * FUNCTION:    acpi_hw_clear_gpe_block
377  *
378  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
379  *              gpe_block           - Gpe Block info
380  *
381  * RETURN:      Status
382  *
383  * DESCRIPTION: Clear status bits for all GPEs within a GPE block
384  *
385  ******************************************************************************/
386
387 acpi_status
388 acpi_hw_clear_gpe_block (
389         struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
390         struct acpi_gpe_block_info      *gpe_block)
391 {
392         u32                             i;
393         acpi_status                     status;
394
395
396         /* Examine each GPE Register within the block */
397
398         for (i = 0; i < gpe_block->register_count; i++) {
399                 /* Clear status on all GPEs in this register */
400
401                 status = acpi_hw_low_level_write (8, 0xFF,
402                                  &gpe_block->register_info[i].status_address);
403                 if (ACPI_FAILURE (status)) {
404                         return (status);
405                 }
406         }
407
408         return (AE_OK);
409 }
410
411
412 /******************************************************************************
413  *
414  * FUNCTION:    acpi_hw_prepare_gpe_block_for_sleep
415  *
416  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
417  *              gpe_block           - Gpe Block info
418  *
419  * RETURN:      Status
420  *
421  * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within
422  *              a single GPE block
423  *
424  ******************************************************************************/
425
426 static acpi_status
427 acpi_hw_prepare_gpe_block_for_sleep (
428         struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
429         struct acpi_gpe_block_info      *gpe_block)
430 {
431         u32                             i;
432         struct acpi_gpe_register_info   *gpe_register_info;
433         u32                             in_value;
434         acpi_status                     status;
435
436
437         /* Get the register info for the entire GPE block */
438
439         gpe_register_info = gpe_block->register_info;
440
441         /* Examine each GPE Register within the block */
442
443         for (i = 0; i < gpe_block->register_count; i++) {
444                 /*
445                  * Read the enabled/disabled status of all GPEs. We
446                  * will be using it to restore all the GPEs later.
447                  *
448                  * NOTE:  Wake GPEs are are ALL disabled at this time, so when we wake
449                  * and restore this register, they will be automatically disabled.
450                  */
451                 status = acpi_hw_low_level_read (8, &in_value,
452                                  &gpe_register_info->enable_address);
453                 if (ACPI_FAILURE (status)) {
454                         return (status);
455                 }
456
457                 gpe_register_info->enable = (u8) in_value;
458
459                 /*
460                  * 1) Disable all runtime GPEs
461                  * 2) Enable all wakeup GPEs
462                  */
463                 status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable,
464                                 &gpe_register_info->enable_address);
465                 if (ACPI_FAILURE (status)) {
466                         return (status);
467                 }
468
469                 /* Point to next GPE register */
470
471                 gpe_register_info++;
472         }
473
474         return (AE_OK);
475 }
476
477
478 /******************************************************************************
479  *
480  * FUNCTION:    acpi_hw_prepare_gpes_for_sleep
481  *
482  * PARAMETERS:  None
483  *
484  * RETURN:      Status
485  *
486  * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs.
487  *              Called with interrupts disabled. The interrupt handler also
488  *              modifies gpe_register_info->Enable, so it should not be
489  *              given the chance to run until after the runtime GPEs are
490  *              re-enabled.
491  *
492  ******************************************************************************/
493
494 acpi_status
495 acpi_hw_prepare_gpes_for_sleep (
496         void)
497 {
498         acpi_status                     status;
499
500
501         ACPI_FUNCTION_ENTRY ();
502
503
504         status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep);
505         return (status);
506 }
507
508
509 /******************************************************************************
510  *
511  * FUNCTION:    acpi_hw_restore_gpe_block_on_wake
512  *
513  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
514  *              gpe_block           - Gpe Block info
515  *
516  * RETURN:      Status
517  *
518  * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one
519  *              GPE block
520  *
521  ******************************************************************************/
522
523 static acpi_status
524 acpi_hw_restore_gpe_block_on_wake (
525         struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
526         struct acpi_gpe_block_info      *gpe_block)
527 {
528         u32                             i;
529         struct acpi_gpe_register_info   *gpe_register_info;
530         acpi_status                     status;
531
532
533         /* This callback processes one entire GPE block */
534
535         /* Get the register info for the entire GPE block */
536
537         gpe_register_info = gpe_block->register_info;
538
539         /* Examine each GPE register within the block */
540
541         for (i = 0; i < gpe_block->register_count; i++) {
542                 /* Clear the entire status register */
543
544                 status = acpi_hw_low_level_write (8, 0xFF,
545                                  &gpe_block->register_info[i].status_address);
546                 if (ACPI_FAILURE (status)) {
547                         return (status);
548                 }
549
550                 /*
551                  * Restore the GPE Enable register, which will do the following:
552                  *
553                  * 1) Disable all wakeup GPEs
554                  * 2) Enable all runtime GPEs
555                  *
556                  *  (On sleep, we saved the enabled status of all GPEs)
557                  */
558                 status = acpi_hw_low_level_write (8, gpe_register_info->enable,
559                                  &gpe_register_info->enable_address);
560                 if (ACPI_FAILURE (status)) {
561                         return (status);
562                 }
563
564                 /* Point to next GPE register */
565
566                 gpe_register_info++;
567         }
568
569         return (AE_OK);
570 }
571
572
573 /******************************************************************************
574  *
575  * FUNCTION:    acpi_hw_restore_gpes_on_wake
576  *
577  * PARAMETERS:  None
578  *
579  * RETURN:      Status
580  *
581  * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all
582  *              GPE blocks
583  *
584  ******************************************************************************/
585
586 acpi_status
587 acpi_hw_restore_gpes_on_wake (
588         void)
589 {
590         acpi_status                     status;
591
592
593         ACPI_FUNCTION_ENTRY ();
594
595
596         status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake);
597         return (status);
598 }