• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libbacklight - userspace interface to Linux backlight control
3  *
4  * Copyright © 2012 Intel Corporation
5  * Copyright 2010 Red Hat <mjg@redhat.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Matthew Garrett <mjg@redhat.com>
29  *    Tiago Vignatti <vignatti@freedesktop.org>
30  */
31 
32 #include "config.h"
33 
34 #include "libbacklight.h"
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <linux/types.h>
40 #include <dirent.h>
41 #include <drm.h>
42 #include <fcntl.h>
43 #include <malloc.h>
44 #include <string.h>
45 #include <errno.h>
46 
47 #include "shared/string-helpers.h"
48 
backlight_get(struct backlight * backlight,char * node)49 static long backlight_get(struct backlight *backlight, char *node)
50 {
51 	char buffer[100];
52 	char *path;
53 	int fd, value;
54 	long ret;
55 
56 	if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
57 		return -ENOMEM;
58 	fd = open(path, O_RDONLY);
59 	if (fd < 0) {
60 		ret = -1;
61 		goto out;
62 	}
63 
64 	ret = read(fd, &buffer, sizeof(buffer));
65 	if (ret < 1) {
66 		ret = -1;
67 		goto out;
68 	}
69 
70 	if (!safe_strtoint(buffer, &value)) {
71 		ret = -1;
72 		goto out;
73 	}
74 
75 	ret = value;
76 
77 out:
78 	if (fd >= 0)
79 		close(fd);
80 	free(path);
81 	return ret;
82 }
83 
backlight_get_brightness(struct backlight * backlight)84 long backlight_get_brightness(struct backlight *backlight)
85 {
86 	return backlight_get(backlight, "brightness");
87 }
88 
backlight_get_max_brightness(struct backlight * backlight)89 long backlight_get_max_brightness(struct backlight *backlight)
90 {
91 	return backlight_get(backlight, "max_brightness");
92 }
93 
backlight_get_actual_brightness(struct backlight * backlight)94 long backlight_get_actual_brightness(struct backlight *backlight)
95 {
96 	return backlight_get(backlight, "actual_brightness");
97 }
98 
backlight_set_brightness(struct backlight * backlight,long brightness)99 long backlight_set_brightness(struct backlight *backlight, long brightness)
100 {
101 	char *path;
102 	char *buffer = NULL;
103 	int fd;
104 	long ret;
105 
106 	if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
107 		return -ENOMEM;
108 
109 	fd = open(path, O_RDWR);
110 	if (fd < 0) {
111 		ret = -1;
112 		goto out;
113 	}
114 
115 	ret = read(fd, &buffer, sizeof(buffer));
116 	if (ret < 1) {
117 		ret = -1;
118 		goto out;
119 	}
120 
121 	if (asprintf(&buffer, "%ld", brightness) < 0) {
122 		ret = -1;
123 		goto out;
124 	}
125 
126 	ret = write(fd, buffer, strlen(buffer));
127 	if (ret < 0) {
128 		ret = -1;
129 		goto out;
130 	}
131 
132 	ret = backlight_get_brightness(backlight);
133 	backlight->brightness = ret;
134 out:
135 	free(buffer);
136 	free(path);
137 	if (fd >= 0)
138 		close(fd);
139 	return ret;
140 }
141 
backlight_destroy(struct backlight * backlight)142 void backlight_destroy(struct backlight *backlight)
143 {
144 	if (!backlight)
145 		return;
146 
147 	if (backlight->path)
148 		free(backlight->path);
149 
150 	free(backlight);
151 }
152 
backlight_init(struct udev_device * drm_device,uint32_t connector_type)153 struct backlight *backlight_init(struct udev_device *drm_device,
154 				 uint32_t connector_type)
155 {
156 	const char *syspath = NULL;
157 	char *pci_name = NULL;
158 	char *chosen_path = NULL;
159 	char *path = NULL;
160 	DIR *backlights = NULL;
161 	struct dirent *entry;
162 	enum backlight_type type = 0;
163 	char buffer[100];
164 	struct backlight *backlight = NULL;
165 	int ret;
166 
167 	if (!drm_device)
168 		return NULL;
169 
170 	syspath = udev_device_get_syspath(drm_device);
171 	if (!syspath)
172 		return NULL;
173 
174 	if (asprintf(&path, "%s/%s", syspath, "device") < 0)
175 		return NULL;
176 
177 	ret = readlink(path, buffer, sizeof(buffer) - 1);
178 	free(path);
179 	if (ret < 0)
180 		return NULL;
181 
182 	buffer[ret] = '\0';
183 	pci_name = basename(buffer);
184 
185 	if (connector_type <= 0)
186 		return NULL;
187 
188 	backlights = opendir("/sys/class/backlight");
189 	if (!backlights)
190 		return NULL;
191 
192 	/* Find the "best" backlight for the device. Firmware
193 	   interfaces are preferred over platform interfaces are
194 	   preferred over raw interfaces. For raw interfaces we'll
195 	   check if the device ID in the form of pci match, while
196 	   for firmware interfaces we require the pci ID to
197 	   match. It's assumed that platform interfaces always match,
198 	   since we can't actually associate them with IDs.
199 
200 	   A further awkwardness is that, while it's theoretically
201 	   possible for an ACPI interface to include support for
202 	   changing the backlight of external devices, it's unlikely
203 	   to ever be done. It's effectively impossible for a platform
204 	   interface to do so. So if we get asked about anything that
205 	   isn't LVDS or eDP, we pretty much have to require that the
206 	   control be supplied via a raw interface */
207 
208 	while ((entry = readdir(backlights))) {
209 		char *backlight_path;
210 		char *parent;
211 		enum backlight_type entry_type;
212 		int fd;
213 
214 		if (entry->d_name[0] == '.')
215 			continue;
216 
217 		if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
218 			     entry->d_name) < 0)
219 			goto err;
220 
221 		if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
222 			free(backlight_path);
223 			goto err;
224 		}
225 
226 		fd = open(path, O_RDONLY);
227 
228 		if (fd < 0)
229 			goto out;
230 
231 		ret = read (fd, &buffer, sizeof(buffer));
232 		close (fd);
233 
234 		if (ret < 1)
235 			goto out;
236 
237 		buffer[ret] = '\0';
238 
239 		if (!strncmp(buffer, "raw\n", sizeof(buffer)))
240 			entry_type = BACKLIGHT_RAW;
241 		else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
242 			entry_type = BACKLIGHT_PLATFORM;
243 		else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
244 			entry_type = BACKLIGHT_FIRMWARE;
245 		else
246 			goto out;
247 
248 		if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
249 		    connector_type != DRM_MODE_CONNECTOR_eDP) {
250 			/* External displays are assumed to require
251 			   gpu control at the moment */
252 			if (entry_type != BACKLIGHT_RAW)
253 				goto out;
254 		}
255 
256 		free (path);
257 
258 		if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
259 			goto err;
260 
261 		ret = readlink(path, buffer, sizeof(buffer) - 1);
262 
263 		if (ret < 0)
264 			goto out;
265 
266 		buffer[ret] = '\0';
267 
268 		parent = basename(buffer);
269 
270 		/* Perform matching for raw and firmware backlights -
271 		   platform backlights have to be assumed to match */
272 		if (entry_type == BACKLIGHT_RAW ||
273 		    entry_type == BACKLIGHT_FIRMWARE) {
274 			if (!(pci_name && !strcmp(pci_name, parent)))
275 				goto out;
276 		}
277 
278 		if (entry_type < type)
279 			goto out;
280 
281 		type = entry_type;
282 
283 		if (chosen_path)
284 			free(chosen_path);
285 		chosen_path = strdup(backlight_path);
286 
287 	out:
288 		free(backlight_path);
289 		free(path);
290 	}
291 
292 	if (!chosen_path)
293 		goto err;
294 
295 	backlight = malloc(sizeof(struct backlight));
296 
297 	if (!backlight)
298 		goto err;
299 
300 	backlight->path = chosen_path;
301 	backlight->type = type;
302 
303 	backlight->max_brightness = backlight_get_max_brightness(backlight);
304 	if (backlight->max_brightness < 0)
305 		goto err;
306 
307 	backlight->brightness = backlight_get_actual_brightness(backlight);
308 	if (backlight->brightness < 0)
309 		goto err;
310 
311 	closedir(backlights);
312 	return backlight;
313 err:
314 	closedir(backlights);
315 	free (chosen_path);
316 	free (backlight);
317 	return NULL;
318 }
319