d0f0503f3662f1a8aaf5752e2b169b6f15115fdc
[reactos.git] / reactos / drivers / bus / acpi / busmgr / system.c
1 /*
2 * acpi_system.c - ACPI System Driver ($Revision: 57 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25
26 /* Modified for ReactOS and latest ACPICA
27 * Copyright (C)2009 Samuel Serapion
28 */
29 #include <ntddk.h>
30 #include <acpi.h>
31 #include <acpi_bus.h>
32 #include <acpi_drivers.h>
33 #include "list.h"
34
35 //#define NDEBUG
36 #include <debug.h>
37
38 ACPI_STATUS acpi_system_save_state(UINT32);
39
40 #define _COMPONENT ACPI_SYSTEM_COMPONENT
41 ACPI_MODULE_NAME ("acpi_system")
42
43 #define PREFIX "ACPI: "
44
45 static int acpi_system_add (struct acpi_device *device);
46 static int acpi_system_remove (struct acpi_device *device, int type);
47
48 ACPI_STATUS acpi_suspend (UINT32 state);
49
50 static struct acpi_driver acpi_system_driver = {
51 .name = ACPI_SYSTEM_DRIVER_NAME,
52 .class = ACPI_SYSTEM_CLASS,
53 .ids = ACPI_SYSTEM_HID,
54 .ops = {
55 .add = acpi_system_add,
56 .remove = acpi_system_remove
57 },
58 };
59
60 struct acpi_system
61 {
62 ACPI_HANDLE handle;
63 UINT8 states[ACPI_S_STATE_COUNT];
64 };
65
66
67 static int
68 acpi_system_add (
69 struct acpi_device *device)
70 {
71 int result = 0;
72 ACPI_STATUS status = AE_OK;
73 struct acpi_system *system = NULL;
74 UINT8 i = 0;
75
76 ACPI_FUNCTION_TRACE("acpi_system_add");
77
78 if (!device)
79 return_VALUE(-1);
80
81 system = ExAllocatePool(NonPagedPool,sizeof(struct acpi_system));
82 if (!system)
83 return_VALUE(-14);
84 memset(system, 0, sizeof(struct acpi_system));
85
86 system->handle = device->handle;
87 sprintf(acpi_device_name(device), "%s", ACPI_SYSTEM_DEVICE_NAME);
88 sprintf(acpi_device_class(device), "%s", ACPI_SYSTEM_CLASS);
89 acpi_driver_data(device) = system;
90
91 DPRINT("%s [%s] (supports",
92 acpi_device_name(device), acpi_device_bid(device));
93 for (i=0; i<ACPI_S_STATE_COUNT; i++) {
94 UINT8 type_a, type_b;
95 status = AcpiGetSleepTypeData(i, &type_a, &type_b);
96 switch (i) {
97 case ACPI_STATE_S4:
98 if (/*AcpiGbl_FACS->S4bios_f &&*/
99 0 != AcpiGbl_FADT.SmiCommand) {
100 DPRINT(" S4bios");
101 system->states[i] = 1;
102 }
103 /* no break */
104 default:
105 if (ACPI_SUCCESS(status)) {
106 system->states[i] = 1;
107 DPRINT(" S%d", i);
108 }
109 }
110 }
111
112 //#ifdef CONFIG_PM
113 // /* Install the soft-off (S5) handler. */
114 // if (system->states[ACPI_STATE_S5]) {
115 // pm_power_off = acpi_power_off;
116 // register_sysrq_key('o', &sysrq_acpi_poweroff_op);
117 // }
118 //#endif
119
120 if (result)
121 ExFreePool(system);
122
123 return_VALUE(result);
124 }
125
126 static int
127 acpi_system_remove (
128 struct acpi_device *device,
129 int type)
130 {
131 struct acpi_system *system = NULL;
132
133 ACPI_FUNCTION_TRACE("acpi_system_remove");
134
135 if (!device || !acpi_driver_data(device))
136 return_VALUE(-1);
137
138 system = (struct acpi_system *) acpi_driver_data(device);
139
140 //#ifdef CONFIG_PM
141 // /* Remove the soft-off (S5) handler. */
142 // if (system->states[ACPI_STATE_S5]) {
143 // unregister_sysrq_key('o', &sysrq_acpi_poweroff_op);
144 // pm_power_off = NULL;
145 // }
146 //#endif
147 //
148 //
149 ExFreePool(system);
150
151 return 0;
152 }
153
154 /**
155 * acpi_system_restore_state - OS-specific restoration of state
156 * @state: sleep state we're exiting
157 *
158 * Note that if we're coming back from S4, the memory image should have
159 * already been loaded from the disk and is already in place. (Otherwise how
160 * else would we be here?).
161 */
162 ACPI_STATUS
163 acpi_system_restore_state(
164 UINT32 state)
165 {
166 /*
167 * We should only be here if we're coming back from STR or STD.
168 * And, in the case of the latter, the memory image should have already
169 * been loaded from disk.
170 */
171 if (state > ACPI_STATE_S1) {
172 //acpi_restore_state_mem();
173
174 /* Do _early_ resume for irqs. Required by
175 * ACPI specs.
176 */
177 /* TBD: call arch dependant reinitialization of the
178 * interrupts.
179 */
180 #ifdef _X86_
181 //init_8259A(0);
182 #endif
183 /* wait for power to come back */
184 KeStallExecutionProcessor(100);
185
186 }
187
188 /* Be really sure that irqs are disabled. */
189 //ACPI_DISABLE_IRQS();
190
191 /* Wait a little again, just in case... */
192 KeStallExecutionProcessor(10);
193
194 /* enable interrupts once again */
195 //ACPI_ENABLE_IRQS();
196
197 /* turn all the devices back on */
198 //if (state > ACPI_STATE_S1)
199 //pm_send_all(PM_RESUME, (void *)0);
200
201 return AE_OK;
202 }
203
204
205 /**
206 * acpi_system_save_state - save OS specific state and power down devices
207 * @state: sleep state we're entering.
208 *
209 * This handles saving all context to memory, and possibly disk.
210 * First, we call to the device driver layer to save device state.
211 * Once we have that, we save whatevery processor and kernel state we
212 * need to memory.
213 * If we're entering S4, we then write the memory image to disk.
214 *
215 * Only then it is safe for us to power down devices, since we may need
216 * the disks and upstream buses to write to.
217 */
218 ACPI_STATUS
219 acpi_system_save_state(
220 UINT32 state)
221 {
222 int error = 0;
223
224 /* Send notification to devices that they will be suspended.
225 * If any device or driver cannot make the transition, either up
226 * or down, we'll get an error back.
227 */
228 /*if (state > ACPI_STATE_S1) {
229 error = pm_send_all(PM_SAVE_STATE, (void *)3);
230 if (error)
231 return AE_ERROR;
232 }*/
233
234 //if (state <= ACPI_STATE_S5) {
235 // /* Tell devices to stop I/O and actually save their state.
236 // * It is theoretically possible that something could fail,
237 // * so handle that gracefully..
238 // */
239 // if (state > ACPI_STATE_S1 && state != ACPI_STATE_S5) {
240 // error = pm_send_all(PM_SUSPEND, (void *)3);
241 // if (error) {
242 // /* Tell devices to restore state if they have
243 // * it saved and to start taking I/O requests.
244 // */
245 // pm_send_all(PM_RESUME, (void *)0);
246 // return error;
247 // }
248 // }
249
250 /* flush caches */
251 ACPI_FLUSH_CPU_CACHE();
252
253 /* Do arch specific saving of state. */
254 if (state > ACPI_STATE_S1) {
255 error = 0;//acpi_save_state_mem();
256
257 /* TBD: if no s4bios, write codes for
258 * acpi_save_state_disk()...
259 */
260 #if 0
261 if (!error && (state == ACPI_STATE_S4))
262 error = acpi_save_state_disk();
263 #endif
264 /*if (error) {
265 pm_send_all(PM_RESUME, (void *)0);
266 return error;
267 }*/
268 }
269 //}
270 /* disable interrupts
271 * Note that acpi_suspend -- our caller -- will do this once we return.
272 * But, we want it done early, so we don't get any suprises during
273 * the device suspend sequence.
274 */
275 //ACPI_DISABLE_IRQS();
276
277 /* Unconditionally turn off devices.
278 * Obvious if we enter a sleep state.
279 * If entering S5 (soft off), this should put devices in a
280 * quiescent state.
281 */
282
283 //if (state > ACPI_STATE_S1) {
284 // error = pm_send_all(PM_SUSPEND, (void *)3);
285
286 // /* We're pretty screwed if we got an error from this.
287 // * We try to recover by simply calling our own restore_state
288 // * function; see above for definition.
289 // *
290 // * If it's S5 though, go through with it anyway..
291 // */
292 // if (error && state != ACPI_STATE_S5)
293 // acpi_system_restore_state(state);
294 //}
295 return error ? AE_ERROR : AE_OK;
296 }
297
298
299 /****************************************************************************
300 *
301 * FUNCTION: acpi_system_suspend
302 *
303 * PARAMETERS: %state: Sleep state to enter.
304 *
305 * RETURN: ACPI_STATUS, whether or not we successfully entered and
306 * exited sleep.
307 *
308 * DESCRIPTION: Perform OS-specific action to enter sleep state.
309 * This is the final step in going to sleep, per spec. If we
310 * know we're coming back (i.e. not entering S5), we save the
311 * processor flags. [ We'll have to save and restore them anyway,
312 * so we use the arch-agnostic save_flags and restore_flags
313 * here.] We then set the place to return to in arch-specific
314 * globals using arch_set_return_point. Finally, we call the
315 * ACPI function to write the proper values to I/O ports.
316 *
317 ****************************************************************************/
318
319 ACPI_STATUS
320 acpi_system_suspend(
321 UINT32 state)
322 {
323 ACPI_STATUS status = AE_ERROR;
324 //unsigned long flags = 0;
325
326 //local_irq_save(flags);
327 /* kernel_fpu_begin(); */
328
329 switch (state) {
330 case ACPI_STATE_S1:
331 case ACPI_STATE_S5:
332 //barrier();
333 status = AcpiEnterSleepState(state);
334 break;
335 case ACPI_STATE_S4:
336 //do_suspend_lowlevel_s4bios(0);
337 break;
338 }
339
340 /* kernel_fpu_end(); */
341 //local_irq_restore(flags);
342
343 return status;
344 }
345
346
347
348 /**
349 * acpi_suspend - OS-agnostic system suspend/resume support (S? states)
350 * @state: state we're entering
351 *
352 */
353 ACPI_STATUS
354 acpi_suspend (
355 UINT32 state)
356 {
357 ACPI_STATUS status;
358
359 /* only support S1 and S5 on kernel 2.4 */
360 //if (state != ACPI_STATE_S1 && state != ACPI_STATE_S4
361 // && state != ACPI_STATE_S5)
362 // return AE_ERROR;
363
364
365 //if (ACPI_STATE_S4 == state) {
366 // /* For s4bios, we need a wakeup address. */
367 // if (1 == AcpiGbl_FACS->S4bios_f &&
368 // 0 != AcpiGbl_FADT->smi_cmd) {
369 // if (!acpi_wakeup_address)
370 // return AE_ERROR;
371 // AcpiSetFirmwareWakingVector((acpi_physical_address) acpi_wakeup_address);
372 // } else
373 // /* We don't support S4 under 2.4. Give up */
374 // return AE_ERROR;
375 //}
376 AcpiEnterSleepStatePrep(state);
377
378 status = AcpiEnterSleepState(state);
379 if (!ACPI_SUCCESS(status) && state != ACPI_STATE_S5)
380 return status;
381
382 /* disable interrupts and flush caches */
383 _disable();
384 ACPI_FLUSH_CPU_CACHE();
385
386 /* perform OS-specific sleep actions */
387 status = acpi_system_suspend(state);
388
389 /* Even if we failed to go to sleep, all of the devices are in an suspended
390 * mode. So, we run these unconditionaly to make sure we have a usable system
391 * no matter what.
392 */
393 AcpiLeaveSleepState(state);
394 acpi_system_restore_state(state);
395
396 /* make sure interrupts are enabled */
397 _enable();
398
399 /* reset firmware waking vector */
400 AcpiSetFirmwareWakingVector((ACPI_PHYSICAL_ADDRESS) 0);
401
402 return status;
403 }
404
405 int
406 acpi_system_init (void)
407 {
408 int result = 0;
409
410 ACPI_FUNCTION_TRACE("acpi_system_init");
411
412 result = acpi_bus_register_driver(&acpi_system_driver);
413 if (result < 0)
414 return_VALUE(AE_NOT_FOUND);
415
416 return_VALUE(0);
417 }
418
419
420 void
421 acpi_system_exit (void)
422 {
423 ACPI_FUNCTION_TRACE("acpi_system_exit");
424 acpi_bus_unregister_driver(&acpi_system_driver);
425 return_VOID;
426 }
427