2 * libbacklight - userspace interface to Linux backlight control
4 * Copyright © 2012 Intel Corporation
5 * Copyright 2010 Red Hat <mjg@redhat.com>
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:
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
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.
28 * Matthew Garrett <mjg@redhat.com>
29 * Tiago Vignatti <vignatti@freedesktop.org>
34 #include <libbacklight.h>
36 #include <linux/types.h>
38 #include <drm/drm_mode.h>
44 static const char *output_names[] = { "Unknown",
58 "Embedded DisplayPort"
61 static long backlight_get(struct backlight *backlight, char *node)
68 if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
71 fd = open(path, O_RDONLY);
77 ret = read(fd, &buffer, sizeof(buffer));
83 value = strtol(buffer, NULL, 10);
92 long backlight_get_brightness(struct backlight *backlight)
94 return backlight_get(backlight, "brightness");
97 long backlight_get_max_brightness(struct backlight *backlight)
99 return backlight_get(backlight, "max_brightness");
102 long backlight_get_actual_brightness(struct backlight *backlight)
104 return backlight_get(backlight, "actual_brightness");
107 long backlight_set_brightness(struct backlight *backlight, long brightness)
114 if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
117 fd = open(path, O_RDWR);
123 ret = read(fd, &buffer, sizeof(buffer));
129 if (asprintf(&buffer, "%ld", brightness) < 0)
132 ret = write(fd, buffer, strlen(buffer));
138 ret = backlight_get_brightness(backlight);
139 backlight->brightness = ret;
149 void backlight_destroy(struct backlight *backlight)
155 free(backlight->path);
160 struct backlight *backlight_init(struct udev_device *drm_device,
161 uint32_t connector_type)
163 const char *syspath = NULL;
164 char *pci_name = NULL;
165 char *chosen_path = NULL;
168 struct dirent *entry;
169 enum backlight_type type = 0;
171 struct backlight *backlight;
177 syspath = udev_device_get_syspath(drm_device);
181 if (asprintf(&path, "%s/%s", syspath, "device") < 0)
184 ret = readlink(path, buffer, sizeof(buffer));
190 pci_name = basename(buffer);
192 if (connector_type <= 0)
195 backlights = opendir("/sys/class/backlight");
199 /* Find the "best" backlight for the device. Firmware
200 interfaces are preferred over platform interfaces are
201 preferred over raw interfaces. For raw interfaces we'll
202 check if the device ID in the form of pci match, while
203 for firmware interfaces we require the pci ID to
204 match. It's assumed that platform interfaces always match,
205 since we can't actually associate them with IDs.
207 A further awkwardness is that, while it's theoretically
208 possible for an ACPI interface to include support for
209 changing the backlight of external devices, it's unlikely
210 to ever be done. It's effectively impossible for a platform
211 interface to do so. So if we get asked about anything that
212 isn't LVDS or eDP, we pretty much have to require that the
213 control be supplied via a raw interface */
215 while ((entry = readdir(backlights))) {
216 char *backlight_path;
218 enum backlight_type entry_type;
221 if (entry->d_name[0] == '.')
224 if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
228 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
231 fd = open(path, O_RDONLY);
236 ret = read (fd, &buffer, sizeof(buffer));
244 if (!strncmp(buffer, "raw\n", sizeof(buffer)))
245 entry_type = BACKLIGHT_RAW;
246 else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
247 entry_type = BACKLIGHT_PLATFORM;
248 else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
249 entry_type = BACKLIGHT_FIRMWARE;
253 if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
254 connector_type != DRM_MODE_CONNECTOR_eDP) {
255 /* External displays are assumed to require
256 gpu control at the moment */
257 if (entry_type != BACKLIGHT_RAW)
263 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
266 ret = readlink(path, buffer, sizeof(buffer));
273 parent = basename(buffer);
275 /* Perform matching for raw and firmware backlights -
276 platform backlights have to be assumed to match */
277 if (entry_type == BACKLIGHT_RAW ||
278 entry_type == BACKLIGHT_FIRMWARE) {
279 if (!(pci_name && !strcmp(pci_name, parent)))
283 if (entry_type < type)
290 chosen_path = strdup(backlight_path);
293 free(backlight_path);
300 backlight = malloc(sizeof(struct backlight));
305 backlight->path = chosen_path;
306 backlight->type = type;
308 backlight->max_brightness = backlight_get_max_brightness(backlight);
309 if (backlight->max_brightness < 0)
312 backlight->brightness = backlight_get_actual_brightness(backlight);
313 if (backlight->brightness < 0)