• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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