libbacklight is 300 lines of code in one .c file, and we're relying on udev changes that aren't yet upstream. For now, let's just keep a copy in weston and if the Xorg DDX drivers start using libbacklight and it becomes more widely available, we'll make it an external dependency.
parent
8e53c7f566
commit
51cba3ca38
@ -0,0 +1,322 @@ |
||||
/*
|
||||
* libbacklight - userspace interface to Linux backlight control |
||||
* |
||||
* Copyright © 2012 Intel Corporation |
||||
* Copyright 2010 Red Hat <mjg@redhat.com> |
||||
* |
||||
* Permission is hereby granted, free of charge, to any person obtaining a |
||||
* copy of this software and associated documentation files (the "Software"), |
||||
* to deal in the Software without restriction, including without limitation |
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
* and/or sell copies of the Software, and to permit persons to whom the |
||||
* Software is furnished to do so, subject to the following conditions: |
||||
* |
||||
* The above copyright notice and this permission notice (including the next |
||||
* paragraph) shall be included in all copies or substantial portions of the |
||||
* Software. |
||||
* |
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
* DEALINGS IN THE SOFTWARE. |
||||
* |
||||
* Authors: |
||||
* Matthew Garrett <mjg@redhat.com> |
||||
* Tiago Vignatti <vignatti@freedesktop.org> |
||||
*/ |
||||
|
||||
#define _GNU_SOURCE |
||||
|
||||
#include <libbacklight.h> |
||||
#include <stdio.h> |
||||
#include <linux/types.h> |
||||
#include <dirent.h> |
||||
#include <drm/drm_mode.h> |
||||
#include <fcntl.h> |
||||
#include <malloc.h> |
||||
#include <string.h> |
||||
#include <errno.h> |
||||
|
||||
static const char *output_names[] = { "Unknown", |
||||
"VGA", |
||||
"DVI-I", |
||||
"DVI-D", |
||||
"DVI-A", |
||||
"Composite", |
||||
"SVIDEO", |
||||
"LVDS", |
||||
"Component", |
||||
"9-pin DIN", |
||||
"DisplayPort" |
||||
"HDMI Type A", |
||||
"HDMI Type B", |
||||
"TV", |
||||
"Embedded DisplayPort" |
||||
}; |
||||
|
||||
static long backlight_get(struct backlight *backlight, char *node) |
||||
{ |
||||
char buffer[100]; |
||||
char *path; |
||||
int fd; |
||||
long value, ret; |
||||
|
||||
if (asprintf(&path, "%s/%s", backlight->path, node) < 0) |
||||
return -ENOMEM |
||||
; |
||||
fd = open(path, O_RDONLY); |
||||
if (fd < 0) { |
||||
ret = -1; |
||||
goto out; |
||||
} |
||||
|
||||
ret = read(fd, &buffer, sizeof(buffer)); |
||||
if (ret < 1) { |
||||
ret = -1; |
||||
goto out; |
||||
} |
||||
|
||||
value = strtol(buffer, NULL, 10); |
||||
ret = value; |
||||
out: |
||||
close(fd); |
||||
if (path) |
||||
free(path); |
||||
return ret; |
||||
} |
||||
|
||||
long backlight_get_brightness(struct backlight *backlight) |
||||
{ |
||||
return backlight_get(backlight, "brightness"); |
||||
} |
||||
|
||||
long backlight_get_max_brightness(struct backlight *backlight) |
||||
{ |
||||
return backlight_get(backlight, "max_brightness"); |
||||
} |
||||
|
||||
long backlight_get_actual_brightness(struct backlight *backlight) |
||||
{ |
||||
return backlight_get(backlight, "actual_brightness"); |
||||
} |
||||
|
||||
long backlight_set_brightness(struct backlight *backlight, long brightness) |
||||
{ |
||||
char *path; |
||||
char *buffer = NULL; |
||||
int fd; |
||||
long ret; |
||||
|
||||
if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0) |
||||
return -ENOMEM; |
||||
|
||||
fd = open(path, O_RDWR); |
||||
if (fd < 0) { |
||||
ret = -1; |
||||
goto out; |
||||
} |
||||
|
||||
ret = read(fd, &buffer, sizeof(buffer)); |
||||
if (ret < 1) { |
||||
ret = -1; |
||||
goto out; |
||||
} |
||||
|
||||
if (asprintf(&buffer, "%ld", brightness) < 0) |
||||
return -ENOMEM; |
||||
|
||||
ret = write(fd, buffer, strlen(buffer)); |
||||
if (ret < 0) { |
||||
ret = -1; |
||||
goto out; |
||||
} |
||||
|
||||
ret = backlight_get_brightness(backlight); |
||||
backlight->brightness = ret; |
||||
out: |
||||
if (buffer) |
||||
free(buffer); |
||||
if (path) |
||||
free(path); |
||||
close(fd); |
||||
return ret; |
||||
} |
||||
|
||||
void backlight_destroy(struct backlight *backlight) |
||||
{ |
||||
if (!backlight) |
||||
return; |
||||
|
||||
if (backlight->path) |
||||
free(backlight->path); |
||||
|
||||
free(backlight); |
||||
} |
||||
|
||||
struct backlight *backlight_init(struct udev_device *drm_device, |
||||
uint32_t connector_type) |
||||
{ |
||||
const char *syspath = NULL; |
||||
char *pci_name = NULL; |
||||
char *chosen_path = NULL; |
||||
char *path = NULL; |
||||
DIR *backlights; |
||||
struct dirent *entry; |
||||
enum backlight_type type = 0; |
||||
char buffer[100]; |
||||
struct backlight *backlight; |
||||
int err, ret; |
||||
|
||||
if (!drm_device) |
||||
return NULL; |
||||
|
||||
syspath = udev_device_get_syspath(drm_device); |
||||
if (!syspath) |
||||
return NULL; |
||||
|
||||
if (asprintf(&path, "%s/%s", syspath, "device") < 0) |
||||
return NULL; |
||||
|
||||
ret = readlink(path, buffer, sizeof(buffer)); |
||||
free(path); |
||||
if (ret < 0) |
||||
return NULL; |
||||
|
||||
buffer[ret] = '\0'; |
||||
pci_name = basename(buffer); |
||||
|
||||
if (connector_type <= 0) |
||||
return NULL; |
||||
|
||||
backlights = opendir("/sys/class/backlight"); |
||||
if (!backlights) |
||||
return NULL; |
||||
|
||||
/* Find the "best" backlight for the device. Firmware
|
||||
interfaces are preferred over platform interfaces are |
||||
preferred over raw interfaces. For raw interfaces we'll |
||||
check if the device ID in the form of pci match, while |
||||
for firmware interfaces we require the pci ID to |
||||
match. It's assumed that platform interfaces always match, |
||||
since we can't actually associate them with IDs. |
||||
|
||||
A further awkwardness is that, while it's theoretically |
||||
possible for an ACPI interface to include support for |
||||
changing the backlight of external devices, it's unlikely |
||||
to ever be done. It's effectively impossible for a platform |
||||
interface to do so. So if we get asked about anything that |
||||
isn't LVDS or eDP, we pretty much have to require that the |
||||
control be supplied via a raw interface */ |
||||
|
||||
while ((entry = readdir(backlights))) { |
||||
char *backlight_path; |
||||
char *parent; |
||||
enum backlight_type entry_type; |
||||
int fd; |
||||
|
||||
if (entry->d_name[0] == '.') |
||||
continue; |
||||
|
||||
if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight", |
||||
entry->d_name) < 0) |
||||
return NULL; |
||||
|
||||
if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) |
||||
return NULL; |
||||
|
||||
fd = open(path, O_RDONLY); |
||||
|
||||
if (fd < 0) |
||||
goto out; |
||||
|
||||
ret = read (fd, &buffer, sizeof(buffer)); |
||||
close (fd); |
||||
|
||||
if (ret < 1) |
||||
goto out; |
||||
|
||||
buffer[ret] = '\0'; |
||||
|
||||
if (!strncmp(buffer, "raw\n", sizeof(buffer))) |
||||
entry_type = BACKLIGHT_RAW; |
||||
else if (!strncmp(buffer, "platform\n", sizeof(buffer))) |
||||
entry_type = BACKLIGHT_PLATFORM; |
||||
else if (!strncmp(buffer, "firmware\n", sizeof(buffer))) |
||||
entry_type = BACKLIGHT_FIRMWARE; |
||||
else |
||||
goto out; |
||||
|
||||
if (connector_type != DRM_MODE_CONNECTOR_LVDS && |
||||
connector_type != DRM_MODE_CONNECTOR_eDP) { |
||||
/* External displays are assumed to require
|
||||
gpu control at the moment */ |
||||
if (entry_type != BACKLIGHT_RAW) |
||||
goto out; |
||||
} |
||||
|
||||
free (path); |
||||
|
||||
if (asprintf(&path, "%s/%s", backlight_path, "device") < 0) |
||||
return NULL; |
||||
|
||||
ret = readlink(path, buffer, sizeof(buffer)); |
||||
|
||||
if (ret < 0) |
||||
goto out; |
||||
|
||||
buffer[ret] = '\0'; |
||||
|
||||
parent = basename(buffer); |
||||
|
||||
/* Perform matching for raw and firmware backlights -
|
||||
platform backlights have to be assumed to match */ |
||||
if (entry_type == BACKLIGHT_RAW || |
||||
entry_type == BACKLIGHT_FIRMWARE) { |
||||
if (!(pci_name && !strcmp(pci_name, parent))) |
||||
goto out; |
||||
} |
||||
|
||||
if (entry_type < type) |
||||
goto out; |
||||
|
||||
type = entry_type; |
||||
|
||||
if (chosen_path) |
||||
free(chosen_path); |
||||
chosen_path = strdup(backlight_path); |
||||
|
||||
out: |
||||
free(backlight_path); |
||||
free(path); |
||||
} |
||||
|
||||
if (!chosen_path) |
||||
return NULL; |
||||
|
||||
backlight = malloc(sizeof(struct backlight)); |
||||
|
||||
if (!backlight) |
||||
goto err; |
||||
|
||||
backlight->path = chosen_path; |
||||
backlight->type = type; |
||||
|
||||
backlight->max_brightness = backlight_get_max_brightness(backlight); |
||||
if (backlight->max_brightness < 0) |
||||
goto err; |
||||
|
||||
backlight->brightness = backlight_get_actual_brightness(backlight); |
||||
if (backlight->brightness < 0) |
||||
goto err; |
||||
|
||||
return backlight; |
||||
err: |
||||
if (chosen_path) |
||||
free(chosen_path); |
||||
free (backlight); |
||||
return NULL; |
||||
} |
@ -0,0 +1,49 @@ |
||||
#ifndef LIBBACKLIGHT_H |
||||
#define LIBBACKLIGHT_H |
||||
#include <libudev.h> |
||||
#include <stdint.h> |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
enum backlight_type { |
||||
BACKLIGHT_RAW, |
||||
BACKLIGHT_PLATFORM, |
||||
BACKLIGHT_FIRMWARE, |
||||
}; |
||||
|
||||
struct backlight { |
||||
char *path; |
||||
int max_brightness; |
||||
int brightness; |
||||
enum backlight_type type; |
||||
}; |
||||
|
||||
/*
|
||||
* Find and set up a backlight for a valid udev connector device, i.e. one |
||||
* matching drm subsytem and with status of connected. |
||||
*/ |
||||
struct backlight *backlight_init(struct udev_device *drm_device, |
||||
uint32_t connector_type); |
||||
|
||||
/* Free backlight resources */ |
||||
void backlight_destroy(struct backlight *backlight); |
||||
|
||||
/* Provide the maximum backlight value */ |
||||
long backlight_get_max_brightness(struct backlight *backlight); |
||||
|
||||
/* Provide the cached backlight value */ |
||||
long backlight_get_brightness(struct backlight *backlight); |
||||
|
||||
/* Provide the hardware backlight value */ |
||||
long backlight_get_actual_brightness(struct backlight *backlight); |
||||
|
||||
/* Set the backlight to a value between 0 and max */ |
||||
long backlight_set_brightness(struct backlight *backlight, long brightness); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* LIBBACKLIGHT_H */ |
Loading…
Reference in new issue