19ddaa99dSEmmanuel Vadot /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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
289ddaa99dSEmmanuel Vadot #include <sys/types.h>
299ddaa99dSEmmanuel Vadot #include <sys/ioctl.h>
309ddaa99dSEmmanuel Vadot #include <stdbool.h>
319ddaa99dSEmmanuel Vadot #include <sys/capsicum.h>
329ddaa99dSEmmanuel Vadot #include <sys/backlight.h>
339ddaa99dSEmmanuel Vadot
349ddaa99dSEmmanuel Vadot #include <err.h>
359ddaa99dSEmmanuel Vadot #include <errno.h>
369ddaa99dSEmmanuel Vadot #include <fcntl.h>
379ddaa99dSEmmanuel Vadot #include <limits.h>
389ddaa99dSEmmanuel Vadot #include <stdio.h>
399ddaa99dSEmmanuel Vadot #include <stdlib.h>
409ddaa99dSEmmanuel Vadot #include <string.h>
419ddaa99dSEmmanuel Vadot #include <unistd.h>
429ddaa99dSEmmanuel Vadot #include <capsicum_helpers.h>
439ddaa99dSEmmanuel Vadot
449ddaa99dSEmmanuel Vadot #define BACKLIGHT_QUERY 0x0001
459ddaa99dSEmmanuel Vadot #define BACKLIGHT_SET_BRIGHTNESS 0x0002
469ddaa99dSEmmanuel Vadot #define BACKLIGHT_INCR 0x0004
479ddaa99dSEmmanuel Vadot #define BACKLIGHT_DECR 0x0008
489ddaa99dSEmmanuel Vadot #define BACKLIGHT_INFO 0x0010
499ddaa99dSEmmanuel Vadot
509ddaa99dSEmmanuel Vadot static char device_name[PATH_MAX] = "/dev/backlight/backlight0";
519ddaa99dSEmmanuel Vadot
529ddaa99dSEmmanuel Vadot static void
set_device_name(const char * name)539ddaa99dSEmmanuel Vadot set_device_name(const char *name)
549ddaa99dSEmmanuel Vadot {
559ddaa99dSEmmanuel Vadot
569ddaa99dSEmmanuel Vadot if (name[0] == '/')
579ddaa99dSEmmanuel Vadot strlcpy(device_name, name, sizeof(device_name));
589ddaa99dSEmmanuel Vadot else
599ddaa99dSEmmanuel Vadot snprintf(device_name, sizeof(device_name), "/dev/backlight/%s", name);
609ddaa99dSEmmanuel Vadot }
619ddaa99dSEmmanuel Vadot
629ddaa99dSEmmanuel Vadot static void
usage(void)639ddaa99dSEmmanuel Vadot usage(void)
649ddaa99dSEmmanuel Vadot {
659ddaa99dSEmmanuel Vadot fprintf(stderr, "Usage:\n");
66f4b00609SMateusz Piotrowski fprintf(stderr, "\tbacklight [-q] [-f device]\n");
67f4b00609SMateusz Piotrowski fprintf(stderr, "\tbacklight [-q] [-f device] -i\n");
68f4b00609SMateusz Piotrowski fprintf(stderr, "\tbacklight [-f device] value\n");
69f4b00609SMateusz Piotrowski fprintf(stderr, "\tbacklight [-f device] incr|+ value\n");
70f4b00609SMateusz Piotrowski fprintf(stderr, "\tbacklight [-f device] decr|- value\n");
719ddaa99dSEmmanuel Vadot exit(1);
729ddaa99dSEmmanuel Vadot }
739ddaa99dSEmmanuel Vadot
749ddaa99dSEmmanuel Vadot static const char *
backlight_type_to_string(enum backlight_info_type type)759ddaa99dSEmmanuel Vadot backlight_type_to_string(enum backlight_info_type type)
769ddaa99dSEmmanuel Vadot {
779ddaa99dSEmmanuel Vadot switch (type) {
789ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_PANEL:
799ddaa99dSEmmanuel Vadot return ("Panel");
809ddaa99dSEmmanuel Vadot case BACKLIGHT_TYPE_KEYBOARD:
819ddaa99dSEmmanuel Vadot return ("Keyboard");
829ddaa99dSEmmanuel Vadot }
839ddaa99dSEmmanuel Vadot
849ddaa99dSEmmanuel Vadot return ("Unknown");
859ddaa99dSEmmanuel Vadot }
869ddaa99dSEmmanuel Vadot
879ddaa99dSEmmanuel Vadot int
main(int argc,char * argv[])889ddaa99dSEmmanuel Vadot main(int argc, char *argv[])
899ddaa99dSEmmanuel Vadot {
909ddaa99dSEmmanuel Vadot struct backlight_props props;
919ddaa99dSEmmanuel Vadot struct backlight_info info;
929ddaa99dSEmmanuel Vadot int fd;
939ddaa99dSEmmanuel Vadot int action, ch;
949ddaa99dSEmmanuel Vadot cap_rights_t right_ioctl;
959ddaa99dSEmmanuel Vadot const unsigned long backlight_ioctls[] = {
969ddaa99dSEmmanuel Vadot BACKLIGHTGETSTATUS,
979ddaa99dSEmmanuel Vadot BACKLIGHTUPDATESTATUS,
989ddaa99dSEmmanuel Vadot BACKLIGHTGETINFO};
993b005d51SDavid Schlachter long percent = -1;
1009ddaa99dSEmmanuel Vadot const char *percent_error;
1019ddaa99dSEmmanuel Vadot uint32_t i;
1029ddaa99dSEmmanuel Vadot bool quiet = false;
1039ddaa99dSEmmanuel Vadot
1049ddaa99dSEmmanuel Vadot action = BACKLIGHT_QUERY;
1059ddaa99dSEmmanuel Vadot fd = -1;
1069ddaa99dSEmmanuel Vadot
1079ddaa99dSEmmanuel Vadot while ((ch = getopt(argc, argv, "f:qhi")) != -1) {
1089ddaa99dSEmmanuel Vadot switch (ch) {
1099ddaa99dSEmmanuel Vadot case 'q':
1109ddaa99dSEmmanuel Vadot quiet = true;
1119ddaa99dSEmmanuel Vadot break;
1129ddaa99dSEmmanuel Vadot case 'f':
1139ddaa99dSEmmanuel Vadot set_device_name(optarg);
1149ddaa99dSEmmanuel Vadot break;
1159ddaa99dSEmmanuel Vadot case 'i':
1169ddaa99dSEmmanuel Vadot action = BACKLIGHT_INFO;
1179ddaa99dSEmmanuel Vadot break;
1189ddaa99dSEmmanuel Vadot case 'h':
1199ddaa99dSEmmanuel Vadot usage();
1209ddaa99dSEmmanuel Vadot break;
1219ddaa99dSEmmanuel Vadot }
1229ddaa99dSEmmanuel Vadot }
1239ddaa99dSEmmanuel Vadot
1249ddaa99dSEmmanuel Vadot argc -= optind;
1259ddaa99dSEmmanuel Vadot argv += optind;
1269ddaa99dSEmmanuel Vadot if (argc != 0) {
1279ddaa99dSEmmanuel Vadot if (strcmp("incr", argv[0]) == 0 ||
1289ddaa99dSEmmanuel Vadot strcmp("+", argv[0]) == 0) {
1299ddaa99dSEmmanuel Vadot action = BACKLIGHT_INCR;
1309ddaa99dSEmmanuel Vadot argc -= 1;
1319ddaa99dSEmmanuel Vadot argv += 1;
1329ddaa99dSEmmanuel Vadot }
1339ddaa99dSEmmanuel Vadot else if (strcmp("decr", argv[0]) == 0 ||
1349ddaa99dSEmmanuel Vadot strcmp("-", argv[0]) == 0) {
1359ddaa99dSEmmanuel Vadot action = BACKLIGHT_DECR;
1369ddaa99dSEmmanuel Vadot argc -= 1;
1379ddaa99dSEmmanuel Vadot argv += 1;
1389ddaa99dSEmmanuel Vadot } else
1399ddaa99dSEmmanuel Vadot action = BACKLIGHT_SET_BRIGHTNESS;
1409ddaa99dSEmmanuel Vadot
1419ddaa99dSEmmanuel Vadot if (argc == 1) {
1424d1308f4SBaptiste Daroussin /* ignore a trailing % for user friendlyness */
143cf64bfefSBaptiste Daroussin if (strlen(argv[0]) > 0 &&
144cf64bfefSBaptiste Daroussin argv[0][strlen(argv[0]) - 1] == '%')
1454d1308f4SBaptiste Daroussin argv[0][strlen(argv[0]) - 1] = '\0';
1469ddaa99dSEmmanuel Vadot percent = strtonum(argv[0], 0, 100, &percent_error);
1479ddaa99dSEmmanuel Vadot if (percent_error)
1489ddaa99dSEmmanuel Vadot errx(1, "Cannot parse brightness level %s: %s",
1499ddaa99dSEmmanuel Vadot argv[0],
1509ddaa99dSEmmanuel Vadot percent_error);
1519ddaa99dSEmmanuel Vadot }
1529ddaa99dSEmmanuel Vadot }
1539ddaa99dSEmmanuel Vadot
1549ddaa99dSEmmanuel Vadot if ((fd = open(device_name, O_RDWR)) == -1)
1559ddaa99dSEmmanuel Vadot errx(1, "cannot open %s: %s",
1569ddaa99dSEmmanuel Vadot device_name, strerror(errno));
1579ddaa99dSEmmanuel Vadot
1589ddaa99dSEmmanuel Vadot if (caph_limit_stdio() < 0)
1599ddaa99dSEmmanuel Vadot errx(1, "can't limit stdio rights");
1609ddaa99dSEmmanuel Vadot caph_cache_catpages();
1619ddaa99dSEmmanuel Vadot cap_rights_init(&right_ioctl, CAP_IOCTL);
1629ddaa99dSEmmanuel Vadot if (caph_rights_limit(fd, &right_ioctl) < 0)
1639ddaa99dSEmmanuel Vadot errx(1, "cap_right_limit() failed");
1649ddaa99dSEmmanuel Vadot if (caph_ioctls_limit(fd, backlight_ioctls, nitems(backlight_ioctls)) < 0)
1659ddaa99dSEmmanuel Vadot errx(1, "caph_ioctls_limit() failed");
1669ddaa99dSEmmanuel Vadot if (caph_enter() < 0)
1679ddaa99dSEmmanuel Vadot errx(1, "failed to enter capability mode");
1689ddaa99dSEmmanuel Vadot
1699ddaa99dSEmmanuel Vadot switch (action) {
1709ddaa99dSEmmanuel Vadot case BACKLIGHT_QUERY:
1719ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1)
1729ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device");
1739ddaa99dSEmmanuel Vadot if (quiet)
1749ddaa99dSEmmanuel Vadot printf("%u\n", props.brightness);
1759ddaa99dSEmmanuel Vadot else {
1769ddaa99dSEmmanuel Vadot printf("brightness: %d\n", props.brightness);
1779ddaa99dSEmmanuel Vadot if (props.nlevels != 0) {
1789ddaa99dSEmmanuel Vadot printf("levels:");
1799ddaa99dSEmmanuel Vadot for (i = 0; i < props.nlevels; i++)
1809ddaa99dSEmmanuel Vadot printf(" %d", props.levels[i]);
1819ddaa99dSEmmanuel Vadot printf("\n");
1829ddaa99dSEmmanuel Vadot }
1839ddaa99dSEmmanuel Vadot }
1849ddaa99dSEmmanuel Vadot break;
1859ddaa99dSEmmanuel Vadot case BACKLIGHT_SET_BRIGHTNESS:
1863b005d51SDavid Schlachter if (percent == -1)
1873b005d51SDavid Schlachter usage();
1889ddaa99dSEmmanuel Vadot props.brightness = percent;
1899ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTUPDATESTATUS, &props) == -1)
1909ddaa99dSEmmanuel Vadot errx(1, "Cannot update the backlight device");
1919ddaa99dSEmmanuel Vadot break;
1929ddaa99dSEmmanuel Vadot case BACKLIGHT_INCR:
1939ddaa99dSEmmanuel Vadot case BACKLIGHT_DECR:
1943b005d51SDavid Schlachter if (percent == 0)
1953b005d51SDavid Schlachter /* Avoid any ioctl if we don't have anything to do */
1963b005d51SDavid Schlachter break;
1979ddaa99dSEmmanuel Vadot if (ioctl(fd, BACKLIGHTGETSTATUS, &props) == -1)
1989ddaa99dSEmmanuel Vadot errx(1, "Cannot query the backlight device");
1993b005d51SDavid Schlachter percent = percent == -1 ? 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