input: Rename wl_pointer to weston_pointer
[platform/upstream/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         if (fd >= 0)
72                 close(fd);
73         free(path);
74         return ret;
75 }
76
77 long backlight_get_brightness(struct backlight *backlight)
78 {
79         return backlight_get(backlight, "brightness");
80 }
81
82 long backlight_get_max_brightness(struct backlight *backlight)
83 {
84         return backlight_get(backlight, "max_brightness");
85 }
86
87 long backlight_get_actual_brightness(struct backlight *backlight)
88 {
89         return backlight_get(backlight, "actual_brightness");
90 }
91
92 long backlight_set_brightness(struct backlight *backlight, long brightness)
93 {
94         char *path;
95         char *buffer = NULL;
96         int fd;
97         long ret;
98
99         if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
100                 return -ENOMEM;
101
102         fd = open(path, O_RDWR);
103         if (fd < 0) {
104                 ret = -1;
105                 goto out;
106         }
107
108         ret = read(fd, &buffer, sizeof(buffer));
109         if (ret < 1) {
110                 ret = -1;
111                 goto out;
112         }
113
114         if (asprintf(&buffer, "%ld", brightness) < 0) {
115                 ret = -1;
116                 goto out;
117         }
118
119         ret = write(fd, buffer, strlen(buffer));
120         if (ret < 0) {
121                 ret = -1;
122                 goto out;
123         }
124
125         ret = backlight_get_brightness(backlight);
126         backlight->brightness = ret;
127 out:
128         free(buffer);
129         free(path);
130         if (fd >= 0)
131                 close(fd);
132         return ret;
133 }
134
135 void backlight_destroy(struct backlight *backlight)
136 {
137         if (!backlight)
138                 return;
139
140         if (backlight->path)
141                 free(backlight->path);
142
143         free(backlight);
144 }
145
146 struct backlight *backlight_init(struct udev_device *drm_device,
147                                  uint32_t connector_type)
148 {
149         const char *syspath = NULL;
150         char *pci_name = NULL;
151         char *chosen_path = NULL;
152         char *path = NULL;
153         DIR *backlights = NULL;
154         struct dirent *entry;
155         enum backlight_type type = 0;
156         char buffer[100];
157         struct backlight *backlight = NULL;
158         int ret;
159
160         if (!drm_device)
161                 return NULL;
162
163         syspath = udev_device_get_syspath(drm_device);
164         if (!syspath)
165                 return NULL;
166
167         if (asprintf(&path, "%s/%s", syspath, "device") < 0)
168                 return NULL;
169
170         ret = readlink(path, buffer, sizeof(buffer) - 1);
171         free(path);
172         if (ret < 0)
173                 return NULL;
174
175         buffer[ret] = '\0';
176         pci_name = basename(buffer);
177
178         if (connector_type <= 0)
179                 return NULL;
180
181         backlights = opendir("/sys/class/backlight");
182         if (!backlights)
183                 return NULL;
184
185         /* Find the "best" backlight for the device. Firmware
186            interfaces are preferred over platform interfaces are
187            preferred over raw interfaces. For raw interfaces we'll
188            check if the device ID in the form of pci match, while
189            for firmware interfaces we require the pci ID to
190            match. It's assumed that platform interfaces always match,
191            since we can't actually associate them with IDs.
192
193            A further awkwardness is that, while it's theoretically
194            possible for an ACPI interface to include support for
195            changing the backlight of external devices, it's unlikely
196            to ever be done. It's effectively impossible for a platform
197            interface to do so. So if we get asked about anything that
198            isn't LVDS or eDP, we pretty much have to require that the
199            control be supplied via a raw interface */
200
201         while ((entry = readdir(backlights))) {
202                 char *backlight_path;
203                 char *parent;
204                 enum backlight_type entry_type;
205                 int fd;
206
207                 if (entry->d_name[0] == '.')
208                         continue;
209
210                 if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
211                              entry->d_name) < 0)
212                         goto err;
213
214                 if (asprintf(&path, "%s/%s", backlight_path, "type") < 0)
215                         goto err;
216
217                 fd = open(path, O_RDONLY);
218
219                 if (fd < 0)
220                         goto out;
221
222                 ret = read (fd, &buffer, sizeof(buffer));
223                 close (fd);
224
225                 if (ret < 1)
226                         goto out;
227
228                 buffer[ret] = '\0';
229
230                 if (!strncmp(buffer, "raw\n", sizeof(buffer)))
231                         entry_type = BACKLIGHT_RAW;
232                 else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
233                         entry_type = BACKLIGHT_PLATFORM;
234                 else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
235                         entry_type = BACKLIGHT_FIRMWARE;
236                 else
237                         goto out;
238
239                 if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
240                     connector_type != DRM_MODE_CONNECTOR_eDP) {
241                         /* External displays are assumed to require
242                            gpu control at the moment */
243                         if (entry_type != BACKLIGHT_RAW)
244                                 goto out;
245                 }
246
247                 free (path);
248
249                 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
250                         goto err;
251
252                 ret = readlink(path, buffer, sizeof(buffer) - 1);
253
254                 if (ret < 0)
255                         goto out;
256
257                 buffer[ret] = '\0';
258
259                 parent = basename(buffer);
260
261                 /* Perform matching for raw and firmware backlights - 
262                    platform backlights have to be assumed to match */
263                 if (entry_type == BACKLIGHT_RAW ||
264                     entry_type == BACKLIGHT_FIRMWARE) {
265                         if (!(pci_name && !strcmp(pci_name, parent)))
266                                 goto out;
267                 }
268
269                 if (entry_type < type)
270                         goto out;
271
272                 type = entry_type;
273
274                 if (chosen_path)
275                         free(chosen_path);
276                 chosen_path = strdup(backlight_path);
277
278         out:
279                 free(backlight_path);
280                 free(path);
281         }
282
283         if (!chosen_path)
284                 goto err;
285
286         backlight = malloc(sizeof(struct backlight));
287
288         if (!backlight)
289                 goto err;
290
291         backlight->path = chosen_path;
292         backlight->type = type;
293
294         backlight->max_brightness = backlight_get_max_brightness(backlight);
295         if (backlight->max_brightness < 0)
296                 goto err;
297
298         backlight->brightness = backlight_get_actual_brightness(backlight);
299         if (backlight->brightness < 0)
300                 goto err;
301
302         closedir(backlights);
303         return backlight;
304 err:
305         closedir(backlights);
306         free (chosen_path);
307         free (backlight);
308         return NULL;
309 }