1*9ddaa99dSEmmanuel Vadot /*- 2*9ddaa99dSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*9ddaa99dSEmmanuel Vadot * 4*9ddaa99dSEmmanuel Vadot * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org> 5*9ddaa99dSEmmanuel Vadot * 6*9ddaa99dSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 7*9ddaa99dSEmmanuel Vadot * modification, are permitted provided that the following conditions 8*9ddaa99dSEmmanuel Vadot * are met: 9*9ddaa99dSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 10*9ddaa99dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 11*9ddaa99dSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 12*9ddaa99dSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 13*9ddaa99dSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 14*9ddaa99dSEmmanuel Vadot * 15*9ddaa99dSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*9ddaa99dSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*9ddaa99dSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*9ddaa99dSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*9ddaa99dSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*9ddaa99dSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*9ddaa99dSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*9ddaa99dSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*9ddaa99dSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*9ddaa99dSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*9ddaa99dSEmmanuel Vadot * SUCH DAMAGE. 26*9ddaa99dSEmmanuel Vadot * 27*9ddaa99dSEmmanuel Vadot * $FreeBSD$ 28*9ddaa99dSEmmanuel Vadot */ 29*9ddaa99dSEmmanuel Vadot 30*9ddaa99dSEmmanuel Vadot #include <sys/types.h> 31*9ddaa99dSEmmanuel Vadot #include <sys/ioctl.h> 32*9ddaa99dSEmmanuel Vadot #include <stdbool.h> 33*9ddaa99dSEmmanuel Vadot #include <sys/capsicum.h> 34*9ddaa99dSEmmanuel Vadot #include <sys/backlight.h> 35*9ddaa99dSEmmanuel Vadot 36*9ddaa99dSEmmanuel Vadot #include <err.h> 37*9ddaa99dSEmmanuel Vadot #include <errno.h> 38*9ddaa99dSEmmanuel Vadot #include <fcntl.h> 39*9ddaa99dSEmmanuel Vadot #include <limits.h> 40*9ddaa99dSEmmanuel Vadot #include <stdio.h> 41*9ddaa99dSEmmanuel Vadot #include <stdlib.h> 42*9ddaa99dSEmmanuel Vadot #include <string.h> 43*9ddaa99dSEmmanuel Vadot #include <unistd.h> 44*9ddaa99dSEmmanuel Vadot #include <capsicum_helpers.h> 45*9ddaa99dSEmmanuel Vadot 46*9ddaa99dSEmmanuel Vadot #define BACKLIGHT_QUERY 0x0001 47*9ddaa99dSEmmanuel Vadot #define BACKLIGHT_SET_BRIGHTNESS 0x0002 48*9ddaa99dSEmmanuel Vadot #define BACKLIGHT_INCR 0x0004 49*9ddaa99dSEmmanuel Vadot #define BACKLIGHT_DECR 0x0008 50*9ddaa99dSEmmanuel Vadot #define BACKLIGHT_INFO 0x0010 51*9ddaa99dSEmmanuel Vadot 52*9ddaa99dSEmmanuel Vadot static char device_name[PATH_MAX] = "/dev/backlight/backlight0"; 53*9ddaa99dSEmmanuel Vadot 54*9ddaa99dSEmmanuel Vadot static void 55*9ddaa99dSEmmanuel Vadot set_device_name(const char *name) 56*9ddaa99dSEmmanuel Vadot { 57*9ddaa99dSEmmanuel Vadot 58*9ddaa99dSEmmanuel Vadot if (name[0] == '/') 59*9ddaa99dSEmmanuel Vadot strlcpy(device_name, name, sizeof(device_name)); 60*9ddaa99dSEmmanuel Vadot else 61*9ddaa99dSEmmanuel Vadot snprintf(device_name, sizeof(device_name), "/dev/backlight/%s", name); 62*9ddaa99dSEmmanuel Vadot } 63*9ddaa99dSEmmanuel Vadot 64*9ddaa99dSEmmanuel Vadot static void 65*9ddaa99dSEmmanuel Vadot usage(void) 66*9ddaa99dSEmmanuel Vadot { 67*9ddaa99dSEmmanuel Vadot fprintf(stderr, "Usage:\n"); 68*9ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev]\n"); 69*9ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] -i\n"); 70*9ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] <percent>\n"); 71*9ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] incr|+ <percent>\n"); 72*9ddaa99dSEmmanuel Vadot fprintf(stderr, "\tbacklight [-f dev] decr|- <percent>\n"); 73*9ddaa99dSEmmanuel Vadot exit(1); 74*9ddaa99dSEmmanuel Vadot } 75*9ddaa99dSEmmanuel Vadot 76*9ddaa99dSEmmanuel Vadot static const char * 77*9ddaa99dSEmmanuel Vadot backlight_type_to_string(enum backlight_info_type type) 78*9ddaa99dSEmmanuel Vadot { 79*9ddaa99dSEmmanuel Vadot switch (type) { 80*9ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_PANEL: 81*9ddaa99dSEmmanuel Vadot return ("Panel"); 82*9ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_KEYBOARD: 83*9ddaa99dSEmmanuel Vadot return ("Keyboard"); 84*9ddaa99dSEmmanuel Vadot } 85*9ddaa99dSEmmanuel Vadot 86*9ddaa99dSEmmanuel Vadot return ("Unknown"); 87*9ddaa99dSEmmanuel Vadot } 88*9ddaa99dSEmmanuel Vadot 89*9ddaa99dSEmmanuel Vadot int 90*9ddaa99dSEmmanuel Vadot main(int argc, char *argv[]) 91*9ddaa99dSEmmanuel Vadot { 92*9ddaa99dSEmmanuel Vadot struct backlight_props props; 93*9ddaa99dSEmmanuel Vadot struct backlight_info info; 94*9ddaa99dSEmmanuel Vadot int fd; 95*9ddaa99dSEmmanuel Vadot int action, ch; 96*9ddaa99dSEmmanuel Vadot cap_rights_t right_ioctl; 97*9ddaa99dSEmmanuel Vadot const unsigned long backlight_ioctls[] = { 98*9ddaa99dSEmmanuel Vadot BACKLIGHTGETSTATUS, 99*9ddaa99dSEmmanuel Vadot BACKLIGHTUPDATESTATUS, 100*9ddaa99dSEmmanuel Vadot BACKLIGHTGETINFO}; 101*9ddaa99dSEmmanuel Vadot long percent = 0; 102*9ddaa99dSEmmanuel Vadot const char *percent_error; 103*9ddaa99dSEmmanuel Vadot uint32_t i; 104*9ddaa99dSEmmanuel Vadot bool setname; 105*9ddaa99dSEmmanuel Vadot bool quiet = false; 106*9ddaa99dSEmmanuel Vadot 107*9ddaa99dSEmmanuel Vadot action = BACKLIGHT_QUERY; 108*9ddaa99dSEmmanuel Vadot setname = false; 109*9ddaa99dSEmmanuel Vadot fd = -1; 110*9ddaa99dSEmmanuel Vadot 111*9ddaa99dSEmmanuel Vadot while ((ch = getopt(argc, argv, "f:qhi")) != -1) { 112*9ddaa99dSEmmanuel Vadot switch (ch) { 113*9ddaa99dSEmmanuel Vadot case 'q': 114*9ddaa99dSEmmanuel Vadot quiet = true; 115*9ddaa99dSEmmanuel Vadot break; 116*9ddaa99dSEmmanuel Vadot case 'f': 117*9ddaa99dSEmmanuel Vadot setname = true; 118*9ddaa99dSEmmanuel Vadot set_device_name(optarg); 119*9ddaa99dSEmmanuel Vadot break; 120*9ddaa99dSEmmanuel Vadot case 'i': 121*9ddaa99dSEmmanuel Vadot action = BACKLIGHT_INFO; 122*9ddaa99dSEmmanuel Vadot break; 123*9ddaa99dSEmmanuel Vadot case 'h': 124*9ddaa99dSEmmanuel Vadot usage(); 125*9ddaa99dSEmmanuel Vadot break; 126*9ddaa99dSEmmanuel Vadot } 127*9ddaa99dSEmmanuel Vadot } 128*9ddaa99dSEmmanuel Vadot 129*9ddaa99dSEmmanuel Vadot argc -= optind; 130*9ddaa99dSEmmanuel Vadot argv += optind; 131*9ddaa99dSEmmanuel Vadot if (argc != 0) { 132*9ddaa99dSEmmanuel Vadot if (strcmp("incr", argv[0]) == 0 || 133*9ddaa99dSEmmanuel Vadot strcmp("+", argv[0]) == 0) { 134*9ddaa99dSEmmanuel Vadot action = BACKLIGHT_INCR; 135*9ddaa99dSEmmanuel Vadot argc -= 1; 136*9ddaa99dSEmmanuel Vadot argv += 1; 137*9ddaa99dSEmmanuel Vadot } 138*9ddaa99dSEmmanuel Vadot else if (strcmp("decr", argv[0]) == 0 || 139*9ddaa99dSEmmanuel Vadot strcmp("-", argv[0]) == 0) { 140*9ddaa99dSEmmanuel Vadot action = BACKLIGHT_DECR; 141*9ddaa99dSEmmanuel Vadot argc -= 1; 142*9ddaa99dSEmmanuel Vadot argv += 1; 143*9ddaa99dSEmmanuel Vadot } else 144*9ddaa99dSEmmanuel Vadot action = BACKLIGHT_SET_BRIGHTNESS; 145*9ddaa99dSEmmanuel Vadot 146*9ddaa99dSEmmanuel Vadot if (argc == 1) { 147*9ddaa99dSEmmanuel Vadot percent = strtonum(argv[0], 0, 100, &percent_error); 148*9ddaa99dSEmmanuel Vadot if (percent_error) 149*9ddaa99dSEmmanuel Vadot errx(1, "Cannot parse brightness level %s: %s", 150*9ddaa99dSEmmanuel Vadot argv[0], 151*9ddaa99dSEmmanuel Vadot percent_error); 152*9ddaa99dSEmmanuel Vadot } 153*9ddaa99dSEmmanuel Vadot } 154*9ddaa99dSEmmanuel Vadot 155*9ddaa99dSEmmanuel Vadot if ((fd = open(device_name, O_RDWR)) == -1) 156*9ddaa99dSEmmanuel Vadot errx(1, "cannot open %s: %s", 157*9ddaa99dSEmmanuel Vadot device_name, strerror(errno)); 158*9ddaa99dSEmmanuel Vadot 159*9ddaa99dSEmmanuel Vadot if (caph_limit_stdio() < 0) 160*9ddaa99dSEmmanuel Vadot errx(1, "can't limit stdio rights"); 161*9ddaa99dSEmmanuel Vadot caph_cache_catpages(); 162*9ddaa99dSEmmanuel Vadot cap_rights_init(&right_ioctl, CAP_IOCTL); 163*9ddaa99dSEmmanuel Vadot if (caph_rights_limit(fd, &right_ioctl) < 0) 164*9ddaa99dSEmmanuel Vadot errx(1, "cap_right_limit() failed"); 165*9ddaa99dSEmmanuel Vadot if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0) 166*9ddaa99dSEmmanuel Vadot errx(1, "caph_ioctls_limit() failed"); 167*9ddaa99dSEmmanuel Vadot if (caph_enter() < 0) 168*9ddaa99dSEmmanuel Vadot errx(1, "failed to enter capability mode"); 169*9ddaa99dSEmmanuel Vadot 170*9ddaa99dSEmmanuel Vadot switch (action) { 171*9ddaa99dSEmmanuel Vadot case BACKLIGHT_QUERY: 172*9ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 173*9ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 174*9ddaa99dSEmmanuel Vadot if (quiet) 175*9ddaa99dSEmmanuel Vadot printf("%u\n", props.brightness); 176*9ddaa99dSEmmanuel Vadot else { 177*9ddaa99dSEmmanuel Vadot printf("brightness: %d\n", props.brightness); 178*9ddaa99dSEmmanuel Vadot if (props.nlevels != 0) { 179*9ddaa99dSEmmanuel Vadot printf("levels:"); 180*9ddaa99dSEmmanuel Vadot for (i = 0; i < props.nlevels; i++) 181*9ddaa99dSEmmanuel Vadot printf(" %d", props.levels[i]); 182*9ddaa99dSEmmanuel Vadot printf("\n"); 183*9ddaa99dSEmmanuel Vadot } 184*9ddaa99dSEmmanuel Vadot } 185*9ddaa99dSEmmanuel Vadot break; 186*9ddaa99dSEmmanuel Vadot case BACKLIGHT_SET_BRIGHTNESS: 187*9ddaa99dSEmmanuel Vadot props.brightness = percent; 188*9ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 189*9ddaa99dSEmmanuel Vadot errx(1, "Cannot update the backlight device"); 190*9ddaa99dSEmmanuel Vadot break; 191*9ddaa99dSEmmanuel Vadot case BACKLIGHT_INCR: 192*9ddaa99dSEmmanuel Vadot case BACKLIGHT_DECR: 193*9ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1) 194*9ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 195*9ddaa99dSEmmanuel Vadot percent = percent == 0 ? 10 : percent; 196*9ddaa99dSEmmanuel Vadot percent = action == BACKLIGHT_INCR ? percent : -percent; 197*9ddaa99dSEmmanuel Vadot props.brightness += percent; 198*9ddaa99dSEmmanuel Vadot if ((int)props.brightness < 0) 199*9ddaa99dSEmmanuel Vadot props.brightness = 0; 200*9ddaa99dSEmmanuel Vadot if (props.brightness > 100) 201*9ddaa99dSEmmanuel Vadot props.brightness = 100; 202*9ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1) 203*9ddaa99dSEmmanuel Vadot errx(1, "Cannot update the backlight device"); 204*9ddaa99dSEmmanuel Vadot break; 205*9ddaa99dSEmmanuel Vadot case BACKLIGHT_INFO: 206*9ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETINFO, &info) == -1) 207*9ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device"); 208*9ddaa99dSEmmanuel Vadot if (quiet == false) { 209*9ddaa99dSEmmanuel Vadot printf("Backlight name: %s\n", info.name); 210*9ddaa99dSEmmanuel Vadot printf("Backlight hardware type: %s\n", backlight_type_to_string(info.type)); 211*9ddaa99dSEmmanuel Vadot } else { 212*9ddaa99dSEmmanuel Vadot printf("%s\n", info.name); 213*9ddaa99dSEmmanuel Vadot printf("%s\n", backlight_type_to_string(info.type)); 214*9ddaa99dSEmmanuel Vadot } 215*9ddaa99dSEmmanuel Vadot break; 216*9ddaa99dSEmmanuel Vadot } 217*9ddaa99dSEmmanuel Vadot 218*9ddaa99dSEmmanuel Vadot close(fd); 219*9ddaa99dSEmmanuel Vadot return (0); 220*9ddaa99dSEmmanuel Vadot } 221