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"
38 #include <linux/types.h>
46 static long backlight_get(struct backlight *backlight, char *node)
53 if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
56 fd = open(path, O_RDONLY);
62 ret = read(fd, &buffer, sizeof(buffer));
68 value = strtol(buffer, NULL, 10);
77 long backlight_get_brightness(struct backlight *backlight)
79 return backlight_get(backlight, "brightness");
82 long backlight_get_max_brightness(struct backlight *backlight)
84 return backlight_get(backlight, "max_brightness");
87 long backlight_get_actual_brightness(struct backlight *backlight)
89 return backlight_get(backlight, "actual_brightness");
92 long backlight_set_brightness(struct backlight *backlight, long brightness)
99 if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
102 fd = open(path, O_RDWR);
108 ret = read(fd, &buffer, sizeof(buffer));
114 if (asprintf(&buffer, "%ld", brightness) < 0) {
119 ret = write(fd, buffer, strlen(buffer));
125 ret = backlight_get_brightness(backlight);
126 backlight->brightness = ret;
136 void backlight_destroy(struct backlight *backlight)
142 free(backlight->path);
147 struct backlight *backlight_init(struct udev_device *drm_device,
148 uint32_t connector_type)
150 const char *syspath = NULL;
151 char *pci_name = NULL;
152 char *chosen_path = NULL;
155 struct dirent *entry;
156 enum backlight_type type = 0;
158 struct backlight *backlight;
164 syspath = udev_device_get_syspath(drm_device);
168 if (asprintf(&path, "%s/%s", syspath, "device") < 0)
171 ret = readlink(path, buffer, sizeof(buffer) - 1);
177 pci_name = basename(buffer);
179 if (connector_type <= 0)
182 backlights = opendir("/sys/class/backlight");
186 /* Find the "best" backlight for the device. Firmware
187 interfaces are preferred over platform interfaces are
188 preferred over raw interfaces. For raw interfaces we'll
189 check if the device ID in the form of pci match, while
190 for firmware interfaces we require the pci ID to
191 match. It's assumed that platform interfaces always match,
192 since we can't actually associate them with IDs.
194 A further awkwardness is that, while it's theoretically
195 possible for an ACPI interface to include support for
196 changing the backlight of external devices, it's unlikely
197 to ever be done. It's effectively impossible for a platform
198 interface to do so. So if we get asked about anything that
199 isn't LVDS or eDP, we pretty much have to require that the
200 control be supplied via a raw interface */
202 while ((entry = readdir(backlights))) {
203 char *backlight_path;
205 enum backlight_type entry_type;
208 if (entry->d_name[0] == '.')
211 if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
215 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
218 fd = open(path, O_RDONLY);
223 ret = read (fd, &buffer, sizeof(buffer));
231 if (!strncmp(buffer, "raw\n", sizeof(buffer)))
232 entry_type = BACKLIGHT_RAW;
233 else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
234 entry_type = BACKLIGHT_PLATFORM;
235 else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
236 entry_type = BACKLIGHT_FIRMWARE;
240 if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
241 connector_type != DRM_MODE_CONNECTOR_eDP) {
242 /* External displays are assumed to require
243 gpu control at the moment */
244 if (entry_type != BACKLIGHT_RAW)
250 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
253 ret = readlink(path, buffer, sizeof(buffer) - 1);
260 parent = basename(buffer);
262 /* Perform matching for raw and firmware backlights -
263 platform backlights have to be assumed to match */
264 if (entry_type == BACKLIGHT_RAW ||
265 entry_type == BACKLIGHT_FIRMWARE) {
266 if (!(pci_name && !strcmp(pci_name, parent)))
270 if (entry_type < type)
277 chosen_path = strdup(backlight_path);
280 free(backlight_path);
287 backlight = malloc(sizeof(struct backlight));
292 backlight->path = chosen_path;
293 backlight->type = type;
295 backlight->max_brightness = backlight_get_max_brightness(backlight);
296 if (backlight->max_brightness < 0)
299 backlight->brightness = backlight_get_actual_brightness(backlight);
300 if (backlight->brightness < 0)