compositor-drm: Just pull in libbacklight source for now
authorKristian Høgsberg <krh@bitplanet.net>
Wed, 29 Feb 2012 19:23:51 +0000 (14:23 -0500)
committerKristian Høgsberg <krh@bitplanet.net>
Wed, 29 Feb 2012 19:23:51 +0000 (14:23 -0500)
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.

configure.ac
src/Makefile.am
src/libbacklight.c [new file with mode: 0644]
src/libbacklight.h [new file with mode: 0644]

index 6b54bb3..ba42a04 100644 (file)
@@ -73,7 +73,7 @@ AC_ARG_ENABLE(drm-compositor, [  --enable-drm-compositor],,
 AM_CONDITIONAL(ENABLE_DRM_COMPOSITOR, test x$enable_drm_compositor = xyes)
 if test x$enable_drm_compositor = xyes; then
   AC_DEFINE([BUILD_DRM_COMPOSITOR], [1], [Build the DRM compositor])
-  PKG_CHECK_MODULES(DRM_COMPOSITOR, [libbacklight libudev >= 136 libdrm >= 2.4.30 gbm])
+  PKG_CHECK_MODULES(DRM_COMPOSITOR, [libudev >= 136 libdrm >= 2.4.30 gbm])
 fi
 
 
index 5788df3..f1003f7 100644 (file)
@@ -61,7 +61,13 @@ drm_backend = drm-backend.la
 drm_backend_la_LDFLAGS = -module -avoid-version
 drm_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(DRM_COMPOSITOR_LIBS)
 drm_backend_la_CFLAGS = $(DRM_COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
-drm_backend_la_SOURCES = compositor-drm.c tty.c evdev.c evdev.h
+drm_backend_la_SOURCES =                       \
+       compositor-drm.c                        \
+       tty.c                                   \
+       evdev.c                                 \
+       evdev.h                                 \
+       libbacklight.c                          \
+       libbacklight.h
 endif
 
 if ENABLE_WAYLAND_COMPOSITOR
diff --git a/src/libbacklight.c b/src/libbacklight.c
new file mode 100644 (file)
index 0000000..b2e19bf
--- /dev/null
@@ -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;
+}
diff --git a/src/libbacklight.h b/src/libbacklight.h
new file mode 100644 (file)
index 0000000..cea34c2
--- /dev/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 */