142542f5fSchristos/*************************************************************************** 242542f5fSchristos 342542f5fSchristos Copyright 2014 Intel Corporation. All Rights Reserved. 442542f5fSchristos Copyright 2014 Red Hat, Inc. 542542f5fSchristos 642542f5fSchristos Permission is hereby granted, free of charge, to any person obtaining a 742542f5fSchristos copy of this software and associated documentation files (the 842542f5fSchristos "Software"), to deal in the Software without restriction, including 942542f5fSchristos without limitation the rights to use, copy, modify, merge, publish, 1042542f5fSchristos distribute, sub license, and/or sell copies of the Software, and to 1142542f5fSchristos permit persons to whom the Software is furnished to do so, subject to 1242542f5fSchristos the following conditions: 1342542f5fSchristos 1442542f5fSchristos The above copyright notice and this permission notice (including the 1542542f5fSchristos next paragraph) shall be included in all copies or substantial portions 1642542f5fSchristos of the Software. 1742542f5fSchristos 1842542f5fSchristos THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1942542f5fSchristos OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2042542f5fSchristos MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2142542f5fSchristos IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2242542f5fSchristos DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2342542f5fSchristos OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 2442542f5fSchristos THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2542542f5fSchristos 2642542f5fSchristos **************************************************************************/ 2742542f5fSchristos 2842542f5fSchristos#ifdef HAVE_CONFIG_H 2942542f5fSchristos#include "config.h" 3042542f5fSchristos#endif 3142542f5fSchristos 3242542f5fSchristos#include <sys/types.h> 3342542f5fSchristos#include <sys/wait.h> 3442542f5fSchristos#include <sys/stat.h> 3542542f5fSchristos#include <sys/ioctl.h> 3642542f5fSchristos 3763ef14f0Smrg#if MAJOR_IN_MKDEV 3863ef14f0Smrg#include <sys/mkdev.h> 3963ef14f0Smrg#elif MAJOR_IN_SYSMACROS 4063ef14f0Smrg#include <sys/sysmacros.h> 4163ef14f0Smrg#endif 4263ef14f0Smrg 4342542f5fSchristos#include <stdio.h> 4442542f5fSchristos#include <stdlib.h> 4542542f5fSchristos#include <string.h> 4642542f5fSchristos#include <ctype.h> 4742542f5fSchristos#include <limits.h> 4842542f5fSchristos#include <fcntl.h> 4942542f5fSchristos#include <unistd.h> 5042542f5fSchristos#include <dirent.h> 5163ef14f0Smrg#include <errno.h> 5242542f5fSchristos 5342542f5fSchristos#include <xorg-server.h> 5442542f5fSchristos#include <xf86.h> 5542542f5fSchristos#include <pciaccess.h> 5642542f5fSchristos 5742542f5fSchristos#include "backlight.h" 5842542f5fSchristos#include "fd.h" 5942542f5fSchristos 6042542f5fSchristos#define BACKLIGHT_CLASS "/sys/class/backlight" 6142542f5fSchristos 6242542f5fSchristos/* Enough for 10 digits of backlight + '\n' + '\0' */ 6342542f5fSchristos#define BACKLIGHT_VALUE_LEN 12 6442542f5fSchristos 6542542f5fSchristos#ifndef ARRAY_SIZE 6642542f5fSchristos#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) 6742542f5fSchristos#endif 6842542f5fSchristos 6942542f5fSchristos/* 7042542f5fSchristos * Unfortunately this is not as simple as I would like it to be. If selinux is 7142542f5fSchristos * dropping dbus messages pkexec may block *forever*. 7242542f5fSchristos * 7342542f5fSchristos * Backgrounding pkexec by doing System("pkexec ...&") does not work because 7442542f5fSchristos * that detaches pkexec from its parent at which point its security checks 7542542f5fSchristos * fail and it refuses to execute the helper. 7642542f5fSchristos * 7742542f5fSchristos * So we're left with spawning a helper child which gets levels to set written 7842542f5fSchristos * to it through a pipe. This turns the blocking forever problem from a hung 7942542f5fSchristos * machine problem into a simple backlight control not working problem. 8042542f5fSchristos * 8142542f5fSchristos * If only things were as simple as on OpenBSD! :) 8242542f5fSchristos */ 8342542f5fSchristos 8442542f5fSchristosvoid backlight_init(struct backlight *b) 8542542f5fSchristos{ 8642542f5fSchristos b->type = BL_NONE; 8742542f5fSchristos b->iface = NULL; 8842542f5fSchristos b->fd = -1; 8942542f5fSchristos b->pid = -1; 9042542f5fSchristos b->max = -1; 91813957e3Ssnj b->has_power = 0; 9242542f5fSchristos} 9342542f5fSchristos 9463ef14f0Smrg#ifdef HAVE_DEV_WSCONS_WSCONSIO_H 9542542f5fSchristos 9642542f5fSchristos#include <dev/wscons/wsconsio.h> 9742542f5fSchristos#include <xf86Priv.h> 9842542f5fSchristos 9942542f5fSchristosint backlight_set(struct backlight *b, int level) 10042542f5fSchristos{ 10142542f5fSchristos struct wsdisplay_param param; 10242542f5fSchristos 10342542f5fSchristos if (b->iface == NULL) 10442542f5fSchristos return -1; 10542542f5fSchristos 10642542f5fSchristos if ((unsigned)level > b->max) 10742542f5fSchristos level = b->max; 10842542f5fSchristos 10942542f5fSchristos memset(¶m, 0, sizeof(param)); 11042542f5fSchristos param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 11142542f5fSchristos param.curval = level; 11242542f5fSchristos 11342542f5fSchristos return ioctl(xf86Info.consoleFd, WSDISPLAYIO_SETPARAM, ¶m); 11442542f5fSchristos} 11542542f5fSchristos 11642542f5fSchristosint backlight_get(struct backlight *b) 11742542f5fSchristos{ 11842542f5fSchristos struct wsdisplay_param param; 11942542f5fSchristos 12042542f5fSchristos if (b->iface == NULL) 12142542f5fSchristos return -1; 12242542f5fSchristos 12342542f5fSchristos memset(¶m, 0, sizeof(param)); 12442542f5fSchristos param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 12542542f5fSchristos 12642542f5fSchristos if (ioctl(xf86Info.consoleFd, WSDISPLAYIO_GETPARAM, ¶m)) 12742542f5fSchristos return -1; 12842542f5fSchristos 12942542f5fSchristos return param.curval; 13042542f5fSchristos} 13142542f5fSchristos 13263ef14f0Smrgchar *backlight_find_for_device(struct pci_device *pci) 13363ef14f0Smrg{ 13463ef14f0Smrg return NULL; 13563ef14f0Smrg} 13663ef14f0Smrg 13742542f5fSchristosint backlight_open(struct backlight *b, char *iface) 13842542f5fSchristos{ 13942542f5fSchristos struct wsdisplay_param param; 14042542f5fSchristos 14142542f5fSchristos if (iface != NULL) 14242542f5fSchristos return -1; 14342542f5fSchristos 14442542f5fSchristos memset(¶m, 0, sizeof(param)); 14542542f5fSchristos param.param = WSDISPLAYIO_PARAM_BRIGHTNESS; 14642542f5fSchristos 14742542f5fSchristos if (ioctl(xf86Info.consoleFd, WSDISPLAYIO_GETPARAM, ¶m) == -1) 14842542f5fSchristos return -1; 14942542f5fSchristos 15042542f5fSchristos b->iface = strdup("wscons"); 15142542f5fSchristos if (b->iface == NULL) 15242542f5fSchristos return -1; 15342542f5fSchristos 15442542f5fSchristos b->max = param.max; 15542542f5fSchristos b->fd = -1; 15642542f5fSchristos b->type = BL_PLATFORM; 15742542f5fSchristos 15842542f5fSchristos return param.curval; 15942542f5fSchristos} 16042542f5fSchristos 16163ef14f0Smrgint backlight_exists(const char *iface) 16242542f5fSchristos{ 16363ef14f0Smrg return iface == NULL; 16442542f5fSchristos} 16542542f5fSchristos 166813957e3Ssnjint backlight_on(struct backlight *b) 167813957e3Ssnj{ 168813957e3Ssnj return 0; 169813957e3Ssnj} 170813957e3Ssnj 171813957e3Ssnjint backlight_off(struct backlight *b) 172813957e3Ssnj{ 173813957e3Ssnj return 0; 174813957e3Ssnj} 17563ef14f0Smrg 17642542f5fSchristos#else 17742542f5fSchristos 17842542f5fSchristosstatic int 17942542f5fSchristosis_sysfs_fd(int fd) 18042542f5fSchristos{ 18142542f5fSchristos struct stat st; 18242542f5fSchristos return fstat(fd, &st) == 0 && major(st.st_dev) == 0; 18342542f5fSchristos} 18442542f5fSchristos 18542542f5fSchristosstatic int 18642542f5fSchristos__backlight_open(const char *iface, const char *file, int mode) 18742542f5fSchristos{ 18842542f5fSchristos char buf[1024]; 18942542f5fSchristos int fd; 19042542f5fSchristos 19142542f5fSchristos snprintf(buf, sizeof(buf), BACKLIGHT_CLASS "/%s/%s", iface, file); 19242542f5fSchristos fd = open(buf, mode); 19342542f5fSchristos if (fd == -1) 19442542f5fSchristos return -1; 19542542f5fSchristos 19642542f5fSchristos if (!is_sysfs_fd(fd)) { 19742542f5fSchristos close(fd); 19842542f5fSchristos return -1; 19942542f5fSchristos } 20042542f5fSchristos 20142542f5fSchristos return fd; 20242542f5fSchristos} 20342542f5fSchristos 20442542f5fSchristosstatic int 20542542f5fSchristos__backlight_read(const char *iface, const char *file) 20642542f5fSchristos{ 20742542f5fSchristos char buf[BACKLIGHT_VALUE_LEN]; 20842542f5fSchristos int fd, val; 20942542f5fSchristos 21042542f5fSchristos fd = __backlight_open(iface, file, O_RDONLY); 21142542f5fSchristos if (fd < 0) 21242542f5fSchristos return -1; 21342542f5fSchristos 21442542f5fSchristos val = read(fd, buf, BACKLIGHT_VALUE_LEN - 1); 21542542f5fSchristos if (val > 0) { 21642542f5fSchristos buf[val] = '\0'; 21742542f5fSchristos val = atoi(buf); 21842542f5fSchristos } else 21942542f5fSchristos val = -1; 22042542f5fSchristos close(fd); 22142542f5fSchristos 22242542f5fSchristos return val; 22342542f5fSchristos} 22442542f5fSchristos 22563ef14f0Smrgstatic int 22663ef14f0Smrgwriten(int fd, const char *value, int len) 22763ef14f0Smrg{ 22863ef14f0Smrg int ret; 22963ef14f0Smrg 23063ef14f0Smrg do { 23163ef14f0Smrg ret = write(fd, value, len); 23263ef14f0Smrg if (ret < 0) { 23363ef14f0Smrg if (errno == EAGAIN || errno == EINTR) 23463ef14f0Smrg continue; 23563ef14f0Smrg 23663ef14f0Smrg return ret; 23763ef14f0Smrg } 23863ef14f0Smrg } while (value += ret, len -= ret); 23963ef14f0Smrg 24063ef14f0Smrg return 0; 24163ef14f0Smrg} 24263ef14f0Smrg 243813957e3Ssnjstatic int 244813957e3Ssnj__backlight_write(const char *iface, const char *file, const char *value) 245813957e3Ssnj{ 246813957e3Ssnj int fd, ret; 247813957e3Ssnj 248813957e3Ssnj fd = __backlight_open(iface, file, O_WRONLY); 249813957e3Ssnj if (fd < 0) 250813957e3Ssnj return -1; 251813957e3Ssnj 25263ef14f0Smrg ret = writen(fd, value, strlen(value)+1); 253813957e3Ssnj close(fd); 254813957e3Ssnj 255813957e3Ssnj return ret; 256813957e3Ssnj} 257813957e3Ssnj 25842542f5fSchristos/* List of available kernel interfaces in priority order */ 25942542f5fSchristosstatic const char *known_interfaces[] = { 26042542f5fSchristos "dell_backlight", 26142542f5fSchristos "gmux_backlight", 26242542f5fSchristos "asus-laptop", 26342542f5fSchristos "asus-nb-wmi", 26442542f5fSchristos "eeepc", 26542542f5fSchristos "thinkpad_screen", 26642542f5fSchristos "mbp_backlight", 26742542f5fSchristos "fujitsu-laptop", 26842542f5fSchristos "sony", 26942542f5fSchristos "samsung", 27042542f5fSchristos "acpi_video1", 27142542f5fSchristos "acpi_video0", 27242542f5fSchristos "intel_backlight", 27342542f5fSchristos}; 27442542f5fSchristos 27563ef14f0Smrgstatic int __backlight_type(const char *iface) 27642542f5fSchristos{ 27742542f5fSchristos char buf[1024]; 27863ef14f0Smrg int fd, v, i; 27942542f5fSchristos 28042542f5fSchristos v = -1; 28142542f5fSchristos fd = __backlight_open(iface, "type", O_RDONLY); 28242542f5fSchristos if (fd >= 0) { 28342542f5fSchristos v = read(fd, buf, sizeof(buf)-1); 28442542f5fSchristos close(fd); 28542542f5fSchristos } 28642542f5fSchristos if (v > 0) { 28742542f5fSchristos while (v > 0 && isspace(buf[v-1])) 28842542f5fSchristos v--; 28942542f5fSchristos buf[v] = '\0'; 29042542f5fSchristos 29142542f5fSchristos if (strcmp(buf, "raw") == 0) 29263ef14f0Smrg v = BL_RAW << 8; 29342542f5fSchristos else if (strcmp(buf, "platform") == 0) 29463ef14f0Smrg v = BL_PLATFORM << 8; 29542542f5fSchristos else if (strcmp(buf, "firmware") == 0) 29663ef14f0Smrg v = BL_FIRMWARE << 8; 29742542f5fSchristos else 29863ef14f0Smrg v = BL_NAMED << 8; 29942542f5fSchristos } else 30063ef14f0Smrg v = BL_NAMED << 8; 30142542f5fSchristos 30263ef14f0Smrg for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) { 30363ef14f0Smrg if (strcmp(iface, known_interfaces[i]) == 0) 30463ef14f0Smrg break; 30542542f5fSchristos } 30663ef14f0Smrg v += i; 30742542f5fSchristos 30842542f5fSchristos return v; 30942542f5fSchristos} 31042542f5fSchristos 31163ef14f0Smrgstatic int __backlight_exists(const char *iface) 31242542f5fSchristos{ 31342542f5fSchristos if (__backlight_read(iface, "brightness") < 0) 31463ef14f0Smrg return -1; 31542542f5fSchristos 31642542f5fSchristos if (__backlight_read(iface, "max_brightness") <= 0) 31763ef14f0Smrg return -1; 31842542f5fSchristos 31942542f5fSchristos return __backlight_type(iface); 32042542f5fSchristos} 32142542f5fSchristos 32263ef14f0Smrgint backlight_exists(const char *iface) 32363ef14f0Smrg{ 32463ef14f0Smrg return __backlight_exists(iface) != -1; 32563ef14f0Smrg} 32663ef14f0Smrg 32742542f5fSchristosstatic int __backlight_init(struct backlight *b, char *iface, int fd) 32842542f5fSchristos{ 32942542f5fSchristos b->fd = fd_move_cloexec(fd_set_nonblock(fd)); 33042542f5fSchristos b->iface = iface; 33142542f5fSchristos return 1; 33242542f5fSchristos} 33342542f5fSchristos 33442542f5fSchristosstatic int __backlight_direct_init(struct backlight *b, char *iface) 33542542f5fSchristos{ 33642542f5fSchristos int fd; 33742542f5fSchristos 33842542f5fSchristos fd = __backlight_open(iface, "brightness", O_RDWR); 33942542f5fSchristos if (fd < 0) 34042542f5fSchristos return 0; 34142542f5fSchristos 342813957e3Ssnj if (__backlight_read(iface, "bl_power") != -1) 343813957e3Ssnj b->has_power = 1; 344813957e3Ssnj 34542542f5fSchristos return __backlight_init(b, iface, fd); 34642542f5fSchristos} 34742542f5fSchristos 34842542f5fSchristosstatic int __backlight_helper_init(struct backlight *b, char *iface) 34942542f5fSchristos{ 35042542f5fSchristos#if USE_BACKLIGHT_HELPER 35142542f5fSchristos struct stat st; 35242542f5fSchristos char *env[] = { NULL }; 35342542f5fSchristos int use_pkexec = 0; 35442542f5fSchristos int fds[2]; 35542542f5fSchristos 35642542f5fSchristos /* 35742542f5fSchristos * Some systems may prefer using PolicyKit's pkexec over 35842542f5fSchristos * making the helper suid root, since the suid option will allow 35942542f5fSchristos * anyone to control the backlight. However, as pkexec 36042542f5fSchristos * is quite troublesome and not universally available, we 36142542f5fSchristos * still try the old fashioned and simple method first. 36242542f5fSchristos * Either way, we have to trust that it is our backlight-helper 36342542f5fSchristos * that is run and that we have scrutinised it carefully. 36442542f5fSchristos */ 36542542f5fSchristos if (stat(LIBEXEC_PATH "/xf86-video-intel-backlight-helper", &st)) 36642542f5fSchristos return 0; 36742542f5fSchristos 36842542f5fSchristos if ((st.st_mode & (S_IFREG | S_ISUID | S_IXUSR)) != (S_IFREG | S_ISUID | S_IXUSR)) { 36942542f5fSchristos if (System("pkexec --version")) 37042542f5fSchristos return 0; 37142542f5fSchristos 37242542f5fSchristos use_pkexec = 1; 37342542f5fSchristos } 37442542f5fSchristos 37542542f5fSchristos if (pipe(fds)) 37642542f5fSchristos return 0; 37742542f5fSchristos 37842542f5fSchristos switch ((b->pid = fork())) { 37942542f5fSchristos case 0: 38042542f5fSchristos if (setgid(getgid()) || setuid(getuid())) 38142542f5fSchristos _exit(127); 38242542f5fSchristos 38342542f5fSchristos close(fds[1]); 38442542f5fSchristos if (dup2(fds[0], 0)) 38542542f5fSchristos _exit(127); 38642542f5fSchristos close(fds[0]); 38742542f5fSchristos 38842542f5fSchristos if (use_pkexec) { 38942542f5fSchristos execlp("pkexec", "pkexec", 39042542f5fSchristos LIBEXEC_PATH "/xf86-video-intel-backlight-helper", 39142542f5fSchristos iface, (char *)0); 39242542f5fSchristos } else { 39342542f5fSchristos execle(LIBEXEC_PATH "/xf86-video-intel-backlight-helper", 39442542f5fSchristos "xf86-video-intel-backlight-helper", 39542542f5fSchristos iface, (char *)0, env); 39642542f5fSchristos } 39742542f5fSchristos _exit(1); 39842542f5fSchristos /* unreachable fallthrough */ 39942542f5fSchristos case -1: 40042542f5fSchristos close(fds[1]); 40142542f5fSchristos close(fds[0]); 40242542f5fSchristos return 0; 40342542f5fSchristos 40442542f5fSchristos default: 40542542f5fSchristos close(fds[0]); 40642542f5fSchristos return __backlight_init(b, iface, fds[1]); 40742542f5fSchristos } 40842542f5fSchristos#else 40942542f5fSchristos return 0; 41042542f5fSchristos#endif 41142542f5fSchristos} 41242542f5fSchristos 41342542f5fSchristosstatic char * 41442542f5fSchristos__backlight_find(void) 41542542f5fSchristos{ 41642542f5fSchristos char *best_iface = NULL; 41742542f5fSchristos unsigned best_type = INT_MAX; 41842542f5fSchristos DIR *dir; 41942542f5fSchristos struct dirent *de; 42042542f5fSchristos 42142542f5fSchristos dir = opendir(BACKLIGHT_CLASS); 42242542f5fSchristos if (dir == NULL) 42342542f5fSchristos return NULL; 42442542f5fSchristos 42542542f5fSchristos while ((de = readdir(dir))) { 42642542f5fSchristos int v; 42742542f5fSchristos 42842542f5fSchristos if (*de->d_name == '.') 42942542f5fSchristos continue; 43042542f5fSchristos 43142542f5fSchristos /* Fallback to priority list of known iface for old kernels */ 43263ef14f0Smrg v = __backlight_exists(de->d_name); 43363ef14f0Smrg if (v < 0) 43463ef14f0Smrg continue; 43563ef14f0Smrg 43663ef14f0Smrg if (v < best_type) { 43763ef14f0Smrg char *copy = strdup(de->d_name); 43863ef14f0Smrg if (copy) { 43963ef14f0Smrg free(best_iface); 44063ef14f0Smrg best_iface = copy; 44163ef14f0Smrg best_type = v; 44263ef14f0Smrg } 44363ef14f0Smrg } 44463ef14f0Smrg } 44563ef14f0Smrg closedir(dir); 44663ef14f0Smrg 44763ef14f0Smrg return best_iface; 44863ef14f0Smrg} 44963ef14f0Smrg 45063ef14f0Smrgchar *backlight_find_for_device(struct pci_device *pci) 45163ef14f0Smrg{ 45263ef14f0Smrg char path[200]; 45363ef14f0Smrg unsigned best_type = INT_MAX; 45463ef14f0Smrg char *best_iface = NULL; 45563ef14f0Smrg DIR *dir; 45663ef14f0Smrg struct dirent *de; 45763ef14f0Smrg 45863ef14f0Smrg snprintf(path, sizeof(path), 45963ef14f0Smrg "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight", 46063ef14f0Smrg pci->domain, pci->bus, pci->dev, pci->func); 46163ef14f0Smrg 46263ef14f0Smrg dir = opendir(path); 46363ef14f0Smrg if (dir == NULL) 46463ef14f0Smrg return NULL; 46563ef14f0Smrg 46663ef14f0Smrg while ((de = readdir(dir))) { 46763ef14f0Smrg int v; 46863ef14f0Smrg 46963ef14f0Smrg if (*de->d_name == '.') 47063ef14f0Smrg continue; 47163ef14f0Smrg 47263ef14f0Smrg v = __backlight_exists(de->d_name); 47363ef14f0Smrg if (v < 0) 47463ef14f0Smrg continue; 47563ef14f0Smrg 47642542f5fSchristos if (v < best_type) { 47742542f5fSchristos char *copy = strdup(de->d_name); 47842542f5fSchristos if (copy) { 47942542f5fSchristos free(best_iface); 48042542f5fSchristos best_iface = copy; 48142542f5fSchristos best_type = v; 48242542f5fSchristos } 48342542f5fSchristos } 48442542f5fSchristos } 48542542f5fSchristos closedir(dir); 48642542f5fSchristos 48742542f5fSchristos return best_iface; 48842542f5fSchristos} 48942542f5fSchristos 49042542f5fSchristosint backlight_open(struct backlight *b, char *iface) 49142542f5fSchristos{ 49263ef14f0Smrg int level, type; 49342542f5fSchristos 49442542f5fSchristos if (iface == NULL) 49542542f5fSchristos iface = __backlight_find(); 49642542f5fSchristos if (iface == NULL) 49742542f5fSchristos goto err; 49842542f5fSchristos 49963ef14f0Smrg type = __backlight_type(iface); 50063ef14f0Smrg if (type < 0) 50163ef14f0Smrg goto err; 50263ef14f0Smrg b->type = type >> 8; 50342542f5fSchristos 50442542f5fSchristos b->max = __backlight_read(iface, "max_brightness"); 50542542f5fSchristos if (b->max <= 0) 50642542f5fSchristos goto err; 50742542f5fSchristos 50842542f5fSchristos level = __backlight_read(iface, "brightness"); 50942542f5fSchristos if (level < 0) 51042542f5fSchristos goto err; 51142542f5fSchristos 51242542f5fSchristos if (!__backlight_direct_init(b, iface) && 51342542f5fSchristos !__backlight_helper_init(b, iface)) 51442542f5fSchristos goto err; 51542542f5fSchristos 51642542f5fSchristos return level; 51742542f5fSchristos 51842542f5fSchristoserr: 51942542f5fSchristos backlight_init(b); 52042542f5fSchristos return -1; 52142542f5fSchristos} 52242542f5fSchristos 52342542f5fSchristosint backlight_set(struct backlight *b, int level) 52442542f5fSchristos{ 52542542f5fSchristos char val[BACKLIGHT_VALUE_LEN]; 52663ef14f0Smrg int len; 52742542f5fSchristos 52842542f5fSchristos if (b->iface == NULL) 52942542f5fSchristos return 0; 53042542f5fSchristos 53142542f5fSchristos if ((unsigned)level > b->max) 53242542f5fSchristos level = b->max; 53342542f5fSchristos 53442542f5fSchristos len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); 53563ef14f0Smrg return writen(b->fd, val, len); 53642542f5fSchristos} 53742542f5fSchristos 53842542f5fSchristosint backlight_get(struct backlight *b) 53942542f5fSchristos{ 54042542f5fSchristos int level; 54142542f5fSchristos 54242542f5fSchristos if (b->iface == NULL) 54342542f5fSchristos return -1; 54442542f5fSchristos 54542542f5fSchristos level = __backlight_read(b->iface, "brightness"); 54642542f5fSchristos if (level > b->max) 54742542f5fSchristos level = b->max; 54842542f5fSchristos else if (level < 0) 54942542f5fSchristos level = -1; 55042542f5fSchristos return level; 55142542f5fSchristos} 552813957e3Ssnj 553813957e3Ssnjint backlight_off(struct backlight *b) 554813957e3Ssnj{ 555813957e3Ssnj if (b->iface == NULL) 556813957e3Ssnj return 0; 557813957e3Ssnj 558813957e3Ssnj if (!b->has_power) 559813957e3Ssnj return 0; 560813957e3Ssnj 561813957e3Ssnj /* 4 -> FB_BLANK_POWERDOWN */ 562813957e3Ssnj return __backlight_write(b->iface, "bl_power", "4"); 563813957e3Ssnj} 564813957e3Ssnj 565813957e3Ssnjint backlight_on(struct backlight *b) 566813957e3Ssnj{ 567813957e3Ssnj if (b->iface == NULL) 568813957e3Ssnj return 0; 569813957e3Ssnj 570813957e3Ssnj if (!b->has_power) 571813957e3Ssnj return 0; 572813957e3Ssnj 573813957e3Ssnj /* 0 -> FB_BLANK_UNBLANK */ 574813957e3Ssnj return __backlight_write(b->iface, "bl_power", "0"); 575813957e3Ssnj} 57642542f5fSchristos#endif 57742542f5fSchristos 57842542f5fSchristosvoid backlight_disable(struct backlight *b) 57942542f5fSchristos{ 58042542f5fSchristos if (b->iface == NULL) 58142542f5fSchristos return; 58242542f5fSchristos 58342542f5fSchristos if (b->fd != -1) 58442542f5fSchristos close(b->fd); 58542542f5fSchristos 58642542f5fSchristos free(b->iface); 58742542f5fSchristos b->iface = NULL; 58842542f5fSchristos} 58942542f5fSchristos 59042542f5fSchristosvoid backlight_close(struct backlight *b) 59142542f5fSchristos{ 59242542f5fSchristos backlight_disable(b); 59363ef14f0Smrg if (b->pid > 0) 59442542f5fSchristos waitpid(b->pid, NULL, 0); 59542542f5fSchristos} 596