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