1428d7b3dSmrg/*************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrg Copyright 2014 Intel Corporation. All Rights Reserved. 4428d7b3dSmrg Copyright 2014 Red Hat, Inc. 5428d7b3dSmrg 6428d7b3dSmrg Permission is hereby granted, free of charge, to any person obtaining a 7428d7b3dSmrg copy of this software and associated documentation files (the 8428d7b3dSmrg "Software"), to deal in the Software without restriction, including 9428d7b3dSmrg without limitation the rights to use, copy, modify, merge, publish, 10428d7b3dSmrg distribute, sub license, and/or sell copies of the Software, and to 11428d7b3dSmrg permit persons to whom the Software is furnished to do so, subject to 12428d7b3dSmrg the following conditions: 13428d7b3dSmrg 14428d7b3dSmrg The above copyright notice and this permission notice (including the 15428d7b3dSmrg next paragraph) shall be included in all copies or substantial portions 16428d7b3dSmrg of the Software. 17428d7b3dSmrg 18428d7b3dSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19428d7b3dSmrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20428d7b3dSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21428d7b3dSmrg IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 22428d7b3dSmrg DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23428d7b3dSmrg OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 24428d7b3dSmrg THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25428d7b3dSmrg 26428d7b3dSmrg **************************************************************************/ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg#include <sys/types.h> 33428d7b3dSmrg#include <sys/wait.h> 34428d7b3dSmrg#include <sys/stat.h> 35428d7b3dSmrg#include <sys/ioctl.h> 36428d7b3dSmrg 37428d7b3dSmrg#include <stdio.h> 38428d7b3dSmrg#include <stdlib.h> 39428d7b3dSmrg#include <string.h> 40428d7b3dSmrg#include <ctype.h> 41428d7b3dSmrg#include <limits.h> 42428d7b3dSmrg#include <fcntl.h> 43428d7b3dSmrg#include <unistd.h> 44428d7b3dSmrg#include <dirent.h> 45428d7b3dSmrg 46428d7b3dSmrg#include <xorg-server.h> 47428d7b3dSmrg#include <xf86.h> 48428d7b3dSmrg#include <pciaccess.h> 49428d7b3dSmrg 50428d7b3dSmrg#include "backlight.h" 51428d7b3dSmrg#include "fd.h" 52428d7b3dSmrg 53428d7b3dSmrg#define BACKLIGHT_CLASS "/sys/class/backlight" 54428d7b3dSmrg 55428d7b3dSmrg/* Enough for 10 digits of backlight + '\n' + '\0' */ 56428d7b3dSmrg#define BACKLIGHT_VALUE_LEN 12 57428d7b3dSmrg 58428d7b3dSmrg#ifndef ARRAY_SIZE 59428d7b3dSmrg#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) 60428d7b3dSmrg#endif 61428d7b3dSmrg 62428d7b3dSmrg/* 63428d7b3dSmrg * Unfortunately this is not as simple as I would like it to be. If selinux is 64428d7b3dSmrg * dropping dbus messages pkexec may block *forever*. 65428d7b3dSmrg * 66428d7b3dSmrg * Backgrounding pkexec by doing System("pkexec ...&") does not work because 67428d7b3dSmrg * that detaches pkexec from its parent at which point its security checks 68428d7b3dSmrg * fail and it refuses to execute the helper. 69428d7b3dSmrg * 70428d7b3dSmrg * So we're left with spawning a helper child which gets levels to set written 71428d7b3dSmrg * to it through a pipe. This turns the blocking forever problem from a hung 72428d7b3dSmrg * machine problem into a simple backlight control not working problem. 73428d7b3dSmrg * 74428d7b3dSmrg * If only things were as simple as on OpenBSD! :) 75428d7b3dSmrg */ 76428d7b3dSmrg 77428d7b3dSmrgvoid backlight_init(struct backlight *b) 78428d7b3dSmrg{ 79428d7b3dSmrg b->type = BL_NONE; 80428d7b3dSmrg b->iface = NULL; 81428d7b3dSmrg b->fd = -1; 82428d7b3dSmrg b->pid = -1; 83428d7b3dSmrg b->max = -1; 84428d7b3dSmrg b->has_power = 0; 85428d7b3dSmrg} 86428d7b3dSmrg 87428d7b3dSmrg#if defined(__OpenBSD__) || defined(__NetBSD__) 88428d7b3dSmrg 89428d7b3dSmrg#include <dev/wscons/wsconsio.h> 90428d7b3dSmrg#include <xf86Priv.h> 91428d7b3dSmrg 92428d7b3dSmrgint backlight_set(struct backlight *b, int level) 93428d7b3dSmrg{ 94428d7b3dSmrg struct wsdisplay_param param; 95428d7b3dSmrg 96428d7b3dSmrg if (b->iface == NULL) 97428d7b3dSmrg return -1; 98428d7b3dSmrg 99428d7b3dSmrg if ((unsigned)level > b->max) 100428d7b3dSmrg level = b->max; 101428d7b3dSmrg 102428d7b3dSmrg memset(¶m, 0, sizeof(param)); 103428d7b3dSmrg param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 104428d7b3dSmrg param.curval = level; 105428d7b3dSmrg 106428d7b3dSmrg return ioctl(xf86Info.consoleFd, WSDISPLAYIO_SETPARAM, ¶m); 107428d7b3dSmrg} 108428d7b3dSmrg 109428d7b3dSmrgint backlight_get(struct backlight *b) 110428d7b3dSmrg{ 111428d7b3dSmrg struct wsdisplay_param param; 112428d7b3dSmrg 113428d7b3dSmrg if (b->iface == NULL) 114428d7b3dSmrg return -1; 115428d7b3dSmrg 116428d7b3dSmrg memset(¶m, 0, sizeof(param)); 117428d7b3dSmrg param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 118428d7b3dSmrg 119428d7b3dSmrg if (ioctl(xf86Info.consoleFd, WSDISPLAYIO_GETPARAM, ¶m)) 120428d7b3dSmrg return -1; 121428d7b3dSmrg 122428d7b3dSmrg return param.curval; 123428d7b3dSmrg} 124428d7b3dSmrg 125428d7b3dSmrgint backlight_open(struct backlight *b, char *iface) 126428d7b3dSmrg{ 127428d7b3dSmrg struct wsdisplay_param param; 128428d7b3dSmrg 129428d7b3dSmrg if (iface != NULL) 130428d7b3dSmrg return -1; 131428d7b3dSmrg 132428d7b3dSmrg memset(¶m, 0, sizeof(param)); 133428d7b3dSmrg param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 134428d7b3dSmrg 135428d7b3dSmrg if (ioctl(xf86Info.consoleFd, WSDISPLAYIO_GETPARAM, ¶m) == -1) 136428d7b3dSmrg return -1; 137428d7b3dSmrg 138428d7b3dSmrg b->iface = strdup("wscons"); 139428d7b3dSmrg if (b->iface == NULL) 140428d7b3dSmrg return -1; 141428d7b3dSmrg 142428d7b3dSmrg b->max = param.max; 143428d7b3dSmrg b->fd = -1; 144428d7b3dSmrg b->type = BL_PLATFORM; 145428d7b3dSmrg 146428d7b3dSmrg return param.curval; 147428d7b3dSmrg} 148428d7b3dSmrg 149428d7b3dSmrgenum backlight_type backlight_exists(const char *iface) 150428d7b3dSmrg{ 151428d7b3dSmrg if (iface != NULL) 152428d7b3dSmrg return BL_NONE; 153428d7b3dSmrg 154428d7b3dSmrg return BL_PLATFORM; 155428d7b3dSmrg} 156428d7b3dSmrg 157428d7b3dSmrgint backlight_on(struct backlight *b) 158428d7b3dSmrg{ 159428d7b3dSmrg return 0; 160428d7b3dSmrg} 161428d7b3dSmrg 162428d7b3dSmrgint backlight_off(struct backlight *b) 163428d7b3dSmrg{ 164428d7b3dSmrg return 0; 165428d7b3dSmrg} 166428d7b3dSmrg#else 167428d7b3dSmrg 168428d7b3dSmrgstatic int 169428d7b3dSmrgis_sysfs_fd(int fd) 170428d7b3dSmrg{ 171428d7b3dSmrg struct stat st; 172428d7b3dSmrg return fstat(fd, &st) == 0 && major(st.st_dev) == 0; 173428d7b3dSmrg} 174428d7b3dSmrg 175428d7b3dSmrgstatic int 176428d7b3dSmrg__backlight_open(const char *iface, const char *file, int mode) 177428d7b3dSmrg{ 178428d7b3dSmrg char buf[1024]; 179428d7b3dSmrg int fd; 180428d7b3dSmrg 181428d7b3dSmrg snprintf(buf, sizeof(buf), BACKLIGHT_CLASS "/%s/%s", iface, file); 182428d7b3dSmrg fd = open(buf, mode); 183428d7b3dSmrg if (fd == -1) 184428d7b3dSmrg return -1; 185428d7b3dSmrg 186428d7b3dSmrg if (!is_sysfs_fd(fd)) { 187428d7b3dSmrg close(fd); 188428d7b3dSmrg return -1; 189428d7b3dSmrg } 190428d7b3dSmrg 191428d7b3dSmrg return fd; 192428d7b3dSmrg} 193428d7b3dSmrg 194428d7b3dSmrgstatic int 195428d7b3dSmrg__backlight_read(const char *iface, const char *file) 196428d7b3dSmrg{ 197428d7b3dSmrg char buf[BACKLIGHT_VALUE_LEN]; 198428d7b3dSmrg int fd, val; 199428d7b3dSmrg 200428d7b3dSmrg fd = __backlight_open(iface, file, O_RDONLY); 201428d7b3dSmrg if (fd < 0) 202428d7b3dSmrg return -1; 203428d7b3dSmrg 204428d7b3dSmrg val = read(fd, buf, BACKLIGHT_VALUE_LEN - 1); 205428d7b3dSmrg if (val > 0) { 206428d7b3dSmrg buf[val] = '\0'; 207428d7b3dSmrg val = atoi(buf); 208428d7b3dSmrg } else 209428d7b3dSmrg val = -1; 210428d7b3dSmrg close(fd); 211428d7b3dSmrg 212428d7b3dSmrg return val; 213428d7b3dSmrg} 214428d7b3dSmrg 215428d7b3dSmrgstatic int 216428d7b3dSmrg__backlight_write(const char *iface, const char *file, const char *value) 217428d7b3dSmrg{ 218428d7b3dSmrg int fd, ret; 219428d7b3dSmrg 220428d7b3dSmrg fd = __backlight_open(iface, file, O_WRONLY); 221428d7b3dSmrg if (fd < 0) 222428d7b3dSmrg return -1; 223428d7b3dSmrg 224428d7b3dSmrg ret = write(fd, value, strlen(value)+1); 225428d7b3dSmrg close(fd); 226428d7b3dSmrg 227428d7b3dSmrg return ret; 228428d7b3dSmrg} 229428d7b3dSmrg 230428d7b3dSmrg/* List of available kernel interfaces in priority order */ 231428d7b3dSmrgstatic const char *known_interfaces[] = { 232428d7b3dSmrg "dell_backlight", 233428d7b3dSmrg "gmux_backlight", 234428d7b3dSmrg "asus-laptop", 235428d7b3dSmrg "asus-nb-wmi", 236428d7b3dSmrg "eeepc", 237428d7b3dSmrg "thinkpad_screen", 238428d7b3dSmrg "mbp_backlight", 239428d7b3dSmrg "fujitsu-laptop", 240428d7b3dSmrg "sony", 241428d7b3dSmrg "samsung", 242428d7b3dSmrg "acpi_video1", 243428d7b3dSmrg "acpi_video0", 244428d7b3dSmrg "intel_backlight", 245428d7b3dSmrg}; 246428d7b3dSmrg 247428d7b3dSmrgstatic enum backlight_type __backlight_type(const char *iface) 248428d7b3dSmrg{ 249428d7b3dSmrg char buf[1024]; 250428d7b3dSmrg int fd, v; 251428d7b3dSmrg 252428d7b3dSmrg v = -1; 253428d7b3dSmrg fd = __backlight_open(iface, "type", O_RDONLY); 254428d7b3dSmrg if (fd >= 0) { 255428d7b3dSmrg v = read(fd, buf, sizeof(buf)-1); 256428d7b3dSmrg close(fd); 257428d7b3dSmrg } 258428d7b3dSmrg if (v > 0) { 259428d7b3dSmrg while (v > 0 && isspace(buf[v-1])) 260428d7b3dSmrg v--; 261428d7b3dSmrg buf[v] = '\0'; 262428d7b3dSmrg 263428d7b3dSmrg if (strcmp(buf, "raw") == 0) 264428d7b3dSmrg v = BL_RAW; 265428d7b3dSmrg else if (strcmp(buf, "platform") == 0) 266428d7b3dSmrg v = BL_PLATFORM; 267428d7b3dSmrg else if (strcmp(buf, "firmware") == 0) 268428d7b3dSmrg v = BL_FIRMWARE; 269428d7b3dSmrg else 270428d7b3dSmrg v = BL_NAMED; 271428d7b3dSmrg } else 272428d7b3dSmrg v = BL_NAMED; 273428d7b3dSmrg 274428d7b3dSmrg if (v == BL_NAMED) { 275428d7b3dSmrg int i; 276428d7b3dSmrg for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) { 277428d7b3dSmrg if (strcmp(iface, known_interfaces[i]) == 0) 278428d7b3dSmrg break; 279428d7b3dSmrg } 280428d7b3dSmrg v += i; 281428d7b3dSmrg } 282428d7b3dSmrg 283428d7b3dSmrg return v; 284428d7b3dSmrg} 285428d7b3dSmrg 286428d7b3dSmrgenum backlight_type backlight_exists(const char *iface) 287428d7b3dSmrg{ 288428d7b3dSmrg if (__backlight_read(iface, "brightness") < 0) 289428d7b3dSmrg return BL_NONE; 290428d7b3dSmrg 291428d7b3dSmrg if (__backlight_read(iface, "max_brightness") <= 0) 292428d7b3dSmrg return BL_NONE; 293428d7b3dSmrg 294428d7b3dSmrg return __backlight_type(iface); 295428d7b3dSmrg} 296428d7b3dSmrg 297428d7b3dSmrgstatic int __backlight_init(struct backlight *b, char *iface, int fd) 298428d7b3dSmrg{ 299428d7b3dSmrg b->fd = fd_move_cloexec(fd_set_nonblock(fd)); 300428d7b3dSmrg b->iface = iface; 301428d7b3dSmrg return 1; 302428d7b3dSmrg} 303428d7b3dSmrg 304428d7b3dSmrgstatic int __backlight_direct_init(struct backlight *b, char *iface) 305428d7b3dSmrg{ 306428d7b3dSmrg int fd; 307428d7b3dSmrg 308428d7b3dSmrg fd = __backlight_open(iface, "brightness", O_RDWR); 309428d7b3dSmrg if (fd < 0) 310428d7b3dSmrg return 0; 311428d7b3dSmrg 312428d7b3dSmrg if (__backlight_read(iface, "bl_power") != -1) 313428d7b3dSmrg b->has_power = 1; 314428d7b3dSmrg 315428d7b3dSmrg return __backlight_init(b, iface, fd); 316428d7b3dSmrg} 317428d7b3dSmrg 318428d7b3dSmrgstatic int __backlight_helper_init(struct backlight *b, char *iface) 319428d7b3dSmrg{ 320428d7b3dSmrg#if USE_BACKLIGHT_HELPER 321428d7b3dSmrg struct stat st; 322428d7b3dSmrg char *env[] = { NULL }; 323428d7b3dSmrg int use_pkexec = 0; 324428d7b3dSmrg int fds[2]; 325428d7b3dSmrg 326428d7b3dSmrg /* 327428d7b3dSmrg * Some systems may prefer using PolicyKit's pkexec over 328428d7b3dSmrg * making the helper suid root, since the suid option will allow 329428d7b3dSmrg * anyone to control the backlight. However, as pkexec 330428d7b3dSmrg * is quite troublesome and not universally available, we 331428d7b3dSmrg * still try the old fashioned and simple method first. 332428d7b3dSmrg * Either way, we have to trust that it is our backlight-helper 333428d7b3dSmrg * that is run and that we have scrutinised it carefully. 334428d7b3dSmrg */ 335428d7b3dSmrg if (stat(LIBEXEC_PATH "/xf86-video-intel-backlight-helper", &st)) 336428d7b3dSmrg return 0; 337428d7b3dSmrg 338428d7b3dSmrg if ((st.st_mode & (S_IFREG | S_ISUID | S_IXUSR)) != (S_IFREG | S_ISUID | S_IXUSR)) { 339428d7b3dSmrg if (System("pkexec --version")) 340428d7b3dSmrg return 0; 341428d7b3dSmrg 342428d7b3dSmrg use_pkexec = 1; 343428d7b3dSmrg } 344428d7b3dSmrg 345428d7b3dSmrg if (pipe(fds)) 346428d7b3dSmrg return 0; 347428d7b3dSmrg 348428d7b3dSmrg switch ((b->pid = fork())) { 349428d7b3dSmrg case 0: 350428d7b3dSmrg if (setgid(getgid()) || setuid(getuid())) 351428d7b3dSmrg _exit(127); 352428d7b3dSmrg 353428d7b3dSmrg close(fds[1]); 354428d7b3dSmrg if (dup2(fds[0], 0)) 355428d7b3dSmrg _exit(127); 356428d7b3dSmrg close(fds[0]); 357428d7b3dSmrg 358428d7b3dSmrg if (use_pkexec) { 359428d7b3dSmrg execlp("pkexec", "pkexec", 360428d7b3dSmrg LIBEXEC_PATH "/xf86-video-intel-backlight-helper", 361428d7b3dSmrg iface, (char *)0); 362428d7b3dSmrg } else { 363428d7b3dSmrg execle(LIBEXEC_PATH "/xf86-video-intel-backlight-helper", 364428d7b3dSmrg "xf86-video-intel-backlight-helper", 365428d7b3dSmrg iface, (char *)0, env); 366428d7b3dSmrg } 367428d7b3dSmrg _exit(1); 368428d7b3dSmrg /* unreachable fallthrough */ 369428d7b3dSmrg case -1: 370428d7b3dSmrg close(fds[1]); 371428d7b3dSmrg close(fds[0]); 372428d7b3dSmrg return 0; 373428d7b3dSmrg 374428d7b3dSmrg default: 375428d7b3dSmrg close(fds[0]); 376428d7b3dSmrg return __backlight_init(b, iface, fds[1]); 377428d7b3dSmrg } 378428d7b3dSmrg#else 379428d7b3dSmrg return 0; 380428d7b3dSmrg#endif 381428d7b3dSmrg} 382428d7b3dSmrg 383428d7b3dSmrgstatic char * 384428d7b3dSmrg__backlight_find(void) 385428d7b3dSmrg{ 386428d7b3dSmrg char *best_iface = NULL; 387428d7b3dSmrg unsigned best_type = INT_MAX; 388428d7b3dSmrg DIR *dir; 389428d7b3dSmrg struct dirent *de; 390428d7b3dSmrg 391428d7b3dSmrg dir = opendir(BACKLIGHT_CLASS); 392428d7b3dSmrg if (dir == NULL) 393428d7b3dSmrg return NULL; 394428d7b3dSmrg 395428d7b3dSmrg while ((de = readdir(dir))) { 396428d7b3dSmrg int v; 397428d7b3dSmrg 398428d7b3dSmrg if (*de->d_name == '.') 399428d7b3dSmrg continue; 400428d7b3dSmrg 401428d7b3dSmrg /* Fallback to priority list of known iface for old kernels */ 402428d7b3dSmrg v = backlight_exists(de->d_name); 403428d7b3dSmrg if (v < best_type) { 404428d7b3dSmrg char *copy = strdup(de->d_name); 405428d7b3dSmrg if (copy) { 406428d7b3dSmrg free(best_iface); 407428d7b3dSmrg best_iface = copy; 408428d7b3dSmrg best_type = v; 409428d7b3dSmrg } 410428d7b3dSmrg } 411428d7b3dSmrg } 412428d7b3dSmrg closedir(dir); 413428d7b3dSmrg 414428d7b3dSmrg return best_iface; 415428d7b3dSmrg} 416428d7b3dSmrg 417428d7b3dSmrgint backlight_open(struct backlight *b, char *iface) 418428d7b3dSmrg{ 419428d7b3dSmrg int level; 420428d7b3dSmrg 421428d7b3dSmrg if (iface == NULL) 422428d7b3dSmrg iface = __backlight_find(); 423428d7b3dSmrg if (iface == NULL) 424428d7b3dSmrg goto err; 425428d7b3dSmrg 426428d7b3dSmrg b->type = __backlight_type(iface); 427428d7b3dSmrg 428428d7b3dSmrg b->max = __backlight_read(iface, "max_brightness"); 429428d7b3dSmrg if (b->max <= 0) 430428d7b3dSmrg goto err; 431428d7b3dSmrg 432428d7b3dSmrg level = __backlight_read(iface, "brightness"); 433428d7b3dSmrg if (level < 0) 434428d7b3dSmrg goto err; 435428d7b3dSmrg 436428d7b3dSmrg if (!__backlight_direct_init(b, iface) && 437428d7b3dSmrg !__backlight_helper_init(b, iface)) 438428d7b3dSmrg goto err; 439428d7b3dSmrg 440428d7b3dSmrg return level; 441428d7b3dSmrg 442428d7b3dSmrgerr: 443428d7b3dSmrg backlight_init(b); 444428d7b3dSmrg return -1; 445428d7b3dSmrg} 446428d7b3dSmrg 447428d7b3dSmrgint backlight_set(struct backlight *b, int level) 448428d7b3dSmrg{ 449428d7b3dSmrg char val[BACKLIGHT_VALUE_LEN]; 450428d7b3dSmrg int len, ret = 0; 451428d7b3dSmrg 452428d7b3dSmrg if (b->iface == NULL) 453428d7b3dSmrg return 0; 454428d7b3dSmrg 455428d7b3dSmrg if ((unsigned)level > b->max) 456428d7b3dSmrg level = b->max; 457428d7b3dSmrg 458428d7b3dSmrg len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); 459428d7b3dSmrg if (write(b->fd, val, len) != len) 460428d7b3dSmrg ret = -1; 461428d7b3dSmrg 462428d7b3dSmrg return ret; 463428d7b3dSmrg} 464428d7b3dSmrg 465428d7b3dSmrgint backlight_get(struct backlight *b) 466428d7b3dSmrg{ 467428d7b3dSmrg int level; 468428d7b3dSmrg 469428d7b3dSmrg if (b->iface == NULL) 470428d7b3dSmrg return -1; 471428d7b3dSmrg 472428d7b3dSmrg level = __backlight_read(b->iface, "brightness"); 473428d7b3dSmrg if (level > b->max) 474428d7b3dSmrg level = b->max; 475428d7b3dSmrg else if (level < 0) 476428d7b3dSmrg level = -1; 477428d7b3dSmrg return level; 478428d7b3dSmrg} 479428d7b3dSmrg 480428d7b3dSmrgint backlight_off(struct backlight *b) 481428d7b3dSmrg{ 482428d7b3dSmrg if (b->iface == NULL) 483428d7b3dSmrg return 0; 484428d7b3dSmrg 485428d7b3dSmrg if (!b->has_power) 486428d7b3dSmrg return 0; 487428d7b3dSmrg 488428d7b3dSmrg /* 4 -> FB_BLANK_POWERDOWN */ 489428d7b3dSmrg return __backlight_write(b->iface, "bl_power", "4"); 490428d7b3dSmrg} 491428d7b3dSmrg 492428d7b3dSmrgint backlight_on(struct backlight *b) 493428d7b3dSmrg{ 494428d7b3dSmrg if (b->iface == NULL) 495428d7b3dSmrg return 0; 496428d7b3dSmrg 497428d7b3dSmrg if (!b->has_power) 498428d7b3dSmrg return 0; 499428d7b3dSmrg 500428d7b3dSmrg /* 0 -> FB_BLANK_UNBLANK */ 501428d7b3dSmrg return __backlight_write(b->iface, "bl_power", "0"); 502428d7b3dSmrg} 503428d7b3dSmrg#endif 504428d7b3dSmrg 505428d7b3dSmrgvoid backlight_disable(struct backlight *b) 506428d7b3dSmrg{ 507428d7b3dSmrg if (b->iface == NULL) 508428d7b3dSmrg return; 509428d7b3dSmrg 510428d7b3dSmrg if (b->fd != -1) 511428d7b3dSmrg close(b->fd); 512428d7b3dSmrg 513428d7b3dSmrg free(b->iface); 514428d7b3dSmrg b->iface = NULL; 515428d7b3dSmrg} 516428d7b3dSmrg 517428d7b3dSmrgvoid backlight_close(struct backlight *b) 518428d7b3dSmrg{ 519428d7b3dSmrg backlight_disable(b); 520428d7b3dSmrg if (b->pid) 521428d7b3dSmrg waitpid(b->pid, NULL, 0); 522428d7b3dSmrg} 523428d7b3dSmrg 524428d7b3dSmrgchar *backlight_find_for_device(struct pci_device *pci) 525428d7b3dSmrg{ 526428d7b3dSmrg char path[200]; 527428d7b3dSmrg unsigned best_type = INT_MAX; 528428d7b3dSmrg char *best_iface = NULL; 529428d7b3dSmrg DIR *dir; 530428d7b3dSmrg struct dirent *de; 531428d7b3dSmrg 532428d7b3dSmrg snprintf(path, sizeof(path), 533428d7b3dSmrg "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight", 534428d7b3dSmrg pci->domain, pci->bus, pci->dev, pci->func); 535428d7b3dSmrg 536428d7b3dSmrg dir = opendir(path); 537428d7b3dSmrg if (dir == NULL) 538428d7b3dSmrg return NULL; 539428d7b3dSmrg 540428d7b3dSmrg while ((de = readdir(dir))) { 541428d7b3dSmrg int v; 542428d7b3dSmrg 543428d7b3dSmrg if (*de->d_name == '.') 544428d7b3dSmrg continue; 545428d7b3dSmrg 546428d7b3dSmrg v = backlight_exists(de->d_name); 547428d7b3dSmrg if (v < best_type) { 548428d7b3dSmrg char *copy = strdup(de->d_name); 549428d7b3dSmrg if (copy) { 550428d7b3dSmrg free(best_iface); 551428d7b3dSmrg best_iface = copy; 552428d7b3dSmrg best_type = v; 553428d7b3dSmrg } 554428d7b3dSmrg } 555428d7b3dSmrg } 556428d7b3dSmrg closedir(dir); 557428d7b3dSmrg 558428d7b3dSmrg return best_iface; 559428d7b3dSmrg} 560