File: apm.cpp

package info (click to toggle)
powersave 0.14.0-5
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 4,764 kB
  • ctags: 999
  • sloc: sh: 11,357; cpp: 8,103; ansic: 2,631; makefile: 388
file content (246 lines) | stat: -rw-r--r-- 8,150 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/***************************************************************************
 *                                                                         *
 *                         Powersave Daemon                                *
 *                                                                         *
 *          Copyright (C) 2004,2005 SUSE Linux Products GmbH               *
 *                                                                         *
 *               Author(s): Holger Macht <hmacht@suse.de>                  *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify it *
 * under the terms of the GNU General Public License as published by the   *
 * Free Software Foundation; either version 2 of the License, or (at you   *
 * option) any later version.                                              *
 *                                                                         *
 * This program is distributed in the hope that it will be useful, but     *
 * WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
 * General Public License for more details.                                *
 *                                                                         *
 * You should have received a copy of the GNU General Public License along *
 * with this program; if not, write to the Free Software Foundation, Inc., *
 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA                  *
 *                                                                         *
 ***************************************************************************/

#include <linux/apm_bios.h>
#include <sys/ioctl.h>

#include "globals.h"
#include "apm.h"
#include "fcntl.h"
#include "cpufreq_management.h"
#include "event_management.h"

APM_Interface::APM_Interface():PM_Interface()
{
	pDebug(DBG_INFO, "APM constructor");

	/* disable temperature control for apm only acpi is supported */
	Powersave::Globals::config_obj->current_scheme->ENABLE_THERMAL_MANAGEMENT = OFF;
	/* nothing of this exists in apm */
	_cooling_mode_supported = false;
	_throttleInterface.disableThrottling();
	_thermal_trip_points_supported = false;
}

APM_Interface::~APM_Interface()
{
	close(_hwEvent_fd);
}

int APM_Interface::openHWEventFD()
{
	/* from apmd ... */
	/* Return a file descriptor for the apm_bios device, or -1 if there is an
	 * error.        */
	if ((_hwEvent_fd = open(APM_BIOS_DEV, O_RDWR)) < 0) {
		/* Try to create it. 
		 * Expect major and minor number 10/134
		 * This should work with driver version 1 and above 
		 * (cannot access version number here)
		 * power lib does not provide it -> parse /proc/apm for version
		 * number. Old bios versions may need other major/minor numbers
		 * These can be read out from /proc/devices.
		 * do it yourself and send patch if you have such an old system ...
		 */
		if (mknod(APM_BIOS_DEV, S_IFCHR | S_IRUSR | S_IWUSR, makedev(10, 134))) {
			unlink(APM_BIOS_DEV);
			return -1;
		}
		if ((_hwEvent_fd = open(APM_BIOS_DEV, O_RDWR)) < 0) {
			/* this should never happen */
			pDebug(DBG_DIAG, "Could not open APM device " APM_BIOS_DEV
					": '%s', exit.", strerror(errno));
			return -1;
		}
	}
	return _hwEvent_fd;
}

int APM_Interface::openAcpidSocket()
{
	return 1;
}

int APM_Interface::handleHWEventRequest(int fd)
{
	int nr;

	// from /usr/include/linux/apm_bios.h
	/* Be careful this event structure has nothing to do
	   with the powersave events. */
	apm_event_t events[MAX_EVENTS];

	nr = read(_hwEvent_fd, events, MAX_EVENTS * sizeof(apm_event_t)) / sizeof(apm_event_t);

	if (nr < 0) {
		pDebug(DBG_WARN, "Error reading from apm event file");
		return nr;
	}
	// process events
	for (int x = 0; x < nr; x++) {
		// code partly pasted from apmd...
		switch (events[x]) {
		case APM_SYS_STANDBY:
		case APM_USER_STANDBY:
			if (_sleep_triggered) {
				pDebug(DBG_DIAG, "Be careful, endless loop?");
				break;
			}
			pDebug(DBG_INFO, "APM - Standby requested");
			/* may happen if sleep is initiated by HW, then 
			   we use standby events at this point 
			 */
			if (_requested_sleep_state == 0) {
				pDebug(DBG_DIAG, "Standby requested from BIOS");
				_eM->executeEvent("global.standby");
			}
			break;
		case APM_SYS_SUSPEND:
		case APM_USER_SUSPEND:
		case APM_CRITICAL_SUSPEND:
			if (_sleep_triggered) {
				pDebug(DBG_DIAG, "Be careful, endless loop?");
				break;
			}
			pDebug(DBG_INFO, "APM - Suspend2(ram/disk) requested.");
			/* may happen if sleep is initiated by HW, then 
			   we use suspend2ram events at this point 
			 */
			if (_requested_sleep_state == 0) {
				pDebug(DBG_DIAG, "Suspend requested from BIOS");
				_eM->executeEvent("global.suspend2ram");
			}
			break;
		case APM_STANDBY_RESUME:
			switch (_requested_sleep_state) {
			case PSD_SUSPEND2DISK:
				pDebug(DBG_DIAG, "Wake up from apm standby, but suspend2disk "
				       "has been triggered, this is no error");
				break;
			case PSD_SUSPEND2RAM:
				pDebug(DBG_DIAG, "Wake up from apm standby, but suspend2ram "
				       "has been triggered, this is no error");
				break;
			case PSD_STANDBY:
				pDebug(DBG_DIAG, "Wake up from apm standby");
				break;
			default:
				pDebug(DBG_DIAG, "Resuming from apm standby, no request has been made, "
				       "propably BIOS has initiated sleep state");
				break;
			}
			break;
			// does not happen, according to current kernel
			// implementation, driver sets time itself
		case APM_UPDATE_TIME:
			pDebug(DBG_INFO, "APM - Time updated send from /dev/apm_bios");
			break;
			// normally suspend should generate NORMAL_RESUME
			// don't know when a critical resume could occur,
			// all are processed in the same way ...
		case APM_NORMAL_RESUME:
		case APM_CRITICAL_RESUME:
			switch (_requested_sleep_state) {
			case PSD_SUSPEND2DISK:
				pDebug(DBG_DIAG,
				       "Wake up from apm suspend, suspend2disk has been triggered");
				break;
			case PSD_SUSPEND2RAM:
				pDebug(DBG_DIAG,
				       "Wake up from apm suspend, suspend2ram has been triggered");
				break;
			case PSD_STANDBY:
				pDebug(DBG_DIAG,
				       "Wake up from apm suspend, but standby "
				       "has been triggered, this is no error");
				break;
			default:
				pDebug(DBG_DIAG,
				       "Resuming from apm standby, no request has been made"
				       "propably BIOS has initiated sleep state");
				break;
			}
			_requested_sleep_state = PSD_NO_SLEEP_REQUEST;
			_sleep_triggered = false;
			// reset frequency which may have changed
			// without noticing it.
			Powersave::Globals::cpufreq->reinitSpeeds();
			break;
		case APM_POWER_STATUS_CHANGE:
			pDebug(DBG_INFO, "APM - Power status change event occured");
			break;
		case APM_LOW_BATTERY:
			pDebug(DBG_INFO,
			       "APM - Low Battery event occured");
			checkBatteryStateChanges();
			break;
#ifdef        APM_CAPABILITY_CHANGE
		case APM_CAPABILITY_CHANGE:
			pDebug(DBG_INFO,
			       "APM - Capability change event occured");
			checkACStateChanges();
			checkBatteryStateChanges();
			break;
#endif // APM_CAPABILITY_CHANGE
		default:
			/* other events are not errors, 
			   see the APM BIOS 1.2 spec or apmd.
			 */
			pDebug(DBG_DIAG,
			       "Received unknown APM event: 0x%04x.", events[x]);
		}
	}
	// never returns an error at the moment
	return 1;
}

void APM_Interface::activateSettings()
{
	/* nothing special to do for apm */
	PM_Interface::activateSettings();
}

int APM_Interface::suspend_to_ram()
{
	sync();
	/* ioctl blocks until we are back from suspend */
	pDebug(DBG_INFO, "APM - Trigger suspend2ram");
	if (ioctl(_hwEvent_fd, APM_IOC_SUSPEND, NULL) < 0) {
		pDebug(DBG_ERR, "Could not trigger APM suspend: %s", strerror(errno));
		return -1;
	}
	return 1;
}

int APM_Interface::standby()
{
	sync();
	pDebug(DBG_INFO, "APM - Trigger standby");
	/* ioctl blocks until we are back from standby */
	if (ioctl(_hwEvent_fd, APM_IOC_STANDBY, NULL) < 0) {
		pDebug(DBG_ERR, "Could not trigger APM standby: %s", strerror(errno));
		return -1;
	}
	return 1;
}