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