xref: /reactos/drivers/bus/acpi/busmgr/system.c (revision 34593d93)
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
acpi_system_add(struct acpi_device * device)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
acpi_system_remove(struct acpi_device * device,int type)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
acpi_system_restore_state(UINT32 state)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
acpi_system_save_state(UINT32 state)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
acpi_system_suspend(UINT32 state)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
acpi_suspend(UINT32 state)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
acpi_system_init(void)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
acpi_system_exit(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 
421