Mercurial > backlight
view backlight.c @ 26:9687f2798328
misc: added signature for changeset ea8c8664fa92
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 17 Dec 2020 09:57:39 +0100 |
parents | 6081cc143d37 |
children | 25155025900d |
line wrap: on
line source
/* * main.c -- adjust laptop backlight using ACPI * * Copyright (c) 2010-2020 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* * Functions to implement for your system: * * All of these functions are allowed to exit on failures. */ /* Set the level explicitly to the nearest value in range [0-100] */ static void set(unsigned int); /* Get the current value in range [0-100] */ static unsigned int get(void); static int gap(int argc, char **argv) { int value = 10; if (argc >= 2) { errno = 0; value = atoi(argv[1]); if (errno || value > 100 || value < -100) { fprintf(stderr, "invalid number: %s\n", argv[1]); exit(1); } } return value; } static void increase(int gap) { unsigned int value = get(); if (value + gap > 100) value = 100; else value += gap; set(value); } static void decrease(int gap) { unsigned int value = get(); if ((int)value - gap < 0) value = 0; else value -= gap; set(value); } static void usage(const char *name) { fprintf(stderr, "usage: %s decrease\n", name); fprintf(stderr, " %s get\n", name); fprintf(stderr, " %s increase [amount]\n", name); fprintf(stderr, " %s set percentage [amount]\n", name); exit(1); } static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(stderr, "abort: "); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } /* {{{ Support for FreeBSD */ #if defined(__FreeBSD__) #include <sys/types.h> #include <sys/sysctl.h> static int upper_bound(int *levels, size_t length, unsigned int percent) { size_t low = 0; size_t high = length - 1; while (low < high) { size_t mid = (low + high) / 2; if (percent <= (unsigned)levels[mid]) high = mid; else low = mid + 1; } return low; } static int min(const void *v1, const void *v2) { return *(int *)v1 - *(int *)v2; } static void sort(int *tab, size_t size) { qsort(tab, size, sizeof (int), min); } static void set(unsigned int percent) { int levels[200] = {0}; size_t length = sizeof (levels); if (sysctlbyname("hw.acpi.video.lcd0.levels", levels, &length, NULL, 0) < 0) die("sysctl: %s\n", strerror(errno)); length /= sizeof (int); /* Find appropriate nearest level */ if (percent > 0 && percent < 100) { sort(levels, length); percent = levels[upper_bound(levels, length, percent)]; } if (sysctlbyname("hw.acpi.video.lcd0.brightness", NULL, NULL, &percent, sizeof (int)) < 0) die("sysctl: %s\n", strerror(errno)); } static unsigned int get(void) { int current = 0; size_t length = sizeof (int); if (sysctlbyname("hw.acpi.video.lcd0.brightness", ¤t, &length, NULL, 0) == -1) die("sysctl: %s\n", strerror(errno)); return current; } /* }}} */ /* {{{ Support for Linux */ #elif defined(__linux__) #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <fcntl.h> #include <unistd.h> #define SYS_PATH "/sys/class/backlight" static unsigned int read_int(int dfd, const char *file) { char buf[32] = {0}; int fd; if ((fd = openat(dfd, file, O_RDONLY)) < 0) die("open: %s\n", strerror(errno)); if (read(fd, &buf[0], sizeof (buf) - 1) < 0) die("read: %s\n", strerror(errno)); close(fd); return atoi(buf); } static int write_int(int dfd, const char *file, unsigned int value) { char buf[32] = {0}; int length; int fd; if ((fd = openat(dfd, file, O_WRONLY)) < 0) die("open: %s\n", strerror(errno)); if ((length = snprintf(buf, sizeof (buf), "%d\n", value)) < 0) die("snprintf: %s\n", strerror(errno)); if (write(fd, buf, length) != length) die("write: %s\n", strerror(errno)); /* Re-read in case kernel change the value. */ return read_int(dfd, "brightness"); } static int try_adaptor(int parent_fd, const char *path) { int dfd; struct stat st; if ((dfd = openat(parent_fd, path, O_RDONLY)) < 0) return -1; if (fstatat(dfd, "brightness", &st, 0) < 0) { close(dfd); return -1; } return dfd; } static int find_adaptor(void) { int dfd, adaptorfd = -1; DIR *dirp; struct dirent *dirent; if ((dfd = open(SYS_PATH, O_RDONLY)) < 0) die("open: %s: %s\n", SYS_PATH, strerror(errno)); if (!(dirp = fdopendir(dfd))) die("fdopendir: %s: %s\n", SYS_PATH, strerror(errno)); while ((dirent = readdir(dirp))) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; if ((adaptorfd = try_adaptor(dfd, dirent->d_name)) >= 0) break; } closedir(dirp); close(dfd); if (adaptorfd < 0) die("could not find card adaptor\n"); return adaptorfd; } static unsigned int downscale(int dfd, unsigned int value) { return value * 100 / read_int(dfd, "max_brightness"); } static unsigned int upscale(int dfd, unsigned int value) { return value * read_int(dfd, "max_brightness") / 100; } static void set(unsigned int percent) { int dfd = find_adaptor(); unsigned int value = upscale(dfd, percent); write_int(dfd, "brightness", value); } static unsigned int get(void) { int dfd = find_adaptor(); int value = read_int(dfd, "brightness"); return downscale(dfd, value); } /* }}} */ /* {{{ Support for OpenBSD */ #elif defined(__OpenBSD__) #include <sys/types.h> #include <sys/ioctl.h> #include <sys/time.h> #include <dev/wscons/wsconsio.h> #include <err.h> #include <fcntl.h> #include <unistd.h> #define DEV "/dev/ttyC0" static int instance(int mode) { int fd; if ((fd = open(DEV, mode)) < 0) err(1, "open"); return fd; } static void fetch(struct wsdisplay_param *param) { int fd = instance(O_RDONLY); param->param = WSDISPLAYIO_PARAM_BRIGHTNESS; if (ioctl(fd, WSDISPLAYIO_GETPARAM, param) < 0) err(1, "ioctl"); close(fd); } static void put(struct wsdisplay_param *param) { int fd = instance(O_WRONLY); param->param = WSDISPLAYIO_PARAM_BRIGHTNESS; if (ioctl(fd, WSDISPLAYIO_SETPARAM, param) < 0) err(1, "ioctl"); close(fd); } static void set(unsigned int v) { struct wsdisplay_param param; /* Get current max/min values to scale. */ fetch(¶m); /* Upscale and apply. */ param.curval = v * param.max / 100; put(¶m); } static unsigned int get(void) { struct wsdisplay_param param; fetch(¶m); return (param.curval - param.min) * 100 / (param.max - param.min); } /* }}} */ /* {{{ Non supported shims */ #else static void notsupported(void) { die("backlight is not supported on this system\n"); } static void set(unsigned int v) { (void)v; notsupported(); } static unsigned int get(void) { notsupported(); return -1; } #endif /* }}} */ int main(int argc, char *argv[]) { -- argc; ++ argv; if (argc < 1) usage("backlight"); if (strcmp(argv[0], "get") == 0) printf("%d\n", get()); else if (strcmp(argv[0], "set") == 0) { if (argc != 2) usage(argv[0]); unsigned int value = atoi(argv[1]); if (value > 100) die("value %u is out of range\n", value); set(value); } else if (strcmp(argv[0], "increase") == 0) increase(gap(argc, argv)); else if (strcmp(argv[0], "decrease") == 0) decrease(gap(argc, argv)); else usage("backlight"); }