19ddaa99dSEmmanuel Vadot /*- 29ddaa99dSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 39ddaa99dSEmmanuel Vadot * 49ddaa99dSEmmanuel Vadot * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org> 59ddaa99dSEmmanuel Vadot * 69ddaa99dSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 79ddaa99dSEmmanuel Vadot * modification, are permitted provided that the following conditions 89ddaa99dSEmmanuel Vadot * are met: 99ddaa99dSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 109ddaa99dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 119ddaa99dSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 129ddaa99dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 139ddaa99dSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 149ddaa99dSEmmanuel Vadot * 159ddaa99dSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 169ddaa99dSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 179ddaa99dSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 189ddaa99dSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 199ddaa99dSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 209ddaa99dSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 219ddaa99dSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 229ddaa99dSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 239ddaa99dSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 249ddaa99dSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 259ddaa99dSEmmanuel Vadot * SUCH DAMAGE. 269ddaa99dSEmmanuel Vadot * 279ddaa99dSEmmanuel Vadot * $FreeBSD$ 289ddaa99dSEmmanuel Vadot */ 299ddaa99dSEmmanuel Vadot 309ddaa99dSEmmanuel Vadot #include <sys/types.h> 319ddaa99dSEmmanuel Vadot #include <sys/ioctl.h> 329ddaa99dSEmmanuel Vadot #include <stdbool.h> 339ddaa99dSEmmanuel Vadot #include <sys/capsicum.h> 349ddaa99dSEmmanuel Vadot #include <sys/backlight.h> 359ddaa99dSEmmanuel Vadot 369ddaa99dSEmmanuel Vadot #include <err.h> 379ddaa99dSEmmanuel Vadot #include <errno.h> 389ddaa99dSEmmanuel Vadot #include <fcntl.h> 399ddaa99dSEmmanuel Vadot #include <limits.h> 409ddaa99dSEmmanuel Vadot #include <stdio.h> 419ddaa99dSEmmanuel Vadot #include <stdlib.h> 429ddaa99dSEmmanuel Vadot #include <string.h> 439ddaa99dSEmmanuel Vadot #include <unistd.h> 449ddaa99dSEmmanuel Vadot #include <capsicum_helpers.h> 459ddaa99dSEmmanuel Vadot 469ddaa99dSEmmanuel Vadot #define BACKLIGHT_QUERY 0x0001 479ddaa99dSEmmanuel Vadot #define BACKLIGHT_SET_BRIGHTNESS 0x0002 489ddaa99dSEmmanuel Vadot #define BACKLIGHT_INCR 0x0004 499ddaa99dSEmmanuel Vadot #define BACKLIGHT_DECR 0x0008 509ddaa99dSEmmanuel Vadot #define BACKLIGHT_INFO 0x0010 519ddaa99dSEmmanuel Vadot 529ddaa99dSEmmanuel Vadot static char device_name[PATH_MAX] = "/dev/backlight/backlight0"; 539ddaa99dSEmmanuel Vadot 549ddaa99dSEmmanuel Vadot static void 559ddaa99dSEmmanuel Vadot set_device_name(const char *name) 569ddaa99dSEmmanuel Vadot { 579ddaa99dSEmmanuel Vadot 589ddaa99dSEmmanuel Vadot if (name[0] == '/') 599ddaa99dSEmmanuel Vadot strlcpy(device_name, name, sizeof(device_name)); 609ddaa99dSEmmanuel Vadot else 619ddaa99dSEmmanuel Vadot snprintf(device_name, sizeof(device_name), "/dev/backlight/%s", name); 629ddaa99dSEmmanuel Vadot } 639ddaa99dSEmmanuel Vadot 649ddaa99dSEmmanuel Vadot static void 659ddaa99dSEmmanuel Vadot usage(void) 669ddaa99dSEmmanuel Vadot { 679ddaa99dSEmmanuel Vadot fprintf(stderr, "Usage:\n"); 689ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev]\n"); 699ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] -i\n"); 709ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] <percent>\n"); 719ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] incr|+ <percent>\n"); 729ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] decr|- <percent>\n"); 739ddaa99dSEmmanuel Vadot exit(1); 749ddaa99dSEmmanuel Vadot } 759ddaa99dSEmmanuel Vadot 769ddaa99dSEmmanuel Vadot static const char * 779ddaa99dSEmmanuel Vadot backlight_type_to_string(enum backlight_info_type type) 789ddaa99dSEmmanuel Vadot { 799ddaa99dSEmmanuel Vadot switch (type) { 809ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_PANEL: 819ddaa99dSEmmanuel Vadot return ("Panel"); 829ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_KEYBOARD: 839ddaa99dSEmmanuel Vadot return ("Keyboard"); 849ddaa99dSEmmanuel Vadot } 859ddaa99dSEmmanuel Vadot 869ddaa99dSEmmanuel Vadot return ("Unknown"); 879ddaa99dSEmmanuel Vadot } 889ddaa99dSEmmanuel Vadot 899ddaa99dSEmmanuel Vadot int 909ddaa99dSEmmanuel Vadot main(int argc, char *argv[]) 919ddaa99dSEmmanuel Vadot { 929ddaa99dSEmmanuel Vadot struct backlight_props props; 939ddaa99dSEmmanuel Vadot struct backlight_info info; 949ddaa99dSEmmanuel Vadot int fd; 959ddaa99dSEmmanuel Vadot int action, ch; 969ddaa99dSEmmanuel Vadot cap_rights_t right_ioctl; 979ddaa99dSEmmanuel Vadot const unsigned long backlight_ioctls[] = { 989ddaa99dSEmmanuel Vadot BACKLIGHTGETSTATUS, 999ddaa99dSEmmanuel Vadot BACKLIGHTUPDATESTATUS, 1009ddaa99dSEmmanuel Vadot BACKLIGHTGETINFO}; 1019ddaa99dSEmmanuel Vadot long percent = 0; 1029ddaa99dSEmmanuel Vadot const char *percent_error; 1039ddaa99dSEmmanuel Vadot uint32_t i; 1049ddaa99dSEmmanuel Vadot bool setname; 1059ddaa99dSEmmanuel Vadot bool quiet = false; 1069ddaa99dSEmmanuel Vadot 1079ddaa99dSEmmanuel Vadot action = BACKLIGHT_QUERY; 1089ddaa99dSEmmanuel Vadot setname = false; 1099ddaa99dSEmmanuel Vadot fd = -1; 1109ddaa99dSEmmanuel Vadot 1119ddaa99dSEmmanuel Vadot while ((ch = getopt(argc, argv, "f:qhi")) != -1) { 1129ddaa99dSEmmanuel Vadot switch (ch) { 1139ddaa99dSEmmanuel Vadot case 'q': 1149ddaa99dSEmmanuel Vadot quiet = true; 1159ddaa99dSEmmanuel Vadot break; 1169ddaa99dSEmmanuel Vadot case 'f': 1179ddaa99dSEmmanuel Vadot setname = true; 1189ddaa99dSEmmanuel Vadot set_device_name(optarg); 1199ddaa99dSEmmanuel Vadot break; 1209ddaa99dSEmmanuel Vadot case 'i': 1219ddaa99dSEmmanuel Vadot action = BACKLIGHT_INFO; 1229ddaa99dSEmmanuel Vadot break; 1239ddaa99dSEmmanuel Vadot case 'h': 1249ddaa99dSEmmanuel Vadot usage(); 1259ddaa99dSEmmanuel Vadot break; 1269ddaa99dSEmmanuel Vadot } 1279ddaa99dSEmmanuel Vadot } 1289ddaa99dSEmmanuel Vadot 1299ddaa99dSEmmanuel Vadot argc -= optind; 1309ddaa99dSEmmanuel Vadot argv += optind; 1319ddaa99dSEmmanuel Vadot if (argc != 0) { 1329ddaa99dSEmmanuel Vadot if (strcmp("incr", argv[0]) == 0 || 1339ddaa99dSEmmanuel Vadot strcmp("+", argv[0]) == 0) { 1349ddaa99dSEmmanuel Vadot action = BACKLIGHT_INCR; 1359ddaa99dSEmmanuel Vadot argc -= 1; 1369ddaa99dSEmmanuel Vadot argv += 1; 1379ddaa99dSEmmanuel Vadot } 1389ddaa99dSEmmanuel Vadot else if (strcmp("decr", argv[0]) == 0 || 1399ddaa99dSEmmanuel Vadot strcmp("-", argv[0]) == 0) { 1409ddaa99dSEmmanuel Vadot action = BACKLIGHT_DECR; 1419ddaa99dSEmmanuel Vadot argc -= 1; 1429ddaa99dSEmmanuel Vadot argv += 1; 1439ddaa99dSEmmanuel Vadot } else 1449ddaa99dSEmmanuel Vadot action = BACKLIGHT_SET_BRIGHTNESS; 1459ddaa99dSEmmanuel Vadot 1469ddaa99dSEmmanuel Vadot if (argc == 1) { 1474d1308f4SBaptiste Daroussin /* ignore a trailing % for user friendlyness */ 148*cf64bfefSBaptiste Daroussin if (strlen(argv[0]) > 0 && 149*cf64bfefSBaptiste Daroussin argv[0][strlen(argv[0]) - 1] == '%') 1504d1308f4SBaptiste Daroussin argv[0][strlen(argv[0]) - 1] = '\0'; 1519ddaa99dSEmmanuel Vadot percent = strtonum(argv[0], 0, 100, &percent_error); 1529ddaa99dSEmmanuel Vadot if (percent_error) 1539ddaa99dSEmmanuel Vadot errx(1, "Cannot parse brightness level %s: %s", 1549ddaa99dSEmmanuel Vadot argv[0], 1559ddaa99dSEmmanuel Vadot percent_error); 1569ddaa99dSEmmanuel Vadot } 1579ddaa99dSEmmanuel Vadot } 1589ddaa99dSEmmanuel Vadot 1599ddaa99dSEmmanuel Vadot if ((fd = open(device_name, O_RDWR)) == -1) 1609ddaa99dSEmmanuel Vadot errx(1, "cannot open %s: %s", 1619ddaa99dSEmmanuel Vadot device_name, strerror(errno)); 1629ddaa99dSEmmanuel Vadot 1639ddaa99dSEmmanuel Vadot if (caph_limit_stdio() < 0) 1649ddaa99dSEmmanuel Vadot errx(1, "can't limit stdio rights"); 1659ddaa99dSEmmanuel Vadot caph_cache_catpages(); 1669ddaa99dSEmmanuel Vadot cap_rights_init(&right_ioctl, CAP_IOCTL); 1679ddaa99dSEmmanuel Vadot if (caph_rights_limit(fd, &right_ioctl) < 0) 1689ddaa99dSEmmanuel Vadot errx(1, "cap_right_limit() failed"); 1699ddaa99dSEmmanuel Vadot if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 1709ddaa99dSEmmanuel Vadot errx(1, "caph_ioctls_limit() failed"); 1719ddaa99dSEmmanuel Vadot if (caph_enter() < 0) 1729ddaa99dSEmmanuel Vadot errx(1, "failed to enter capability mode"); 1739ddaa99dSEmmanuel Vadot 1749ddaa99dSEmmanuel Vadot switch (action) { 1759ddaa99dSEmmanuel Vadot case BACKLIGHT_QUERY: 1769ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 1779ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 1789ddaa99dSEmmanuel Vadot if (quiet) 1799ddaa99dSEmmanuel Vadot printf("%u\n", props.brightness); 1809ddaa99dSEmmanuel Vadot else { 1819ddaa99dSEmmanuel Vadot printf("brightness: %d\n", props.brightness); 1829ddaa99dSEmmanuel Vadot if (props.nlevels != 0) { 1839ddaa99dSEmmanuel Vadot printf("levels:"); 1849ddaa99dSEmmanuel Vadot for (i = 0; i < props.nlevels; i++) 1859ddaa99dSEmmanuel Vadot printf(" %d", props.levels[i]); 1869ddaa99dSEmmanuel Vadot printf("\n"); 1879ddaa99dSEmmanuel Vadot } 1889ddaa99dSEmmanuel Vadot } 1899ddaa99dSEmmanuel Vadot break; 1909ddaa99dSEmmanuel Vadot case BACKLIGHT_SET_BRIGHTNESS: 1919ddaa99dSEmmanuel Vadot props.brightness = percent; 1929ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 1939ddaa99dSEmmanuel Vadot errx(1, "Cannot update the backlight device"); 1949ddaa99dSEmmanuel Vadot break; 1959ddaa99dSEmmanuel Vadot case BACKLIGHT_INCR: 1969ddaa99dSEmmanuel Vadot case BACKLIGHT_DECR: 1979ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 1989ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 1999ddaa99dSEmmanuel Vadot percent = percent == 0 ? 10 : percent; 2009ddaa99dSEmmanuel Vadot percent = action == BACKLIGHT_INCR ? percent : -percent; 2019ddaa99dSEmmanuel Vadot props.brightness += percent; 2029ddaa99dSEmmanuel Vadot if ((int)props.brightness < 0) 2039ddaa99dSEmmanuel Vadot props.brightness = 0; 2049ddaa99dSEmmanuel Vadot if (props.brightness > 100) 2059ddaa99dSEmmanuel Vadot props.brightness = 100; 2069ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 2079ddaa99dSEmmanuel Vadot errx(1, "Cannot update the backlight device"); 2089ddaa99dSEmmanuel Vadot break; 2099ddaa99dSEmmanuel Vadot case BACKLIGHT_INFO: 2109ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 2119ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 2129ddaa99dSEmmanuel Vadot if (quiet == false) { 2139ddaa99dSEmmanuel Vadot printf("Backlight name: %s\n", info.name); 2149ddaa99dSEmmanuel Vadot printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 2159ddaa99dSEmmanuel Vadot } else { 2169ddaa99dSEmmanuel Vadot printf("%s\n", info.name); 2179ddaa99dSEmmanuel Vadot printf("%s\n", backlight_type_to_string(info.type)); 2189ddaa99dSEmmanuel Vadot } 2199ddaa99dSEmmanuel Vadot break; 2209ddaa99dSEmmanuel Vadot } 2219ddaa99dSEmmanuel Vadot 2229ddaa99dSEmmanuel Vadot close(fd); 2239ddaa99dSEmmanuel Vadot return (0); 2249ddaa99dSEmmanuel Vadot } 225