1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <time.h>
7 #include <sys/select.h>
8 #include <sys/inotify.h>
9
10 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
11
12 //#include <linux/input.h> // this does not compile
13
14 // from <linux/input.h>
15
16 struct input_event {
17 struct timeval time;
18 __u16 type;
19 __u16 code;
20 __s32 value;
21 };
22
23 #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
24 #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
25 #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
26 #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
27
28 #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
29 #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
30 #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
31
32 #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
33 #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
34 #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
35 #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
36
37 #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
38 #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
39 #define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
40
41 #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
42 #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
43 #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
44
45 #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
46
47 /*
48 * Event types
49 */
50
51 #define EV_SYN 0x00
52 #define EV_KEY 0x01
53 #define EV_REL 0x02
54 #define EV_ABS 0x03
55 #define EV_MSC 0x04
56 #define EV_SW 0x05
57 #define EV_LED 0x11
58 #define EV_SND 0x12
59 #define EV_REP 0x14
60 #define EV_FF 0x15
61 #define EV_PWR 0x16
62 #define EV_FF_STATUS 0x17
63 #define EV_MAX 0x1f
64
65 #define KEY_POWER 116
66 #define KEY_SLEEP 142
67 #define SW_0 0x00
68
69 // end <linux/input.h>
70
71 struct notify_entry {
72 int id;
73 int (*handler)(struct notify_entry *entry, struct inotify_event *event);
74 const char *filename;
75 };
76
charging_state_notify_handler(struct notify_entry * entry,struct inotify_event * event)77 int charging_state_notify_handler(struct notify_entry *entry, struct inotify_event *event)
78 {
79 static int state = -1;
80 int last_state;
81 char buf[40];
82 int read_len;
83 int fd;
84
85 last_state = state;
86 fd = open(entry->filename, O_RDONLY);
87 read_len = read(fd, buf, sizeof(buf));
88 if(read_len > 0) {
89 //printf("charging_state_notify_handler: \"%s\"\n", buf);
90 state = !(strncmp(buf, "Unknown", 7) == 0
91 || strncmp(buf, "Discharging", 11) == 0);
92 }
93 close(fd);
94 //printf("charging_state_notify_handler: %d -> %d\n", last_state, state);
95 return state > last_state;
96 }
97
98 struct notify_entry watched_files[] = {
99 {
100 .filename = "/sys/android_power/charging_state",
101 .handler = charging_state_notify_handler
102 }
103 };
104
call_notify_handler(struct inotify_event * event)105 int call_notify_handler(struct inotify_event *event)
106 {
107 unsigned int start, i;
108 start = event->wd - watched_files[0].id;
109 if(start >= ARRAY_SIZE(watched_files))
110 start = 0;
111 //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
112 for(i = start; i < ARRAY_SIZE(watched_files); i++) {
113 if(event->wd == watched_files[i].id) {
114 if(watched_files[i].handler) {
115 return watched_files[i].handler(&watched_files[i], event);
116 }
117 return 1;
118 }
119 }
120 for(i = 0; i < start; i++) {
121 if(event->wd == watched_files[i].id) {
122 if(watched_files[i].handler) {
123 return watched_files[i].handler(&watched_files[i], event);
124 }
125 return 1;
126 }
127 }
128 return 0;
129 }
130
handle_inotify_event(int nfd)131 int handle_inotify_event(int nfd)
132 {
133 int res;
134 int wake_up = 0;
135 struct inotify_event *event;
136 char event_buf[512];
137 int event_pos = 0;
138
139 res = read(nfd, event_buf, sizeof(event_buf));
140 if(res < (int)sizeof(*event)) {
141 if(errno == EINTR)
142 return 0;
143 fprintf(stderr, "could not get event, %s\n", strerror(errno));
144 return 0;
145 }
146 printf("got %d bytes of event information\n", res);
147 while(res >= (int)sizeof(*event)) {
148 int event_size;
149 event = (struct inotify_event *)(event_buf + event_pos);
150 wake_up |= call_notify_handler(event);
151 event_size = sizeof(*event) + event->len;
152 res -= event_size;
153 event_pos += event_size;
154 }
155 return wake_up;
156 }
157
powerd_main(int argc,char * argv[])158 int powerd_main(int argc, char *argv[])
159 {
160 int c;
161 unsigned int i;
162 int res;
163 struct timeval tv;
164 int eventfd;
165 int notifyfd;
166 int powerfd;
167 int powerfd_is_sleep;
168 int user_activity_fd;
169 int acquire_partial_wake_lock_fd;
170 int acquire_full_wake_lock_fd;
171 int release_wake_lock_fd;
172 char *eventdev = "/dev/input/event0";
173 const char *android_sleepdev = "/sys/android_power/request_sleep";
174 const char *android_autooff_dev = "/sys/android_power/auto_off_timeout";
175 const char *android_user_activity_dev = "/sys/android_power/last_user_activity";
176 const char *android_acquire_partial_wake_lock_dev = "/sys/android_power/acquire_partial_wake_lock";
177 const char *android_acquire_full_wake_lock_dev = "/sys/android_power/acquire_full_wake_lock";
178 const char *android_release_wake_lock_dev = "/sys/android_power/release_wake_lock";
179 const char *powerdev = "/sys/power/state";
180 const char suspendstring[] = "standby";
181 const char wakelockstring[] = "powerd";
182 fd_set rfds;
183 struct input_event event;
184 struct input_event light_event;
185 struct input_event light_event2;
186 int gotkey = 1;
187 time_t idle_time = 5;
188 const char *idle_time_string = "5";
189 time_t lcd_light_time = 0;
190 time_t key_light_time = 0;
191 int verbose = 1;
192 int event_sleep = 0;
193 int got_power_key_down = 0;
194 struct timeval power_key_down_time = { 0, 0 };
195
196 light_event.type = EV_LED;
197 light_event.code = 4; // bright lcd backlight
198 light_event.value = 0; // light off -- sleep after timeout
199
200 light_event2.type = EV_LED;
201 light_event2.code = 8; // keyboard backlight
202 light_event2.value = 0; // light off -- sleep after timeout
203
204 do {
205 c = getopt(argc, argv, "e:ni:vql:k:");
206 if (c == EOF)
207 break;
208 switch (c) {
209 case 'e':
210 eventdev = optarg;
211 break;
212 case 'n':
213 gotkey = 0;
214 break;
215 case 'i':
216 idle_time = atoi(optarg);
217 idle_time_string = optarg;
218 break;
219 case 'v':
220 verbose = 2;
221 break;
222 case 'q':
223 verbose = 0;
224 break;
225 case 'l':
226 lcd_light_time = atoi(optarg);
227 break;
228 case 'k':
229 key_light_time = atoi(optarg);
230 break;
231 case '?':
232 fprintf(stderr, "%s: invalid option -%c\n",
233 argv[0], optopt);
234 exit(1);
235 }
236 } while (1);
237 if(optind != argc) {
238 fprintf(stderr,"%s [-e eventdev]\n", argv[0]);
239 return 1;
240 }
241
242 eventfd = open(eventdev, O_RDWR | O_NONBLOCK);
243 if(eventfd < 0) {
244 fprintf(stderr, "could not open %s, %s\n", eventdev, strerror(errno));
245 return 1;
246 }
247 if(key_light_time >= lcd_light_time) {
248 lcd_light_time = key_light_time + 1;
249 fprintf(stderr,"lcd bright backlight time must be longer than keyboard backlight time.\n"
250 "Setting lcd bright backlight time to %ld seconds\n", lcd_light_time);
251 }
252
253 user_activity_fd = open(android_user_activity_dev, O_RDWR);
254 if(user_activity_fd >= 0) {
255 int auto_off_fd = open(android_autooff_dev, O_RDWR);
256 write(auto_off_fd, idle_time_string, strlen(idle_time_string));
257 close(auto_off_fd);
258 }
259
260 powerfd = open(android_sleepdev, O_RDWR);
261 if(powerfd >= 0) {
262 powerfd_is_sleep = 1;
263 if(verbose > 0)
264 printf("Using android sleep dev: %s\n", android_sleepdev);
265 }
266 else {
267 powerfd_is_sleep = 0;
268 powerfd = open(powerdev, O_RDWR);
269 if(powerfd >= 0) {
270 if(verbose > 0)
271 printf("Using linux power dev: %s\n", powerdev);
272 }
273 }
274 if(powerfd < 0) {
275 fprintf(stderr, "could not open %s, %s\n", powerdev, strerror(errno));
276 return 1;
277 }
278
279 notifyfd = inotify_init();
280 if(notifyfd < 0) {
281 fprintf(stderr, "inotify_init failed, %s\n", strerror(errno));
282 return 1;
283 }
284 fcntl(notifyfd, F_SETFL, O_NONBLOCK | fcntl(notifyfd, F_GETFL));
285 for(i = 0; i < ARRAY_SIZE(watched_files); i++) {
286 watched_files[i].id = inotify_add_watch(notifyfd, watched_files[i].filename, IN_MODIFY);
287 printf("Watching %s, id %d\n", watched_files[i].filename, watched_files[i].id);
288 }
289
290 acquire_partial_wake_lock_fd = open(android_acquire_partial_wake_lock_dev, O_RDWR);
291 acquire_full_wake_lock_fd = open(android_acquire_full_wake_lock_dev, O_RDWR);
292 release_wake_lock_fd = open(android_release_wake_lock_dev, O_RDWR);
293
294 if(user_activity_fd >= 0) {
295 idle_time = 60*60*24; // driver handles real timeout
296 }
297 if(gotkey) {
298 tv.tv_sec = idle_time;
299 tv.tv_usec = 0;
300 }
301 else {
302 tv.tv_sec = 0;
303 tv.tv_usec = 500000;
304 }
305
306 while(1) {
307 FD_ZERO(&rfds);
308 //FD_SET(0, &rfds);
309 FD_SET(eventfd, &rfds);
310 FD_SET(notifyfd, &rfds);
311 res = select(((notifyfd > eventfd) ? notifyfd : eventfd) + 1, &rfds, NULL, NULL, &tv);
312 if(res < 0) {
313 fprintf(stderr, "select failed, %s\n", strerror(errno));
314 return 1;
315 }
316 if(res == 0) {
317 if(light_event2.value == 1)
318 goto light2_off;
319 if(light_event.value == 1)
320 goto light_off;
321 if(user_activity_fd < 0) {
322 if(gotkey && verbose > 0)
323 printf("Idle - sleep\n");
324 if(!gotkey && verbose > 1)
325 printf("Reenter sleep\n");
326 goto sleep;
327 }
328 else {
329 tv.tv_sec = 60*60*24;
330 tv.tv_usec = 0;
331 }
332 }
333 if(res > 0) {
334 //if(FD_ISSET(0, &rfds)) {
335 // printf("goto data on stdin quit\n");
336 // return 0;
337 //}
338 if(FD_ISSET(notifyfd, &rfds)) {
339 write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
340 if(handle_inotify_event(notifyfd) > 0) {
341 write(acquire_full_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
342 }
343 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
344 }
345 if(FD_ISSET(eventfd, &rfds)) {
346 write(acquire_partial_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
347 res = read(eventfd, &event, sizeof(event));
348 if(res < (int)sizeof(event)) {
349 fprintf(stderr, "could not get event\n");
350 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
351 return 1;
352 }
353 if(event.type == EV_PWR && event.code == KEY_SLEEP) {
354 event_sleep = event.value;
355 }
356 if(event.type == EV_KEY || (event.type == EV_SW && event.code == SW_0 && event.value == 1)) {
357 gotkey = 1;
358 if(user_activity_fd >= 0) {
359 char buf[32];
360 int len;
361 len = sprintf(buf, "%ld%06lu000", event.time.tv_sec, event.time.tv_usec);
362 write(user_activity_fd, buf, len);
363 }
364 if(lcd_light_time | key_light_time) {
365 tv.tv_sec = key_light_time;
366 light_event.value = 1;
367 write(eventfd, &light_event, sizeof(light_event));
368 light_event2.value = 1;
369 write(eventfd, &light_event2, sizeof(light_event2));
370 }
371 else {
372 tv.tv_sec = idle_time;
373 }
374 tv.tv_usec = 0;
375 if(verbose > 1)
376 printf("got %s %s %d%s\n", event.type == EV_KEY ? "key" : "switch", event.value ? "down" : "up", event.code, event_sleep ? " from sleep" : "");
377 if(event.code == KEY_POWER) {
378 if(event.value == 0) {
379 int tmp_got_power_key_down = got_power_key_down;
380 got_power_key_down = 0;
381 if(tmp_got_power_key_down) {
382 // power key released
383 if(verbose > 0)
384 printf("Power key released - sleep\n");
385 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
386 goto sleep;
387 }
388 }
389 else if(event_sleep == 0) {
390 got_power_key_down = 1;
391 power_key_down_time = event.time;
392 }
393 }
394 }
395 if(event.type == EV_SW && event.code == SW_0 && event.value == 0) {
396 if(verbose > 0)
397 printf("Flip closed - sleep\n");
398 power_key_down_time = event.time;
399 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
400 goto sleep;
401 }
402 write(release_wake_lock_fd, wakelockstring, sizeof(wakelockstring) - 1);
403 }
404 }
405 if(0) {
406 light_off:
407 light_event.value = 0;
408 write(eventfd, &light_event, sizeof(light_event));
409 tv.tv_sec = idle_time - lcd_light_time;
410 }
411 if(0) {
412 light2_off:
413 light_event2.value = 0;
414 write(eventfd, &light_event2, sizeof(light_event2));
415 tv.tv_sec = lcd_light_time - key_light_time;
416 }
417 if(0) {
418 sleep:
419 if(light_event.value == 1) {
420 light_event.value = 0;
421 write(eventfd, &light_event, sizeof(light_event));
422 light_event2.value = 0;
423 write(eventfd, &light_event2, sizeof(light_event2));
424 tv.tv_sec = idle_time - lcd_light_time;
425 }
426 if(powerfd_is_sleep) {
427 char buf[32];
428 int len;
429 len = sprintf(buf, "%ld%06lu000", power_key_down_time.tv_sec, power_key_down_time.tv_usec);
430 write(powerfd, buf, len);
431 }
432 else
433 write(powerfd, suspendstring, sizeof(suspendstring) - 1);
434 gotkey = 0;
435 tv.tv_sec = 0;
436 tv.tv_usec = 500000;
437 }
438 }
439
440 return 0;
441 }
442