comparison src/power/linux/SDL_syspower.c @ 3203:790cbbda6429

Power: First shot at Linux /proc/acpi/battery support. Untested, not even tried to compile yet.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 30 Jun 2009 03:50:30 +0000
parents 51750b7a966f
children f77f50add24f
comparison
equal deleted inserted replaced
3202:3aa519a5c676 3203:790cbbda6429
27 #include <stdio.h> 27 #include <stdio.h>
28 #include <unistd.h> 28 #include <unistd.h>
29 29
30 #include <sys/types.h> 30 #include <sys/types.h>
31 #include <sys/stat.h> 31 #include <sys/stat.h>
32 #include <dirent.h>
32 #include <fcntl.h> 33 #include <fcntl.h>
33 34
34 #include "SDL_power.h" 35 #include "SDL_power.h"
35 36
36 SDL_bool 37 SDL_bool
37 SDL_GetPowerInfo_Linux_sys_power(SDL_PowerState * state, 38 SDL_GetPowerInfo_Linux_sys_power(SDL_PowerState * state,
38 int *seconds, int *percent) 39 int *seconds, int *percent)
39 { 40 {
40 return SDL_FALSE; /* !!! FIXME: write me. */ 41 return SDL_FALSE; /* !!! FIXME: write me. */
41 #if 0 42 }
42 const int fd = open("/sys/power", O_RDONLY); 43
44
45 static const char *proc_acpi_path = "/proc/acpi/battery";
46
47 static int open_acpi_file(const char *node, const char *key)
48 {
49 const size_t pathlen = strlen(proc_acpi_path)+strlen(node)+strlen(key)+3;
50 char *path = (char *) alloca(pathlen);
51 if (path == NULL) {
52 return -1; /* oh well. */
53 }
54
55 snprintf(path, pathlen, "%s/%s/%s", proc_acpi_path, node, key);
56 return open(path, O_RDONLY);
57 }
58
59
60 static SDL_bool
61 load_acpi_file(const char *node, const char *key, char *buf, size_t buflen)
62 {
63 ssize_t br = 0;
64 const int fd = open_acpi_file(node, key);
43 if (fd == -1) { 65 if (fd == -1) {
44 return SDL_FALSE; /* can't use this interface. */ 66 return SDL_FALSE;
45 } 67 }
68 br = read(fd, buf, buflen-1);
69 close(fd);
70 if (br < 0) {
71 return SDL_FALSE;
72 }
73 buf[br] = '\0'; // null-terminate the string.
46 return SDL_TRUE; 74 return SDL_TRUE;
47 #endif 75 }
76
77 static SDL_bool
78 make_acpi_key_val(char **_ptr, char **_key, char **_val)
79 {
80 char *ptr = *_ptr;
81
82 while (*ptr == ' ') {
83 ptr++; /* skip whitespace. */
84 }
85
86 if (*ptr == '\0') {
87 return SDL_FALSE; /* EOF. */
88 }
89
90 *_key = ptr;
91
92 while ((*ptr != ':') && (*ptr != '\0')) {
93 ptr++;
94 }
95
96 if (*ptr == '\0') {
97 return SDL_FALSE; /* (unexpected) EOF. */
98 }
99
100 *(ptr++) = '\0'; /* terminate the key. */
101
102 while ((*ptr == ' ') && (*ptr != '\0')) {
103 ptr++; /* skip whitespace. */
104 }
105
106 if (*ptr == '\0') {
107 return SDL_FALSE; /* (unexpected) EOF. */
108 }
109
110 *_val = ptr;
111
112 while ((*ptr != '\n') && (*ptr != '\0')) {
113 ptr++;
114 }
115
116 if (*ptr != '\0') {
117 *(ptr++) = '\0'; /* terminate the value. */
118 }
119
120 *_ptr = ptr; /* store for next time. */
121 return SDL_TRUE;
122 }
123
124 static void
125 check_acpi(const char * fname, SDL_bool * have_ac, SDL_bool * have_battery,
126 SDL_bool * charging, int *seconds, int *percent)
127 {
128 int fd = -1;
129 char info[1024];
130 char state[1024];
131 ssize_t br = 0;
132 char *ptr = NULL;
133 char *key = NULL;
134 char *val = NULL;
135 SDL_bool charge = SDL_FALSE;
136 SDL_bool choose = SDL_FALSE;
137 SDL_bool is_ac = SDL_FALSE;
138 int maximum = -1;
139 int remaining = -1;
140 int secs = -1;
141 int pct = -1;
142
143 if (!load_acpi_file(fname, "state", state, sizeof (state))) {
144 return;
145 } else if (!load_acpi_file(fname, "info", info, sizeof (info))) {
146 return;
147 }
148
149 ptr = &state[0];
150 while (make_acpi_key_val(&ptr, &key, &val)) {
151 if (strcmp(key, "present") == 0) {
152 if (strcmp(val, "yes") == 0) {
153 *have_battery = SDL_TRUE;
154 }
155 } else if (strcmp(key, "charging state") == 0) {
156 /* !!! FIXME: what exactly _does_ charging/discharging mean? */
157 if (strcmp(val, "charging/discharging") == 0) {
158 *have_ac = is_ac = SDL_TRUE;
159 charge = SDL_TRUE;
160 } else if (strcmp(val, "charging") == 0) {
161 *have_ac = is_ac = SDL_TRUE;
162 charge = SDL_TRUE;
163 } else if (strcmp(val, "charged") == 0) {
164 /* !!! FIXME: maybe another battery is discharging,
165 !!! FIXME: instead of AC connection. */
166 *have_ac = is_ac = SDL_TRUE;
167 charge = SDL_TRUE;
168 }
169 } else if (strcmp(key, "remaining capacity") == 0) {
170 char *endptr = NULL;
171 const int cvt = (int) strtol(val, &endptr, 10);
172 if (*endptr == ' ') {
173 remaining = cvt;
174 }
175 }
176 }
177
178 ptr = &info[0];
179 while (make_acpi_key_val(&ptr, &key, &val)) {
180 if (strcmp(key, "design capacity") == 0) {
181 char *endptr = NULL;
182 const int cvt = (int) strtol(val, &endptr, 10);
183 if (*endptr == ' ') {
184 maximum = cvt;
185 }
186 }
187 }
188
189 if ((maximum >= 0) && (remaining >= 0)) {
190 pct = (int) ((((float) remaining) / ((float) maximum)) * 100.0f);
191 if (pct < 0) {
192 pct = 0;
193 } else if (pct > 100) {
194 pct = 100;
195 }
196 }
197
198 /* !!! FIXME: calculate (secs). */
199
200 /*
201 * We pick the battery that claims to have the most minutes left.
202 * (failing a report of minutes, we'll take the highest percent.)
203 */
204 if ((secs < 0) && (*seconds < 0)) {
205 if ((pct < 0) && (*percent < 0)) {
206 choose = SDL_TRUE; /* at least we know there's a battery. */
207 }
208 if (pct > *percent) {
209 choose = SDL_TRUE;
210 }
211 } else if (secs > *seconds) {
212 choose = SDL_TRUE;
213 }
214
215 if (choose) {
216 *seconds = secs;
217 *percent = pct;
218 *charging = charge;
219 }
220
48 } 221 }
49 222
50 SDL_bool 223 SDL_bool
51 SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state, 224 SDL_GetPowerInfo_Linux_proc_acpi(SDL_PowerState * state,
52 int *seconds, int *percent) 225 int *seconds, int *percent)
53 { 226 {
54 return SDL_FALSE; /* !!! FIXME: write me. */ 227 struct dirent *dent = NULL;
55 #if 0 228 DIR *dirp = NULL;
56 const int fd = open("/proc/acpi", O_RDONLY); 229 SDL_bool have_ac = SDL_FALSE;
57 if (fd == -1) { 230 SDL_bool have_battery = SDL_FALSE;
58 return SDL_FALSE; /* can't use this interface. */ 231 SDL_bool charging = SDL_FALSE;
59 } 232
60 return SDL_TRUE; 233 *seconds = -1;
61 #endif 234 *percent = -1;
62 } 235 *state = SDL_POWERSTATE_UNKNOWN;
236
237 dirp = opendir(proc_acpi_path);
238 if (dirp == NULL) {
239 return SDL_FALSE; /* can't use this interface. */
240 }
241
242 while ((dent = readdir(dirp)) != NULL) {
243 const char *name = dent->d_name;
244 check_acpi(name, &have_ac, &have_battery, &charging, seconds, percent);
245 }
246
247 if (!have_battery) {
248 *state = SDL_POWERSTATE_NO_BATTERY;
249 } else if (charging) {
250 *state = SDL_POWERSTATE_CHARGING;
251 } else if (have_ac) {
252 *state = SDL_POWERSTATE_CHARGED;
253 } else {
254 *state = SDL_POWERSTATE_ON_BATTERY;
255 }
256
257 return SDL_TRUE; /* definitive answer. */
258 }
259
63 260
64 static SDL_bool 261 static SDL_bool
65 next_string(char **_ptr, char **_str) 262 next_string(char **_ptr, char **_str)
66 { 263 {
67 char *ptr = *_ptr; 264 char *ptr = *_ptr;
74 if (*ptr == '\0') { 271 if (*ptr == '\0') {
75 return SDL_FALSE; 272 return SDL_FALSE;
76 } 273 }
77 274
78 str = ptr; 275 str = ptr;
79 while ((*ptr != ' ') && (*ptr != '\0')) 276 while ((*ptr != ' ') && (*ptr != '\n') && (*ptr != '\0'))
80 ptr++; 277 ptr++;
81 278
82 if (*ptr != '\0') 279 if (*ptr != '\0')
83 *(ptr++) = '\0'; 280 *(ptr++) = '\0';
84 281
114 311
115 if (fd == -1) { 312 if (fd == -1) {
116 return SDL_FALSE; /* can't use this interface. */ 313 return SDL_FALSE; /* can't use this interface. */
117 } 314 }
118 315
119 br = read(fd, buf, sizeof(buf) - 1); 316 br = read(fd, buf, sizeof (buf) - 1);
120 close(fd); 317 close(fd);
121 318
122 if (br < 0) { 319 if (br < 0) {
123 return SDL_FALSE; 320 return SDL_FALSE;
124 } 321 }