xref: /freebsd/usr.bin/backlight/backlight.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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