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