zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_syspower.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "SDL_config.h"
22 
23 #ifndef SDL_POWER_DISABLED
24 #if SDL_POWER_LINUX
25 
26 #include <stdio.h>
27 #include <unistd.h>
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <dirent.h>
32 #include <fcntl.h>
33 
34 #include "SDL_power.h"
35 
36 static const char *proc_apm_path = "/proc/apm";
37 static const char *proc_acpi_battery_path = "/proc/acpi/battery";
38 static const char *proc_acpi_ac_adapter_path = "/proc/acpi/ac_adapter";
39 
40 static int open_acpi_file(const char *base, const char *node, const char *key)
41 {
42  const size_t pathlen = strlen(base) + strlen(node) + strlen(key) + 3;
43  char *path = (char *) alloca(pathlen);
44  if (path == NULL) {
45  return -1; /* oh well. */
46  }
47 
48  snprintf(path, pathlen, "%s/%s/%s", base, node, key);
49  return open(path, O_RDONLY);
50 }
51 
52 
53 static SDL_bool
54 load_acpi_file(const char *base, const char *node, const char *key,
55  char *buf, size_t buflen)
56 {
57  ssize_t br = 0;
58  const int fd = open_acpi_file(base, node, key);
59  if (fd == -1) {
60  return SDL_FALSE;
61  }
62  br = read(fd, buf, buflen-1);
63  close(fd);
64  if (br < 0) {
65  return SDL_FALSE;
66  }
67  buf[br] = '\0'; /* null-terminate the string. */
68  return SDL_TRUE;
69 }
70 
71 
72 static SDL_bool
73 make_proc_acpi_key_val(char **_ptr, char **_key, char **_val)
74 {
75  char *ptr = *_ptr;
76 
77  while (*ptr == ' ') {
78  ptr++; /* skip whitespace. */
79  }
80 
81  if (*ptr == '\0') {
82  return SDL_FALSE; /* EOF. */
83  }
84 
85  *_key = ptr;
86 
87  while ((*ptr != ':') && (*ptr != '\0')) {
88  ptr++;
89  }
90 
91  if (*ptr == '\0') {
92  return SDL_FALSE; /* (unexpected) EOF. */
93  }
94 
95  *(ptr++) = '\0'; /* terminate the key. */
96 
97  while ((*ptr == ' ') && (*ptr != '\0')) {
98  ptr++; /* skip whitespace. */
99  }
100 
101  if (*ptr == '\0') {
102  return SDL_FALSE; /* (unexpected) EOF. */
103  }
104 
105  *_val = ptr;
106 
107  while ((*ptr != '\n') && (*ptr != '\0')) {
108  ptr++;
109  }
110 
111  if (*ptr != '\0') {
112  *(ptr++) = '\0'; /* terminate the value. */
113  }
114 
115  *_ptr = ptr; /* store for next time. */
116  return SDL_TRUE;
117 }
118 
119 static void
120 check_proc_acpi_battery(const char * node, SDL_bool * have_battery,
121  SDL_bool * charging, int *seconds, int *percent)
122 {
123  const char *base = proc_acpi_battery_path;
124  char info[1024];
125  char state[1024];
126  char *ptr = NULL;
127  char *key = NULL;
128  char *val = NULL;
129  SDL_bool charge = SDL_FALSE;
130  SDL_bool choose = SDL_FALSE;
131  int maximum = -1;
132  int remaining = -1;
133  int secs = -1;
134  int pct = -1;
135 
136  if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
137  return;
138  } else if (!load_acpi_file(base, node, "info", info, sizeof (info))) {
139  return;
140  }
141 
142  ptr = &state[0];
143  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
144  if (strcmp(key, "present") == 0) {
145  if (strcmp(val, "yes") == 0) {
146  *have_battery = SDL_TRUE;
147  }
148  } else if (strcmp(key, "charging state") == 0) {
149  /* !!! FIXME: what exactly _does_ charging/discharging mean? */
150  if (strcmp(val, "charging/discharging") == 0) {
151  charge = SDL_TRUE;
152  } else if (strcmp(val, "charging") == 0) {
153  charge = SDL_TRUE;
154  }
155  } else if (strcmp(key, "remaining capacity") == 0) {
156  char *endptr = NULL;
157  const int cvt = (int) strtol(val, &endptr, 10);
158  if (*endptr == ' ') {
159  remaining = cvt;
160  }
161  }
162  }
163 
164  ptr = &info[0];
165  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
166  if (strcmp(key, "design capacity") == 0) {
167  char *endptr = NULL;
168  const int cvt = (int) strtol(val, &endptr, 10);
169  if (*endptr == ' ') {
170  maximum = cvt;
171  }
172  }
173  }
174 
175  if ((maximum >= 0) && (remaining >= 0)) {
176  pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
177  if (pct < 0) {
178  pct = 0;
179  } else if (pct > 100) {
180  pct = 100;
181  }
182  }
183 
184  /* !!! FIXME: calculate (secs). */
185 
186  /*
187  * We pick the battery that claims to have the most minutes left.
188  * (failing a report of minutes, we'll take the highest percent.)
189  */
190  if ((secs < 0) && (*seconds < 0)) {
191  if ((pct < 0) && (*percent < 0)) {
192  choose = SDL_TRUE; /* at least we know there's a battery. */
193  }
194  if (pct > *percent) {
195  choose = SDL_TRUE;
196  }
197  } else if (secs > *seconds) {
198  choose = SDL_TRUE;
199  }
200 
201  if (choose) {
202  *seconds = secs;
203  *percent = pct;
204  *charging = charge;
205  }
206 }
207 
208 static void
209 check_proc_acpi_ac_adapter(const char * node, SDL_bool * have_ac)
210 {
211  const char *base = proc_acpi_ac_adapter_path;
212  char state[256];
213  char *ptr = NULL;
214  char *key = NULL;
215  char *val = NULL;
216 
217  if (!load_acpi_file(base, node, "state", state, sizeof (state))) {
218  return;
219  }
220 
221  ptr = &state[0];
222  while (make_proc_acpi_key_val(&ptr, &key, &val)) {
223  if (strcmp(key, "state") == 0) {
224  if (strcmp(val, "on-line") == 0) {
225  *have_ac = SDL_TRUE;
226  }
227  }
228  }
229 }
230 
231 
232 SDL_bool
234  int *seconds, int *percent)
235 {
236  struct dirent *dent = NULL;
237  DIR *dirp = NULL;
238  SDL_bool have_battery = SDL_FALSE;
239  SDL_bool have_ac = SDL_FALSE;
240  SDL_bool charging = SDL_FALSE;
241 
242  *seconds = -1;
243  *percent = -1;
244  *state = SDL_POWERSTATE_UNKNOWN;
245 
246  dirp = opendir(proc_acpi_battery_path);
247  if (dirp == NULL) {
248  return SDL_FALSE; /* can't use this interface. */
249  } else {
250  while ((dent = readdir(dirp)) != NULL) {
251  const char *node = dent->d_name;
252  check_proc_acpi_battery(node, &have_battery, &charging,
253  seconds, percent);
254  }
255  closedir(dirp);
256  }
257 
258  dirp = opendir(proc_acpi_ac_adapter_path);
259  if (dirp == NULL) {
260  return SDL_FALSE; /* can't use this interface. */
261  } else {
262  while ((dent = readdir(dirp)) != NULL) {
263  const char *node = dent->d_name;
264  check_proc_acpi_ac_adapter(node, &have_ac);
265  }
266  closedir(dirp);
267  }
268 
269  if (!have_battery) {
270  *state = SDL_POWERSTATE_NO_BATTERY;
271  } else if (charging) {
272  *state = SDL_POWERSTATE_CHARGING;
273  } else if (have_ac) {
274  *state = SDL_POWERSTATE_CHARGED;
275  } else {
276  *state = SDL_POWERSTATE_ON_BATTERY;
277  }
278 
279  return SDL_TRUE; /* definitive answer. */
280 }
281 
282 
283 static SDL_bool
284 next_string(char **_ptr, char **_str)
285 {
286  char *ptr = *_ptr;
287  char *str = *_str;
288 
289  while (*ptr == ' ') { /* skip any spaces... */
290  ptr++;
291  }
292 
293  if (*ptr == '\0') {
294  return SDL_FALSE;
295  }
296 
297  str = ptr;
298  while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
299  ptr++;
300 
301  if (*ptr != '\0')
302  *(ptr++) = '\0';
303 
304  *_str = str;
305  *_ptr = ptr;
306  return SDL_TRUE;
307 }
308 
309 static SDL_bool
310 int_string(char *str, int *val)
311 {
312  char *endptr = NULL;
313  *val = (int) strtol(str, &endptr, 0);
314  return ((*str != '\0') && (*endptr == '\0'));
315 }
316 
317 /* http://lxr.linux.no/linux+v2.6.29/drivers/char/apm-emulation.c */
318 SDL_bool
320  int *seconds, int *percent)
321 {
322  SDL_bool need_details = SDL_FALSE;
323  int ac_status = 0;
324  int battery_status = 0;
325  int battery_flag = 0;
326  int battery_percent = 0;
327  int battery_time = 0;
328  const int fd = open(proc_apm_path, O_RDONLY);
329  char buf[128];
330  char *ptr = &buf[0];
331  char *str = NULL;
332  ssize_t br;
333 
334  if (fd == -1) {
335  return SDL_FALSE; /* can't use this interface. */
336  }
337 
338  br = read(fd, buf, sizeof (buf) - 1);
339  close(fd);
340 
341  if (br < 0) {
342  return SDL_FALSE;
343  }
344 
345  buf[br] = '\0'; /* null-terminate the string. */
346  if (!next_string(&ptr, &str)) { /* driver version */
347  return SDL_FALSE;
348  }
349  if (!next_string(&ptr, &str)) { /* BIOS version */
350  return SDL_FALSE;
351  }
352  if (!next_string(&ptr, &str)) { /* APM flags */
353  return SDL_FALSE;
354  }
355 
356  if (!next_string(&ptr, &str)) { /* AC line status */
357  return SDL_FALSE;
358  } else if (!int_string(str, &ac_status)) {
359  return SDL_FALSE;
360  }
361 
362  if (!next_string(&ptr, &str)) { /* battery status */
363  return SDL_FALSE;
364  } else if (!int_string(str, &battery_status)) {
365  return SDL_FALSE;
366  }
367  if (!next_string(&ptr, &str)) { /* battery flag */
368  return SDL_FALSE;
369  } else if (!int_string(str, &battery_flag)) {
370  return SDL_FALSE;
371  }
372  if (!next_string(&ptr, &str)) { /* remaining battery life percent */
373  return SDL_FALSE;
374  }
375  if (str[strlen(str) - 1] == '%') {
376  str[strlen(str) - 1] = '\0';
377  }
378  if (!int_string(str, &battery_percent)) {
379  return SDL_FALSE;
380  }
381 
382  if (!next_string(&ptr, &str)) { /* remaining battery life time */
383  return SDL_FALSE;
384  } else if (!int_string(str, &battery_time)) {
385  return SDL_FALSE;
386  }
387 
388  if (!next_string(&ptr, &str)) { /* remaining battery life time units */
389  return SDL_FALSE;
390  } else if (strcmp(str, "min") == 0) {
391  battery_time *= 60;
392  }
393 
394  if (battery_flag == 0xFF) { /* unknown state */
395  *state = SDL_POWERSTATE_UNKNOWN;
396  } else if (battery_flag & (1 << 7)) { /* no battery */
397  *state = SDL_POWERSTATE_NO_BATTERY;
398  } else if (battery_flag & (1 << 3)) { /* charging */
399  *state = SDL_POWERSTATE_CHARGING;
400  need_details = SDL_TRUE;
401  } else if (ac_status == 1) {
402  *state = SDL_POWERSTATE_CHARGED; /* on AC, not charging. */
403  need_details = SDL_TRUE;
404  } else {
405  *state = SDL_POWERSTATE_ON_BATTERY;
406  need_details = SDL_TRUE;
407  }
408 
409  *percent = -1;
410  *seconds = -1;
411  if (need_details) {
412  const int pct = battery_percent;
413  const int secs = battery_time;
414 
415  if (pct >= 0) { /* -1 == unknown */
416  *percent = (pct > 100) ? 100 : pct; /* clamp between 0%, 100% */
417  }
418  if (secs >= 0) { /* -1 == unknown */
419  *seconds = secs;
420  }
421  }
422 
423  return SDL_TRUE;
424 }
425 
426 #endif /* SDL_POWER_LINUX */
427 #endif /* SDL_POWER_DISABLED */
428 
429 /* vi: set ts=4 sw=4 expandtab: */
GLuint const GLfloat * val
Definition: glew.h:2715
#define NULL
Definition: ftobjs.h:61
SDL_bool
Definition: SDL_stdinc.h:116
SDL_bool SDL_GetPowerInfo_Linux_proc_apm(SDL_PowerState *, int *, int *)
GLsizei const GLchar *const * path
Definition: glew.h:5828
int
Definition: SDL_systhread.c:37
SDL_PowerState
The basic state for the system&#39;s power supply.
Definition: SDL_power.h:42
GLenum GLuint GLsizei const GLchar * buf
Definition: glew.h:2539
#define str(s)
SDL_bool SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState *, int *, int *)