compositor-drm: Work around page flip not setting tiling mode on BYT
[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 #include "config.h"
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         fd = open(path, O_RDONLY);
56         if (fd < 0) {
57                 ret = -1;
58                 goto out;
59         }
60
61         ret = read(fd, &buffer, sizeof(buffer));
62         if (ret < 1) {
63                 ret = -1;
64                 goto out;
65         }
66
67         value = strtol(buffer, NULL, 10);
68         ret = value;
69 out:
70         if (fd >= 0)
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         free(buffer);
128         free(path);
129         if (fd >= 0)
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                         free(backlight_path);
215                         goto err;
216                 }
217
218                 fd = open(path, O_RDONLY);
219
220                 if (fd < 0)
221                         goto out;
222
223                 ret = read (fd, &buffer, sizeof(buffer));
224                 close (fd);
225
226                 if (ret < 1)
227                         goto out;
228
229                 buffer[ret] = '\0';
230
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;
237                 else
238                         goto out;
239
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)
245                                 goto out;
246                 }
247
248                 free (path);
249
250                 if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
251                         goto err;
252
253                 ret = readlink(path, buffer, sizeof(buffer) - 1);
254
255                 if (ret < 0)
256                         goto out;
257
258                 buffer[ret] = '\0';
259
260                 parent = basename(buffer);
261
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)))
267                                 goto out;
268                 }
269
270                 if (entry_type < type)
271                         goto out;
272
273                 type = entry_type;
274
275                 if (chosen_path)
276                         free(chosen_path);
277                 chosen_path = strdup(backlight_path);
278
279         out:
280                 free(backlight_path);
281                 free(path);
282         }
283
284         if (!chosen_path)
285                 goto err;
286
287         backlight = malloc(sizeof(struct backlight));
288
289         if (!backlight)
290                 goto err;
291
292         backlight->path = chosen_path;
293         backlight->type = type;
294
295         backlight->max_brightness = backlight_get_max_brightness(backlight);
296         if (backlight->max_brightness < 0)
297                 goto err;
298
299         backlight->brightness = backlight_get_actual_brightness(backlight);
300         if (backlight->brightness < 0)
301                 goto err;
302
303         closedir(backlights);
304         return backlight;
305 err:
306         closedir(backlights);
307         free (chosen_path);
308         free (backlight);
309         return NULL;
310 }