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