:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / hardware / hwacpi.c
1
2 /******************************************************************************
3  *
4  * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
5  *              $Revision$
6  *
7  *****************************************************************************/
8
9 /*
10  *  Copyright (C) 2000, 2001 R. Byron Moore
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27
28 #include "acpi.h"
29 #include "achware.h"
30
31
32 #define _COMPONENT          ACPI_HARDWARE
33          MODULE_NAME         ("hwacpi")
34
35
36 /******************************************************************************
37  *
38  * FUNCTION:    Acpi_hw_initialize
39  *
40  * PARAMETERS:  None
41  *
42  * RETURN:      Status
43  *
44  * DESCRIPTION: Initialize and validate various ACPI registers
45  *
46  ******************************************************************************/
47
48 ACPI_STATUS
49 acpi_hw_initialize (
50         void)
51 {
52         ACPI_STATUS             status = AE_OK;
53         u32                     index;
54
55
56         /* We must have the ACPI tables by the time we get here */
57
58         if (!acpi_gbl_FADT) {
59                 acpi_gbl_restore_acpi_chipset = FALSE;
60
61                 return (AE_NO_ACPI_TABLES);
62         }
63
64         /* Must support *some* mode! */
65 /*
66         if (!(System_flags & SYS_MODES_MASK))
67         {
68                 Restore_acpi_chipset = FALSE;
69
70                 return (AE_ERROR);
71         }
72
73 */
74
75
76         switch (acpi_gbl_system_flags & SYS_MODES_MASK) {
77                 /* Identify current ACPI/legacy mode   */
78
79         case (SYS_MODE_ACPI):
80
81                 acpi_gbl_original_mode = SYS_MODE_ACPI;
82                 break;
83
84
85         case (SYS_MODE_LEGACY):
86
87                 acpi_gbl_original_mode = SYS_MODE_LEGACY;
88                 break;
89
90
91         case (SYS_MODE_ACPI | SYS_MODE_LEGACY):
92
93                 if (acpi_hw_get_mode () == SYS_MODE_ACPI) {
94                         acpi_gbl_original_mode = SYS_MODE_ACPI;
95                 }
96                 else {
97                         acpi_gbl_original_mode = SYS_MODE_LEGACY;
98                 }
99
100                 break;
101         }
102
103
104         if (acpi_gbl_system_flags & SYS_MODE_ACPI) {
105                 /* Target system supports ACPI mode */
106
107                 /*
108                  * The purpose of this code is to save the initial state
109                  * of the ACPI event enable registers. An exit function will be
110                  * registered which will restore this state when the application
111                  * exits. The exit function will also clear all of the ACPI event
112                  * status bits prior to restoring the original mode.
113                  *
114                  * The location of the PM1a_evt_blk enable registers is defined as the
115                  * base of PM1a_evt_blk + DIV_2(PM1a_evt_blk_length). Since the spec further
116                  * fully defines the PM1a_evt_blk to be a total of 4 bytes, the offset
117                  * for the enable registers is always 2 from the base. It is hard
118                  * coded here. If this changes in the spec, this code will need to
119                  * be modified. The PM1b_evt_blk behaves as expected.
120                  */
121
122                 acpi_gbl_pm1_enable_register_save = (u16) acpi_hw_register_read (ACPI_MTX_LOCK, PM1_EN);
123
124
125                 /*
126                  * The GPEs behave similarly, except that the length of the register
127                  * block is not fixed, so the buffer must be allocated with malloc
128                  */
129
130                 if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) &&
131                         acpi_gbl_FADT->gpe0blk_len) {
132                         /* GPE0 specified in FADT  */
133
134                         acpi_gbl_gpe0enable_register_save =
135                                 acpi_cm_allocate (DIV_2 (acpi_gbl_FADT->gpe0blk_len));
136                         if (!acpi_gbl_gpe0enable_register_save) {
137                                 return (AE_NO_MEMORY);
138                         }
139
140                         /* Save state of GPE0 enable bits */
141
142                         for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe0blk_len); index++) {
143                                 acpi_gbl_gpe0enable_register_save[index] =
144                                         (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE0_EN_BLOCK | index);
145                         }
146                 }
147
148                 else {
149                         acpi_gbl_gpe0enable_register_save = NULL;
150                 }
151
152                 if (ACPI_VALID_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) &&
153                         acpi_gbl_FADT->gpe1_blk_len) {
154                         /* GPE1 defined */
155
156                         acpi_gbl_gpe1_enable_register_save =
157                                 acpi_cm_allocate (DIV_2 (acpi_gbl_FADT->gpe1_blk_len));
158                         if (!acpi_gbl_gpe1_enable_register_save) {
159                                 return (AE_NO_MEMORY);
160                         }
161
162                         /* save state of GPE1 enable bits */
163
164                         for (index = 0; index < DIV_2 (acpi_gbl_FADT->gpe1_blk_len); index++) {
165                                 acpi_gbl_gpe1_enable_register_save[index] =
166                                         (u8) acpi_hw_register_read (ACPI_MTX_LOCK, GPE1_EN_BLOCK | index);
167                         }
168                 }
169
170                 else {
171                         acpi_gbl_gpe1_enable_register_save = NULL;
172                 }
173         }
174
175         return (status);
176 }
177
178
179 /******************************************************************************
180  *
181  * FUNCTION:    Acpi_hw_set_mode
182  *
183  * PARAMETERS:  Mode            - SYS_MODE_ACPI or SYS_MODE_LEGACY
184  *
185  * RETURN:      Status
186  *
187  * DESCRIPTION: Transitions the system into the requested mode or does nothing
188  *              if the system is already in that mode.
189  *
190  ******************************************************************************/
191
192 ACPI_STATUS
193 acpi_hw_set_mode (
194         u32                     mode)
195 {
196
197         ACPI_STATUS             status = AE_NO_HARDWARE_RESPONSE;
198
199
200         if (mode == SYS_MODE_ACPI) {
201                 /* BIOS should have disabled ALL fixed and GP events */
202
203                 acpi_os_out8 (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_enable);
204         }
205
206         else if (mode == SYS_MODE_LEGACY) {
207                 /*
208                  * BIOS should clear all fixed status bits and restore fixed event
209                  * enable bits to default
210                  */
211
212                 acpi_os_out8 (acpi_gbl_FADT->smi_cmd, acpi_gbl_FADT->acpi_disable);
213         }
214
215         if (acpi_hw_get_mode () == mode) {
216                 status = AE_OK;
217         }
218
219         return (status);
220 }
221
222
223 /******************************************************************************
224  *
225  * FUNCTION:    Acpi_hw_get_mode
226  *
227  * PARAMETERS:  none
228  *
229  * RETURN:      SYS_MODE_ACPI or SYS_MODE_LEGACY
230  *
231  * DESCRIPTION: Return current operating state of system.  Determined by
232  *              querying the SCI_EN bit.
233  *
234  ******************************************************************************/
235
236 u32
237 acpi_hw_get_mode (void)
238 {
239
240
241         if (acpi_hw_register_bit_access (ACPI_READ, ACPI_MTX_LOCK, SCI_EN)) {
242                 return (SYS_MODE_ACPI);
243         }
244         else {
245                 return (SYS_MODE_LEGACY);
246         }
247 }
248
249 /******************************************************************************
250  *
251  * FUNCTION:    Acpi_hw_get_mode_capabilities
252  *
253  * PARAMETERS:  none
254  *
255  * RETURN:      logical OR of SYS_MODE_ACPI and SYS_MODE_LEGACY determined at initial
256  *              system state.
257  *
258  * DESCRIPTION: Returns capablities of system
259  *
260  ******************************************************************************/
261
262 u32
263 acpi_hw_get_mode_capabilities (void)
264 {
265
266
267         if (!(acpi_gbl_system_flags & SYS_MODES_MASK)) {
268                 if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
269                         /*
270                          * Assume that if this call is being made, Acpi_init has been called
271                          * and ACPI support has been established by the presence of the
272                          * tables.  Therefore since we're in SYS_MODE_LEGACY, the system
273                          * must support both modes
274                          */
275
276                         acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
277                 }
278
279                 else {
280                         /* TBD: [Investigate] !!! this may be unsafe... */
281                         /*
282                          * system is is ACPI mode, so try to switch back to LEGACY to see if
283                          * it is supported
284                          */
285                         acpi_hw_set_mode (SYS_MODE_LEGACY);
286
287                         if (acpi_hw_get_mode () == SYS_MODE_LEGACY) {
288                                 /* Now in SYS_MODE_LEGACY, so both are supported */
289
290                                 acpi_gbl_system_flags |= (SYS_MODE_ACPI | SYS_MODE_LEGACY);
291                                 acpi_hw_set_mode (SYS_MODE_ACPI);
292                         }
293
294                         else {
295                                 /* Still in SYS_MODE_ACPI so this must be an ACPI only system */
296
297                                 acpi_gbl_system_flags |= SYS_MODE_ACPI;
298                         }
299                 }
300         }
301
302         return (acpi_gbl_system_flags & SYS_MODES_MASK);
303 }
304
305