Update snapshot
[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 <stdlib.h>
37 #include <unistd.h>
38 #include <linux/types.h>
39 #include <dirent.h>
40 #include <drm.h>
41 #include <fcntl.h>
42 #include <malloc.h>
43 #include <string.h>
44 #include <errno.h>
45
46 static 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;
70 out:
71         close(fd);
72         free(path);
73         return ret;
74 }
75
76 long backlight_get_brightness(struct backlight *backlight)
77 {
78         return backlight_get(backlight, "brightness");
79 }
80
81 long backlight_get_max_brightness(struct backlight *backlight)
82 {
83         return backlight_get(backlight, "max_brightness");
84 }
85
86 long backlight_get_actual_brightness(struct backlight *backlight)
87 {
88         return backlight_get(backlight, "actual_brightness");
89 }
90
91 long 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
113         if (asprintf(&buffer, "%ld", brightness) < 0) {
114                 ret = -1;
115                 goto out;
116         }
117
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;
126 out:
127         if (buffer)
128                 free(buffer);
129         free(path);
130         close(fd);
131         return ret;
132 }
133
134 void 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
145 struct 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 = NULL;
153         struct dirent *entry;
154         enum backlight_type type = 0;
155         char buffer[100];
156         struct backlight *backlight = NULL;
157         int ret;
158
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
169         ret = readlink(path, buffer, sizeof(buffer) - 1);
170         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                         goto err;
212
213                 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
214                         goto err;
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                         goto err;
250
251                 ret = readlink(path, buffer, sizeof(buffer) - 1);
252
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                 goto err;
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         closedir(backlights);
302         return backlight;
303 err:
304         closedir(backlights);
305         free (chosen_path);
306         free (backlight);
307         return NULL;
308 }