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 16struct 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 71struct notify_entry { 72 int id; 73 int (*handler)(struct notify_entry *entry, struct inotify_event *event); 74 const char *filename; 75}; 76 77int 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 98struct notify_entry watched_files[] = { 99 { 100 .filename = "/sys/android_power/charging_state", 101 .handler = charging_state_notify_handler 102 } 103}; 104 105int 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 131int 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 158int 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) { 406light_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) { 412light2_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) { 418sleep: 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