compositor-drm: Just pull in libbacklight source for now
[profile/ivi/weston.git] / src / libbacklight.c
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 #define _GNU_SOURCE
33
34 #include <libbacklight.h>
35 #include <stdio.h>
36 #include <linux/types.h>
37 #include <dirent.h>
38 #include <drm/drm_mode.h>
39 #include <fcntl.h>
40 #include <malloc.h>
41 #include <string.h>
42 #include <errno.h>
43
44 static const char *output_names[] = { "Unknown",
45                                       "VGA",
46                                       "DVI-I",
47                                       "DVI-D",
48                                       "DVI-A",
49                                       "Composite",
50                                       "SVIDEO",
51                                       "LVDS",
52                                       "Component",
53                                       "9-pin DIN",
54                                       "DisplayPort"
55                                       "HDMI Type A",
56                                       "HDMI Type B",
57                                       "TV",
58                                       "Embedded DisplayPort"
59 };
60
61 static long backlight_get(struct backlight *backlight, char *node)
62 {
63         char buffer[100];
64         char *path;
65         int fd;
66         long value, ret;
67
68         if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
69                 return -ENOMEM
70 ;
71         fd = open(path, O_RDONLY);
72         if (fd < 0) {
73                 ret = -1;
74                 goto out;
75         }
76
77         ret = read(fd, &buffer, sizeof(buffer));
78         if (ret < 1) {
79                 ret = -1;
80                 goto out;
81         }
82
83         value = strtol(buffer, NULL, 10);
84         ret = value;
85 out:
86         close(fd);
87         if (path)
88                 free(path);
89         return ret;
90 }
91
92 long backlight_get_brightness(struct backlight *backlight)
93 {
94         return backlight_get(backlight, "brightness");
95 }
96
97 long backlight_get_max_brightness(struct backlight *backlight)
98 {
99         return backlight_get(backlight, "max_brightness");
100 }
101
102 long backlight_get_actual_brightness(struct backlight *backlight)
103 {
104         return backlight_get(backlight, "actual_brightness");
105 }
106
107 long backlight_set_brightness(struct backlight *backlight, long brightness)
108 {
109         char *path;
110         char *buffer = NULL;
111         int fd;
112         long ret;
113
114         if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
115                 return -ENOMEM;
116
117         fd = open(path, O_RDWR);
118         if (fd < 0) {
119                 ret = -1;
120                 goto out;
121         }
122
123         ret = read(fd, &buffer, sizeof(buffer));
124         if (ret < 1) {
125                 ret = -1;
126                 goto out;
127         }
128
129         if (asprintf(&buffer, "%ld", brightness) < 0)
130                 return -ENOMEM;
131
132         ret = write(fd, buffer, strlen(buffer));
133         if (ret < 0) {
134                 ret = -1;
135                 goto out;
136         }
137
138         ret = backlight_get_brightness(backlight);
139         backlight->brightness = ret;
140 out:
141         if (buffer)
142                 free(buffer);
143         if (path)
144                 free(path);
145         close(fd);
146         return ret;
147 }
148
149 void backlight_destroy(struct backlight *backlight)
150 {
151         if (!backlight)
152                 return;
153
154         if (backlight->path)
155                 free(backlight->path);
156
157         free(backlight);
158 }
159
160 struct backlight *backlight_init(struct udev_device *drm_device,
161                                  uint32_t connector_type)
162 {
163         const char *syspath = NULL;
164         char *pci_name = NULL;
165         char *chosen_path = NULL;
166         char *path = NULL;
167         DIR *backlights;
168         struct dirent *entry;
169         enum backlight_type type = 0;
170         char buffer[100];
171         struct backlight *backlight;
172         int err, ret;
173
174         if (!drm_device)
175                 return NULL;
176
177         syspath = udev_device_get_syspath(drm_device);
178         if (!syspath)
179                 return NULL;
180
181         if (asprintf(&path, "%s/%s", syspath, "device") < 0)
182                 return NULL;
183
184         ret = readlink(path, buffer, sizeof(buffer));
185         free(path);
186         if (ret < 0)
187                 return NULL;
188
189         buffer[ret] = '\0';
190         pci_name = basename(buffer);
191
192         if (connector_type <= 0)
193                 return NULL;
194
195         backlights = opendir("/sys/class/backlight");
196         if (!backlights)
197                 return NULL;
198
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.
206
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 */
214
215         while ((entry = readdir(backlights))) {
216                 char *backlight_path;
217                 char *parent;
218                 enum backlight_type entry_type;
219                 int fd;
220
221                 if (entry->d_name[0] == '.')
222                         continue;
223
224                 if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
225                              entry->d_name) < 0)
226                         return NULL;
227
228                 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
229                         return NULL;
230
231                 fd = open(path, O_RDONLY);
232
233                 if (fd < 0)
234                         goto out;
235
236                 ret = read (fd, &buffer, sizeof(buffer));
237                 close (fd);
238
239                 if (ret < 1)
240                         goto out;
241
242                 buffer[ret] = '\0';
243
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;
250                 else
251                         goto out;
252
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)
258                                 goto out;
259                 }
260
261                 free (path);
262
263                 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
264                         return NULL;
265
266                 ret = readlink(path, buffer, sizeof(buffer));
267
268                 if (ret < 0)
269                         goto out;
270
271                 buffer[ret] = '\0';
272
273                 parent = basename(buffer);
274
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)))
280                                 goto out;
281                 }
282
283                 if (entry_type < type)
284                         goto out;
285
286                 type = entry_type;
287
288                 if (chosen_path)
289                         free(chosen_path);
290                 chosen_path = strdup(backlight_path);
291
292         out:
293                 free(backlight_path);
294                 free(path);
295         }
296
297         if (!chosen_path)
298                 return NULL;
299
300         backlight = malloc(sizeof(struct backlight));
301
302         if (!backlight)
303                 goto err;
304
305         backlight->path = chosen_path;
306         backlight->type = type;
307
308         backlight->max_brightness = backlight_get_max_brightness(backlight);
309         if (backlight->max_brightness < 0)
310                 goto err;
311
312         backlight->brightness = backlight_get_actual_brightness(backlight);
313         if (backlight->brightness < 0)
314                 goto err;
315
316         return backlight;
317 err:
318         if (chosen_path)
319                 free(chosen_path);
320         free (backlight);
321         return NULL;
322 }