Mercurial > sdl-ios-xcode
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 } |