summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-07-02 10:21:42 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-07-02 10:25:39 +0100
commite80f9c4670a0e84521907b1baa059322784b1558 (patch)
tree8bf6cceebda34f8d7957d93ae3ec5f4b321407a9
parent61e16dc5673a1ac96b2ecee072cc3e80971be5d9 (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.c146
1 files changed, 108 insertions, 38 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 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <dirent.h>
#include <errno.h>
#include <poll.h>
+#include <ctype.h>
#include <xorgVersion.h>
#include <X11/Xatom.h>
@@ -91,7 +93,7 @@ struct sna_output {
int panel_vdisplay;
int dpms_mode;
- const char *backlight_iface;
+ char *backlight_iface;
int backlight_active_level;
int backlight_max;
struct list link;
@@ -104,28 +106,6 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
#define BACKLIGHT_CLASS "/sys/class/backlight"
-/*
- * List of available kernel interfaces in priority order
- */
-static const char *backlight_interfaces[] = {
- "intel", /* prefer our own native backlight driver */
- "asus-laptop",
- "asus-nb-wmi",
- "eeepc",
- "thinkpad_screen",
- "mbp_backlight",
- "fujitsu-laptop",
- "sony",
- "samsung",
- "acpi_video1", /* finally fallback to the generic acpi drivers */
- "acpi_video0",
- NULL,
-};
-/*
- * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
- * '/' + "max_backlight"
- */
-#define BACKLIGHT_PATH_LEN 80
/* Enough for 10 digits of backlight + '\n' + '\0' */
#define BACKLIGHT_VALUE_LEN 12
@@ -219,7 +199,7 @@ static void
sna_output_backlight_set(xf86OutputPtr output, int level)
{
struct sna_output *sna_output = output->driver_private;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ char path[1024], val[BACKLIGHT_VALUE_LEN];
int fd, len, ret;
DBG(("%s: level=%d\n", __FUNCTION__, level));
@@ -252,7 +232,7 @@ static int
sna_output_backlight_get(xf86OutputPtr output)
{
struct sna_output *sna_output = output->driver_private;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ char path[1024], val[BACKLIGHT_VALUE_LEN];
int fd, level;
sprintf(path, "%s/%s/actual_brightness",
@@ -287,7 +267,7 @@ static int
sna_output_backlight_get_max(xf86OutputPtr output)
{
struct sna_output *sna_output = output->driver_private;
- char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ char path[1024], val[BACKLIGHT_VALUE_LEN];
int fd, max = 0;
sprintf(path, "%s/%s/max_brightness",
@@ -313,29 +293,117 @@ sna_output_backlight_get_max(xf86OutputPtr output)
return max;
}
+enum {
+ FIRMWARE,
+ PLATFORM,
+ RAW,
+ NAMED,
+};
+
static void
sna_output_backlight_init(xf86OutputPtr output)
{
+ static const char *known_interfaces[] = {
+ "asus-laptop",
+ "asus-nb-wmi",
+ "eeepc",
+ "thinkpad_screen",
+ "mbp_backlight",
+ "fujitsu-laptop",
+ "sony",
+ "samsung",
+ "acpi_video1",
+ "acpi_video0",
+ "intel_backlight",
+ };
struct sna_output *sna_output = output->driver_private;
+ char *best_iface;
+ int best_type;
+ DIR *dir;
+ struct dirent *de;
+
+ best_iface = NULL;
+ best_type = INT_MAX;
+
+ dir = opendir(BACKLIGHT_CLASS);
+ while ((de = readdir(dir))) {
+ char path[1024];
+ char buf[100];
+ int fd, v;
+
+ snprintf(path, sizeof(path), "%s/%s/type",
+ BACKLIGHT_CLASS, de->d_name);
+
+ v = -1;
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ v = read(fd, buf, sizeof(buf)-1);
+ close(fd);
+ }
+ if (v > 0) {
+ while (v > 0 && isspace(buf[v-1]))
+ v--;
+ buf[v] = '\0';
+
+ if (strcmp(buf, "raw") == 0)
+ v = RAW;
+ else if (strcmp(buf, "platform") == 0)
+ v = PLATFORM;
+ else if (strcmp(buf, "firmware") == 0)
+ v = FIRMWARE;
+ else
+ v = NAMED;
+ } else
+ v = NAMED;
+
+ /* Fallback to priority list of known iface for old kernels */
+ if (v == NAMED) {
int i;
+ for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
+ if (strcmp(de->d_name, known_interfaces[i]) == 0)
+ break;
+ }
+ v += i;
+ }
- for (i = 0; backlight_interfaces[i] != NULL; i++) {
- char path[BACKLIGHT_PATH_LEN];
- struct stat buf;
+ if (v < best_type) {
+ char *copy;
+ int max;
- sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]);
- if (!stat(path, &buf)) {
- sna_output->backlight_iface = backlight_interfaces[i];
- sna_output->backlight_max = sna_output_backlight_get_max(output);
- if (sna_output->backlight_max > 0) {
- sna_output->backlight_active_level = sna_output_backlight_get(output);
- xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
- "found backlight control interface %s\n", path);
- return;
+ /* XXX detect right backlight for multi-GPU/panels */
+
+ sna_output->backlight_iface = de->d_name;
+ max = sna_output_backlight_get_max(output);
+ if (max <= 0)
+ continue;
+
+ copy = strdup(de->d_name);
+ if (copy) {
+ free(best_iface);
+ best_iface = copy;
+ best_type = v;
}
}
}
+
sna_output->backlight_iface = NULL;
+
+ if (best_iface) {
+ const char *str;
+
+ sna_output->backlight_iface = best_iface;
+ sna_output->backlight_max = sna_output_backlight_get_max(output);
+ sna_output->backlight_active_level = sna_output_backlight_get(output);
+ switch (best_type) {
+ case FIRMWARE: str = "firmware"; break;
+ case PLATFORM: str = "platform"; break;
+ case RAW: str = "raw"; break;
+ default: str = "unknown"; break;
+ }
+ xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
+ "found backlight control interface %s (type '%s')\n",
+ best_iface, str);
+ }
}
@@ -1515,6 +1583,8 @@ sna_output_destroy(xf86OutputPtr output)
drmModeFreeConnector(sna_output->mode_output);
sna_output->mode_output = NULL;
+ free(sna_output->backlight_iface);
+
list_del(&sna_output->link);
free(sna_output);