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