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