/* * backsaver - Small backlight power saver daemon * * This app relies on contemporary Linux 2.6 intefaces, like * backlight class dev and generic input devices. Legacy interfaces * are not supported by design. * * Copyright (C) 2007, 2008 Paul Sokolovsky * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include int opt_verbose; int opt_timeout = 2; int opt_power; int opt_brightness = -1; char readbuf[256]; fd_set read_fds; fd_set work_fds; int fds[32]; int bl_state = 1; #define BL_PATH "/sys/class/backlight/" /* Backlight device properties */ char bldev_brightness_path[256] = BL_PATH; char bldev_power_path[256] = BL_PATH; int bldev_max_brightness; int bldev_saved_brightness; int bldev_dim_brightness; void fatal(char *msg) { fprintf(stderr, "%s\n", msg); exit(1); } int sysfs_get_value(char *fname) { char buf[64]; int fd = open(fname, O_RDONLY); int sz = read(fd, buf, sizeof(buf) - 1); buf[sz] = 0; close(fd); return atoi(buf); } void sysfs_set_value(char *fname, int val) { char buf[64]; int fd = open(fname, O_WRONLY); int sz = sprintf(buf, "%d\n", val); write(fd, buf, sz); close(fd); } char *bldev_scan() { static char name[256]; DIR *dir; struct dirent *de; int more_than_one = 0; dir = opendir(BL_PATH); if (!dir) fatal("Backlight device class does not seem to be support by kernel (" BL_PATH " is absent)"); *name = 0; while (de = readdir(dir)) { if (de->d_name[0] == '.') continue; if (*name == 0) { strcpy(name, de->d_name); } else { more_than_one = 1; break; } } closedir(dir); if (*name == 0) fatal("There does not seem to be any backlight device available (" BL_PATH " is empty)"); if (more_than_one) fatal("There seems to be several backlight devices available, use --device= option"); return name; } void bldev_init(char *bldev) { strcat(bldev_brightness_path, bldev); strcat(bldev_brightness_path, "/brightness"); strcat(bldev_power_path, bldev); strcat(bldev_power_path, "/power"); char buf[PATH_MAX]; memcpy(buf, BL_PATH, sizeof(BL_PATH)); strcat(buf, bldev); strcat(buf, "/max_brightness"); bldev_max_brightness = sysfs_get_value(buf); bldev_dim_brightness = bldev_max_brightness * opt_brightness / 100; } void set_backlight(int state) { if (!bl_state) { if (opt_verbose) printf("BL off\n"); if (opt_power) { sysfs_set_value(bldev_power_path, 4); } else { bldev_saved_brightness = sysfs_get_value(bldev_brightness_path); sysfs_set_value(bldev_brightness_path, bldev_dim_brightness); } } else { if (opt_verbose) printf("BL on\n"); if (opt_power) { sysfs_set_value(bldev_power_path, 0); } else { sysfs_set_value(bldev_brightness_path, bldev_saved_brightness); } } } #define INPUT_PATH "/dev/input/" int main_loop(int argc, char *argv[], int argstart) { fd_set read_fds; struct timeval timeout; int i, maxfd = 0, numfd = 0; FD_ZERO(&read_fds); if (argstart == argc) { static char path[256] = INPUT_PATH; DIR *dir; struct dirent *de; struct stat stat; dir = opendir(INPUT_PATH); if (!dir) fatal("Cannot open generic input device directory (" INPUT_PATH " is absent)"); while (de = readdir(dir)) { if (de->d_name[0] == '.') continue; strcpy(path + sizeof(INPUT_PATH) - 1, de->d_name); if (lstat(path, &stat)) fatal("Cannot stat input device to monitor"); if (S_ISLNK(stat.st_mode)) { if (opt_verbose) printf("Skipping symlink %s\n", path); continue; } if (opt_verbose) printf("Using %s\n", path); int fd = open(path, O_RDONLY); if (fd == -1) fatal("Cannot open input device to monitor"); if (fd > maxfd) maxfd = fd; fds[numfd++] = fd; FD_SET(fd, &read_fds); } closedir(dir); } else { for (i = argstart; i < argc; i++) { if (opt_verbose) printf("Using: %s\n", argv[i]); int fd = open(argv[i], O_RDONLY); if (fd == -1) fatal("Cannot open input device to monitor"); if (fd > maxfd) maxfd = fd; fds[numfd++] = fd; FD_SET(fd, &read_fds); } } timeout.tv_usec = 0; while (1) { memcpy(&work_fds, &read_fds, sizeof(read_fds)); timeout.tv_sec = opt_timeout; i = select(maxfd + 1, &work_fds, NULL, NULL, &timeout); if (opt_verbose) printf("Select returned: %d\n", i); if (i > 0) { if (!bl_state) { bl_state = 1; set_backlight(bl_state); } for (i = 0; i < numfd; i++) { if (FD_ISSET(fds[i], &work_fds)) { int sz = read(fds[i], readbuf, sizeof(readbuf)); if (opt_verbose) printf("Discarded %d bytes from fd %d\n", sz, fds[i]); } } } else { if (bl_state) { bl_state = 0; set_backlight(bl_state); } } } } struct option options[] = { { "verbose", no_argument, &opt_verbose, 1 }, { "timeout", required_argument, NULL, 't' }, { "power", no_argument, &opt_power, 1 }, { "brightness", required_argument, NULL, 'b' }, NULL }; int main(int argc, char *argv[]) { int opt; while ((opt = getopt_long(argc, argv, "?h", options, NULL)) != -1) { switch (opt) { case 't': opt_timeout = atoi(optarg); break; case 'b': opt_brightness = atoi(optarg); break; } } printf("%d\n", optind); char *bldev = bldev_scan(); bldev_init(bldev); return main_loop(argc, argv, optind); }