[Nouveau] [PATCH] drmmode: Add backlight support
Daniel Stone
daniel at fooishbar.org
Wed Aug 4 22:46:41 PDT 2010
Straight port of Matthias Hopf's KMS backlight code for
xf86-video-intel, with reformatting and a couple of minor cleanups.
Works fine on my MacBookAir2,1.
Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
src/drmmode_display.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 268 insertions(+), 1 deletions(-)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 9b5d52d..7c3c250 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -35,13 +35,30 @@
#include "nv_include.h"
#include "xf86drmMode.h"
-#include "X11/Xatom.h"
+#include <X11/Xatom.h>
+#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef HAVE_LIBUDEV
#include "libudev.h"
#endif
+
+#define BACKLIGHT_NAME "Backlight"
+#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT"
+#define BACKLIGHT_CLASS "/sys/class/backlight"
+
+/* List of available kernel interfaces in priority order */
+static char *backlight_interfaces[] = {
+ "nv_backlight",
+ NULL,
+};
+/* Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table +
+ * '/' + "max_backlight" */
+#define BACKLIGHT_PATH_LEN 48
+/* Enough for 10 digits of backlight + '\n' + '\0' */
+#define BACKLIGHT_VALUE_LEN 12
+
typedef struct {
int fd;
uint32_t fb_id;
@@ -51,6 +68,7 @@ typedef struct {
struct udev_monitor *uevent_monitor;
InputHandlerProc uevent_handler;
#endif
+ Atom backlight_atom, backlight_deprecated_atom;
} drmmode_rec, *drmmode_ptr;
typedef struct {
@@ -81,6 +99,10 @@ typedef struct {
drmModePropertyBlobPtr edid_blob;
int num_props;
drmmode_prop_ptr props;
+ char *backlight_iface;
+ int32_t backlight_active_level;
+ int32_t backlight_max;
+ int dpms_mode;
} drmmode_output_private_rec, *drmmode_output_private_ptr;
static void drmmode_output_dpms(xf86OutputPtr output, int mode);
@@ -160,6 +182,155 @@ drmmode_ConvertToKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode,
}
static void
+drmmode_backlight_set(xf86OutputPtr output, int level)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ int fd, len, ret;
+
+ if (level > drmmode_output->backlight_max)
+ level = drmmode_output->backlight_max;
+ if (!drmmode_output->backlight_iface || level < 0)
+ return;
+
+ len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
+ sprintf(path, "%s/%s/brightness",
+ BACKLIGHT_CLASS, drmmode_output->backlight_iface);
+ fd = open(path, O_RDWR);
+ if (fd == -1) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "failed to open %s for backlight control: %s\n",
+ path, strerror(errno));
+ return;
+ }
+
+ ret = write(fd, val, len);
+ if (ret == -1) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "write to %s for backlight control failed: %s\n",
+ path, strerror(errno));
+ }
+
+ close(fd);
+}
+
+static int
+drmmode_backlight_get(xf86OutputPtr output)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ int fd, level;
+
+ if (!drmmode_output->backlight_iface)
+ return -1;
+
+ sprintf(path, "%s/%s/actual_brightness",
+ BACKLIGHT_CLASS, drmmode_output->backlight_iface);
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "failed to open %s for backlight control: %s\n",
+ path, strerror(errno));
+ return -1;
+ }
+
+ memset(val, 0, sizeof(val));
+ if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ level = atoi(val);
+ if (level > drmmode_output->backlight_max)
+ level = drmmode_output->backlight_max;
+ if (level < 0)
+ level = -1;
+
+ return level;
+}
+
+static int
+drmmode_backlight_get_max(xf86OutputPtr output)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN];
+ int fd, max = 0;
+
+ sprintf(path, "%s/%s/max_brightness",
+ BACKLIGHT_CLASS, drmmode_output->backlight_iface);
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "failed to open %s for backlight control: %s\n",
+ path, strerror(errno));
+ return 0;
+ }
+
+ memset(val, 0, sizeof(val));
+ if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ max = atoi(val);
+ if (max <= 0)
+ max = -1;
+
+ return max;
+}
+
+static void
+drmmode_backlight_init(xf86OutputPtr output)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+ char path[BACKLIGHT_PATH_LEN];
+ struct stat buf;
+ int i;
+
+ for (i = 0; backlight_interfaces[i] != NULL; i++) {
+ sprintf(path, "%s/%s", BACKLIGHT_CLASS,
+ backlight_interfaces[i]);
+ if (stat(path, &buf))
+ continue;
+
+ drmmode_output->backlight_iface = backlight_interfaces[i];
+ xf86DrvMsg(output->scrn->scrnIndex, X_INFO,
+ "found backlight control interface %s\n", path);
+ drmmode_output->backlight_max = drmmode_backlight_get_max(output);
+ drmmode_output->backlight_active_level = drmmode_backlight_get(output);
+ return;
+ }
+ drmmode_output->backlight_iface = NULL;
+}
+
+static void
+drmmode_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode)
+{
+ drmmode_output_private_ptr drmmode_output = output->driver_private;
+
+ if (!drmmode_output->backlight_iface)
+ return;
+
+ if (mode == DPMSModeOn) {
+ /* If we're going from off->on we may need to turn on the
+ * backlight. */
+ if (oldmode != DPMSModeOn)
+ drmmode_backlight_set(output,
+ drmmode_output->backlight_active_level);
+ } else {
+ /* Only save the current backlight value if we're going from on
+ * to off. */
+ if (oldmode == DPMSModeOn)
+ drmmode_output->backlight_active_level = drmmode_backlight_get(output);
+ drmmode_backlight_set(output, 0);
+ }
+}
+
+static void
drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode)
{
@@ -648,6 +819,9 @@ drmmode_output_destroy(xf86OutputPtr output)
drmModeFreeProperty(drmmode_output->props[i].mode_prop);
free(drmmode_output->props[i].atoms);
}
+ if (drmmode_output->backlight_iface)
+ drmmode_backlight_set(output,
+ drmmode_output->backlight_active_level);
drmModeFreeConnector(drmmode_output->mode_output);
free(drmmode_output);
output->driver_private = NULL;
@@ -679,6 +853,8 @@ drmmode_output_dpms(xf86OutputPtr output, int mode)
drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
mode_id, mode);
+ drmmode_output_dpms_backlight(output, drmmode_output->dpms_mode, mode);
+ drmmode_output->dpms_mode = mode;
}
static Bool
@@ -711,6 +887,48 @@ drmmode_output_create_resources(xf86OutputPtr output)
if (!drmmode_output->props)
return;
+ if (drmmode_output->backlight_iface) {
+ int32_t data, backlight_range[2];
+
+ backlight_range[0] = 0;
+ backlight_range[1] = drmmode_output->backlight_max;
+ err = RRConfigureOutputProperty(output->randr_output,
+ drmmode->backlight_atom,
+ FALSE, TRUE, FALSE, 2,
+ backlight_range);
+ if (err != 0)
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error, %d\n",
+ err);
+
+ err = RRConfigureOutputProperty(output->randr_output,
+ drmmode->backlight_deprecated_atom,
+ FALSE, TRUE, FALSE, 2, backlight_range);
+ if (err != 0)
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "RRConfigureOutputProperty error, %d\n",
+ err);
+
+ /* Set the current value of the backlight property */
+ data = drmmode_output->backlight_active_level;
+ err = RRChangeOutputProperty(output->randr_output,
+ drmmode->backlight_atom,
+ XA_INTEGER, 32, PropModeReplace,
+ 1, &data, FALSE, TRUE);
+ if (err != 0)
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+
+ err = RRChangeOutputProperty(output->randr_output,
+ drmmode->backlight_deprecated_atom,
+ XA_INTEGER, 32, PropModeReplace,
+ 1, &data, FALSE, TRUE);
+ if (err != 0)
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+ }
+
+
drmmode_output->num_props = 0;
for (i = 0, j = 0; i < mode_output->count_props; i++) {
drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
@@ -795,6 +1013,24 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property,
drmmode_ptr drmmode = drmmode_output->drmmode;
int i, ret;
+ if (property == drmmode->backlight_atom ||
+ property == drmmode->backlight_deprecated_atom) {
+ int32_t val;
+
+ if (value->type != XA_INTEGER || value->format != 32 ||
+ value->size != 1)
+ return FALSE;
+
+ val = *(int32_t *)value->data;
+ if (val < 0 || val > drmmode_output->backlight_max)
+ return FALSE;
+
+ if (drmmode_output->dpms_mode == DPMSModeOn)
+ drmmode_backlight_set(output, val);
+ drmmode_output->backlight_active_level = val;
+ return TRUE;
+ }
+
for (i = 0; i < drmmode_output->num_props; i++) {
drmmode_prop_ptr p = &drmmode_output->props[i];
@@ -864,6 +1100,27 @@ drmmode_output_get_property(xf86OutputPtr output, Atom property)
drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
}
+ if (property == drmmode->backlight_atom ||
+ property == drmmode->backlight_deprecated_atom) {
+ int32_t val;
+ if (!drmmode_output->backlight_iface)
+ return FALSE;
+
+ val = drmmode_backlight_get(output);
+ if (val < 0)
+ return FALSE;
+ err = RRChangeOutputProperty(output->randr_output, property,
+ XA_INTEGER, 32, PropModeReplace,
+ 1, &val, FALSE, TRUE);
+ if (err != 0) {
+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
+ "RRChangeOutputProperty error, %d\n", err);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
for (i = 0; i < drmmode_output->num_props; i++) {
drmmode_prop_ptr p = &drmmode_output->props[i];
if (p->atoms[0] != property)
@@ -993,6 +1250,9 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
output->interlaceAllowed = true;
output->doubleScanAllowed = true;
+ if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS)
+ drmmode_backlight_init(output);
+
return;
}
@@ -1116,6 +1376,13 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp)
if (!drmmode->mode_res)
return FALSE;
+ drmmode->backlight_atom = MakeAtom(BACKLIGHT_NAME,
+ sizeof(BACKLIGHT_NAME) - 1,
+ TRUE);
+ drmmode->backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME,
+ sizeof(BACKLIGHT_DEPRECATED_NAME) - 1,
+ TRUE);
+
xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width,
drmmode->mode_res->max_height);
for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
--
1.7.1
More information about the Nouveau
mailing list