blob: 2ac135a5342d6f952ae444f1c4398e60b45e89a5 [file] [log] [blame]
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -05001/*
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#define _GNU_SOURCE
33
Pekka Paalanen4ac32ab2012-03-02 17:33:17 +020034#include "libbacklight.h"
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -050035#include <stdio.h>
Pekka Paalanen4ac32ab2012-03-02 17:33:17 +020036#include <stdlib.h>
37#include <unistd.h>
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -050038#include <linux/types.h>
39#include <dirent.h>
Pekka Paalanen4ac32ab2012-03-02 17:33:17 +020040#include <drm.h>
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -050041#include <fcntl.h>
42#include <malloc.h>
43#include <string.h>
44#include <errno.h>
45
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -050046static long backlight_get(struct backlight *backlight, char *node)
47{
48 char buffer[100];
49 char *path;
50 int fd;
51 long value, ret;
52
53 if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
54 return -ENOMEM
55;
56 fd = open(path, O_RDONLY);
57 if (fd < 0) {
58 ret = -1;
59 goto out;
60 }
61
62 ret = read(fd, &buffer, sizeof(buffer));
63 if (ret < 1) {
64 ret = -1;
65 goto out;
66 }
67
68 value = strtol(buffer, NULL, 10);
69 ret = value;
70out:
71 close(fd);
Rob Bradford0b0be8e2012-12-05 18:47:06 +000072 free(path);
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -050073 return ret;
74}
75
76long backlight_get_brightness(struct backlight *backlight)
77{
78 return backlight_get(backlight, "brightness");
79}
80
81long backlight_get_max_brightness(struct backlight *backlight)
82{
83 return backlight_get(backlight, "max_brightness");
84}
85
86long backlight_get_actual_brightness(struct backlight *backlight)
87{
88 return backlight_get(backlight, "actual_brightness");
89}
90
91long backlight_set_brightness(struct backlight *backlight, long brightness)
92{
93 char *path;
94 char *buffer = NULL;
95 int fd;
96 long ret;
97
98 if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
99 return -ENOMEM;
100
101 fd = open(path, O_RDWR);
102 if (fd < 0) {
103 ret = -1;
104 goto out;
105 }
106
107 ret = read(fd, &buffer, sizeof(buffer));
108 if (ret < 1) {
109 ret = -1;
110 goto out;
111 }
112
Rob Bradforda6b63d02012-10-09 18:44:36 +0100113 if (asprintf(&buffer, "%ld", brightness) < 0) {
114 ret = -1;
115 goto out;
116 }
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -0500117
118 ret = write(fd, buffer, strlen(buffer));
119 if (ret < 0) {
120 ret = -1;
121 goto out;
122 }
123
124 ret = backlight_get_brightness(backlight);
125 backlight->brightness = ret;
126out:
127 if (buffer)
128 free(buffer);
Rob Bradford0b0be8e2012-12-05 18:47:06 +0000129 free(path);
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -0500130 close(fd);
131 return ret;
132}
133
134void backlight_destroy(struct backlight *backlight)
135{
136 if (!backlight)
137 return;
138
139 if (backlight->path)
140 free(backlight->path);
141
142 free(backlight);
143}
144
145struct backlight *backlight_init(struct udev_device *drm_device,
146 uint32_t connector_type)
147{
148 const char *syspath = NULL;
149 char *pci_name = NULL;
150 char *chosen_path = NULL;
151 char *path = NULL;
152 DIR *backlights;
153 struct dirent *entry;
154 enum backlight_type type = 0;
155 char buffer[100];
156 struct backlight *backlight;
Pekka Paalanen4ac32ab2012-03-02 17:33:17 +0200157 int ret;
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -0500158
159 if (!drm_device)
160 return NULL;
161
162 syspath = udev_device_get_syspath(drm_device);
163 if (!syspath)
164 return NULL;
165
166 if (asprintf(&path, "%s/%s", syspath, "device") < 0)
167 return NULL;
168
Rob Bradford273fec82012-10-09 18:44:33 +0100169 ret = readlink(path, buffer, sizeof(buffer) - 1);
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -0500170 free(path);
171 if (ret < 0)
172 return NULL;
173
174 buffer[ret] = '\0';
175 pci_name = basename(buffer);
176
177 if (connector_type <= 0)
178 return NULL;
179
180 backlights = opendir("/sys/class/backlight");
181 if (!backlights)
182 return NULL;
183
184 /* Find the "best" backlight for the device. Firmware
185 interfaces are preferred over platform interfaces are
186 preferred over raw interfaces. For raw interfaces we'll
187 check if the device ID in the form of pci match, while
188 for firmware interfaces we require the pci ID to
189 match. It's assumed that platform interfaces always match,
190 since we can't actually associate them with IDs.
191
192 A further awkwardness is that, while it's theoretically
193 possible for an ACPI interface to include support for
194 changing the backlight of external devices, it's unlikely
195 to ever be done. It's effectively impossible for a platform
196 interface to do so. So if we get asked about anything that
197 isn't LVDS or eDP, we pretty much have to require that the
198 control be supplied via a raw interface */
199
200 while ((entry = readdir(backlights))) {
201 char *backlight_path;
202 char *parent;
203 enum backlight_type entry_type;
204 int fd;
205
206 if (entry->d_name[0] == '.')
207 continue;
208
209 if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
210 entry->d_name) < 0)
211 return NULL;
212
213 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
214 return NULL;
215
216 fd = open(path, O_RDONLY);
217
218 if (fd < 0)
219 goto out;
220
221 ret = read (fd, &buffer, sizeof(buffer));
222 close (fd);
223
224 if (ret < 1)
225 goto out;
226
227 buffer[ret] = '\0';
228
229 if (!strncmp(buffer, "raw\n", sizeof(buffer)))
230 entry_type = BACKLIGHT_RAW;
231 else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
232 entry_type = BACKLIGHT_PLATFORM;
233 else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
234 entry_type = BACKLIGHT_FIRMWARE;
235 else
236 goto out;
237
238 if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
239 connector_type != DRM_MODE_CONNECTOR_eDP) {
240 /* External displays are assumed to require
241 gpu control at the moment */
242 if (entry_type != BACKLIGHT_RAW)
243 goto out;
244 }
245
246 free (path);
247
248 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
249 return NULL;
250
Rob Bradford273fec82012-10-09 18:44:33 +0100251 ret = readlink(path, buffer, sizeof(buffer) - 1);
Kristian Høgsberg51cba3c2012-02-29 14:23:51 -0500252
253 if (ret < 0)
254 goto out;
255
256 buffer[ret] = '\0';
257
258 parent = basename(buffer);
259
260 /* Perform matching for raw and firmware backlights -
261 platform backlights have to be assumed to match */
262 if (entry_type == BACKLIGHT_RAW ||
263 entry_type == BACKLIGHT_FIRMWARE) {
264 if (!(pci_name && !strcmp(pci_name, parent)))
265 goto out;
266 }
267
268 if (entry_type < type)
269 goto out;
270
271 type = entry_type;
272
273 if (chosen_path)
274 free(chosen_path);
275 chosen_path = strdup(backlight_path);
276
277 out:
278 free(backlight_path);
279 free(path);
280 }
281
282 if (!chosen_path)
283 return NULL;
284
285 backlight = malloc(sizeof(struct backlight));
286
287 if (!backlight)
288 goto err;
289
290 backlight->path = chosen_path;
291 backlight->type = type;
292
293 backlight->max_brightness = backlight_get_max_brightness(backlight);
294 if (backlight->max_brightness < 0)
295 goto err;
296
297 backlight->brightness = backlight_get_actual_brightness(backlight);
298 if (backlight->brightness < 0)
299 goto err;
300
301 return backlight;
302err:
303 if (chosen_path)
304 free(chosen_path);
305 free (backlight);
306 return NULL;
307}