diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-07-02 10:21:42 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-07-02 10:25:39 +0100 |
commit | e80f9c4670a0e84521907b1baa059322784b1558 (patch) | |
tree | 8bf6cceebda34f8d7957d93ae3ec5f4b321407a9 | |
parent | 61e16dc5673a1ac96b2ecee072cc3e80971be5d9 (diff) |
sna: Prefer backlight iface based on /sys/class/backlight/*/type
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/sna_display.c | 152 |
1 files changed, 111 insertions, 41 deletions
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 07ff607e..0d9e4741 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c | |||
@@ -34,8 +34,10 @@ | |||
34 | #include <sys/stat.h> | 34 | #include <sys/stat.h> |
35 | #include <fcntl.h> | 35 | #include <fcntl.h> |
36 | #include <unistd.h> | 36 | #include <unistd.h> |
37 | #include <dirent.h> | ||
37 | #include <errno.h> | 38 | #include <errno.h> |
38 | #include <poll.h> | 39 | #include <poll.h> |
40 | #include <ctype.h> | ||
39 | 41 | ||
40 | #include <xorgVersion.h> | 42 | #include <xorgVersion.h> |
41 | #include <X11/Xatom.h> | 43 | #include <X11/Xatom.h> |
@@ -91,7 +93,7 @@ struct sna_output { | |||
91 | int panel_vdisplay; | 93 | int panel_vdisplay; |
92 | 94 | ||
93 | int dpms_mode; | 95 | int dpms_mode; |
94 | const char *backlight_iface; | 96 | char *backlight_iface; |
95 | int backlight_active_level; | 97 | int backlight_active_level; |
96 | int backlight_max; | 98 | int backlight_max; |
97 | struct list link; | 99 | struct list link; |
@@ -104,28 +106,6 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc) | |||
104 | 106 | ||
105 | #define BACKLIGHT_CLASS "/sys/class/backlight" | 107 | #define BACKLIGHT_CLASS "/sys/class/backlight" |
106 | 108 | ||
107 | /* | ||
108 | * List of available kernel interfaces in priority order | ||
109 | */ | ||
110 | static const char *backlight_interfaces[] = { | ||
111 | "intel", /* prefer our own native backlight driver */ | ||
112 | "asus-laptop", | ||
113 | "asus-nb-wmi", | ||
114 | "eeepc", | ||
115 | "thinkpad_screen", | ||
116 | "mbp_backlight", | ||
117 | "fujitsu-laptop", | ||
118 | "sony", | ||
119 | "samsung", | ||
120 | "acpi_video1", /* finally fallback to the generic acpi drivers */ | ||
121 | "acpi_video0", | ||
122 | NULL, | ||
123 | }; | ||
124 | /* | ||
125 | * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table + | ||
126 | * '/' + "max_backlight" | ||
127 | */ | ||
128 | #define BACKLIGHT_PATH_LEN 80 | ||
129 | /* Enough for 10 digits of backlight + '\n' + '\0' */ | 109 | /* Enough for 10 digits of backlight + '\n' + '\0' */ |
130 | #define BACKLIGHT_VALUE_LEN 12 | 110 | #define BACKLIGHT_VALUE_LEN 12 |
131 | 111 | ||
@@ -219,14 +199,14 @@ static void | |||
219 | sna_output_backlight_set(xf86OutputPtr output, int level) | 199 | sna_output_backlight_set(xf86OutputPtr output, int level) |
220 | { | 200 | { |
221 | struct sna_output *sna_output = output->driver_private; | 201 | struct sna_output *sna_output = output->driver_private; |
222 | char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; | 202 | char path[1024], val[BACKLIGHT_VALUE_LEN]; |
223 | int fd, len, ret; | 203 | int fd, len, ret; |
224 | 204 | ||
225 | DBG(("%s: level=%d\n", __FUNCTION__, level)); | 205 | DBG(("%s: level=%d\n", __FUNCTION__, level)); |
226 | 206 | ||
227 | if (level > sna_output->backlight_max) | 207 | if (level > sna_output->backlight_max) |
228 | level = sna_output->backlight_max; | 208 | level = sna_output->backlight_max; |
229 | if (! sna_output->backlight_iface || level < 0) | 209 | if (!sna_output->backlight_iface || level < 0) |
230 | return; | 210 | return; |
231 | 211 | ||
232 | len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); | 212 | len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); |
@@ -252,7 +232,7 @@ static int | |||
252 | sna_output_backlight_get(xf86OutputPtr output) | 232 | sna_output_backlight_get(xf86OutputPtr output) |
253 | { | 233 | { |
254 | struct sna_output *sna_output = output->driver_private; | 234 | struct sna_output *sna_output = output->driver_private; |
255 | char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; | 235 | char path[1024], val[BACKLIGHT_VALUE_LEN]; |
256 | int fd, level; | 236 | int fd, level; |
257 | 237 | ||
258 | sprintf(path, "%s/%s/actual_brightness", | 238 | sprintf(path, "%s/%s/actual_brightness", |
@@ -287,7 +267,7 @@ static int | |||
287 | sna_output_backlight_get_max(xf86OutputPtr output) | 267 | sna_output_backlight_get_max(xf86OutputPtr output) |
288 | { | 268 | { |
289 | struct sna_output *sna_output = output->driver_private; | 269 | struct sna_output *sna_output = output->driver_private; |
290 | char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; | 270 | char path[1024], val[BACKLIGHT_VALUE_LEN]; |
291 | int fd, max = 0; | 271 | int fd, max = 0; |
292 | 272 | ||
293 | sprintf(path, "%s/%s/max_brightness", | 273 | sprintf(path, "%s/%s/max_brightness", |
@@ -313,29 +293,117 @@ sna_output_backlight_get_max(xf86OutputPtr output) | |||
313 | return max; | 293 | return max; |
314 | } | 294 | } |
315 | 295 | ||
296 | enum { | ||
297 | FIRMWARE, | ||
298 | PLATFORM, | ||
299 | RAW, | ||
300 | NAMED, | ||
301 | }; | ||
302 | |||
316 | static void | 303 | static void |
317 | sna_output_backlight_init(xf86OutputPtr output) | 304 | sna_output_backlight_init(xf86OutputPtr output) |
318 | { | 305 | { |
306 | static const char *known_interfaces[] = { | ||
307 | "asus-laptop", | ||
308 | "asus-nb-wmi", | ||
309 | "eeepc", | ||
310 | "thinkpad_screen", | ||
311 | "mbp_backlight", | ||
312 | "fujitsu-laptop", | ||
313 | "sony", | ||
314 | "samsung", | ||
315 | "acpi_video1", | ||
316 | "acpi_video0", | ||
317 | "intel_backlight", | ||
318 | }; | ||
319 | struct sna_output *sna_output = output->driver_private; | 319 | struct sna_output *sna_output = output->driver_private; |
320 | int i; | 320 | char *best_iface; |
321 | int best_type; | ||
322 | DIR *dir; | ||
323 | struct dirent *de; | ||
324 | |||
325 | best_iface = NULL; | ||
326 | best_type = INT_MAX; | ||
327 | |||
328 | dir = opendir(BACKLIGHT_CLASS); | ||
329 | while ((de = readdir(dir))) { | ||
330 | char path[1024]; | ||
331 | char buf[100]; | ||
332 | int fd, v; | ||
333 | |||
334 | snprintf(path, sizeof(path), "%s/%s/type", | ||
335 | BACKLIGHT_CLASS, de->d_name); | ||
336 | |||
337 | v = -1; | ||
338 | fd = open(path, O_RDONLY); | ||
339 | if (fd >= 0) { | ||
340 | v = read(fd, buf, sizeof(buf)-1); | ||
341 | close(fd); | ||
342 | } | ||
343 | if (v > 0) { | ||
344 | while (v > 0 && isspace(buf[v-1])) | ||
345 | v--; | ||
346 | buf[v] = '\0'; | ||
347 | |||
348 | if (strcmp(buf, "raw") == 0) | ||
349 | v = RAW; | ||
350 | else if (strcmp(buf, "platform") == 0) | ||
351 | v = PLATFORM; | ||
352 | else if (strcmp(buf, "firmware") == 0) | ||
353 | v = FIRMWARE; | ||
354 | else | ||
355 | v = NAMED; | ||
356 | } else | ||
357 | v = NAMED; | ||
358 | |||
359 | /* Fallback to priority list of known iface for old kernels */ | ||
360 | if (v == NAMED) { | ||
361 | int i; | ||
362 | for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) { | ||
363 | if (strcmp(de->d_name, known_interfaces[i]) == 0) | ||
364 | break; | ||
365 | } | ||
366 | v += i; | ||
367 | } | ||
368 | |||
369 | if (v < best_type) { | ||
370 | char *copy; | ||
371 | int max; | ||
372 | |||
373 | /* XXX detect right backlight for multi-GPU/panels */ | ||
374 | |||
375 | sna_output->backlight_iface = de->d_name; | ||
376 | max = sna_output_backlight_get_max(output); | ||
377 | if (max <= 0) | ||
378 | continue; | ||
321 | 379 | ||
322 | for (i = 0; backlight_interfaces[i] != NULL; i++) { | 380 | copy = strdup(de->d_name); |
323 | char path[BACKLIGHT_PATH_LEN]; | 381 | if (copy) { |
324 | struct stat buf; | 382 | free(best_iface); |
325 | 383 | best_iface = copy; | |
326 | sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]); | 384 | best_type = v; |
327 | if (!stat(path, &buf)) { | ||
328 | sna_output->backlight_iface = backlight_interfaces[i]; | ||
329 | sna_output->backlight_max = sna_output_backlight_get_max(output); | ||
330 | if (sna_output->backlight_max > 0) { | ||
331 | sna_output->backlight_active_level = sna_output_backlight_get(output); | ||
332 | xf86DrvMsg(output->scrn->scrnIndex, X_INFO, | ||
333 | "found backlight control interface %s\n", path); | ||
334 | return; | ||
335 | } | 385 | } |
336 | } | 386 | } |
337 | } | 387 | } |
388 | |||
338 | sna_output->backlight_iface = NULL; | 389 | sna_output->backlight_iface = NULL; |
390 | |||
391 | if (best_iface) { | ||
392 | const char *str; | ||
393 | |||
394 | sna_output->backlight_iface = best_iface; | ||
395 | sna_output->backlight_max = sna_output_backlight_get_max(output); | ||
396 | sna_output->backlight_active_level = sna_output_backlight_get(output); | ||
397 | switch (best_type) { | ||
398 | case FIRMWARE: str = "firmware"; break; | ||
399 | case PLATFORM: str = "platform"; break; | ||
400 | case RAW: str = "raw"; break; | ||
401 | default: str = "unknown"; break; | ||
402 | } | ||
403 | xf86DrvMsg(output->scrn->scrnIndex, X_INFO, | ||
404 | "found backlight control interface %s (type '%s')\n", | ||
405 | best_iface, str); | ||
406 | } | ||
339 | } | 407 | } |
340 | 408 | ||
341 | 409 | ||
@@ -1515,6 +1583,8 @@ sna_output_destroy(xf86OutputPtr output) | |||
1515 | drmModeFreeConnector(sna_output->mode_output); | 1583 | drmModeFreeConnector(sna_output->mode_output); |
1516 | sna_output->mode_output = NULL; | 1584 | sna_output->mode_output = NULL; |
1517 | 1585 | ||
1586 | free(sna_output->backlight_iface); | ||
1587 | |||
1518 | list_del(&sna_output->link); | 1588 | list_del(&sna_output->link); |
1519 | free(sna_output); | 1589 | free(sna_output); |
1520 | 1590 | ||