summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/sna/sna.h5
-rw-r--r--src/sna/sna_display.c149
2 files changed, 150 insertions, 4 deletions
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 7845cd11..0739f7b0 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -298,6 +298,11 @@ struct sna {
unsigned serial;
uint32_t *encoders;
+
+#if HAVE_UDEV
+ struct udev_monitor *backlight_monitor;
+ pointer backlight_handler;
+#endif
} mode;
struct {
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 2dbe3f34..c6bb9cd8 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -399,6 +399,129 @@ static void gem_close(int fd, uint32_t handle)
#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT"
static Atom backlight_atom, backlight_deprecated_atom;
+#if HAVE_UDEV
+static void
+sna_backlight_uevent(int fd, void *closure)
+{
+ struct sna *sna = closure;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
+ int i;
+
+ DBG(("%s()\n", __FUNCTION__));
+
+ /* Drain the event queue */
+ do {
+ struct udev_device *dev;
+
+ dev = udev_monitor_receive_device(sna->mode.backlight_monitor);
+ if (dev == NULL)
+ break;
+
+ udev_device_unref(dev);
+ } while (1);
+
+ /* Query all backlights for any changes */
+ for (i = 0; i < sna->mode.num_real_output; i++) {
+ xf86OutputPtr output = config->output[i];
+ struct sna_output *sna_output = to_sna_output(output);
+ int val;
+
+ if (sna_output->dpms_mode != DPMSModeOn)
+ continue;
+
+ assert(output->randr_output);
+
+ val = backlight_get(&sna_output->backlight);
+ if (val < 0)
+ continue;
+ DBG(("%s(%s): backlight '%s' was %d, now %d\n",
+ __FUNCTION__, output->name, sna_output->backlight.iface,
+ sna_output->backlight_active_level, val));
+
+ if (val == sna_output->backlight_active_level)
+ continue;
+
+ sna_output->backlight_active_level = val;
+
+ DBG(("%s(%s): sending change notification\n", __FUNCTION__, output->name));
+ RRChangeOutputProperty(output->randr_output,
+ backlight_atom, XA_INTEGER,
+ 32, PropModeReplace, 1, &val,
+ TRUE, FALSE);
+ RRChangeOutputProperty(output->randr_output,
+ backlight_deprecated_atom, XA_INTEGER,
+ 32, PropModeReplace, 1, &val,
+ TRUE, FALSE);
+ }
+}
+
+static void sna_backlight_pre_init(struct sna *sna)
+{
+ struct udev *u;
+ struct udev_monitor *mon;
+
+ u = udev_new();
+ if (!u)
+ return;
+
+ mon = udev_monitor_new_from_netlink(u, "udev");
+ if (!mon)
+ goto free_udev;
+
+ if (udev_monitor_filter_add_match_subsystem_devtype(mon, "backlight", NULL))
+ goto free_monitor;
+
+ if (udev_monitor_enable_receiving(mon))
+ goto free_monitor;
+
+ sna->mode.backlight_handler =
+ xf86AddGeneralHandler(udev_monitor_get_fd(mon),
+ sna_backlight_uevent, sna);
+ if (!sna->mode.backlight_handler)
+ goto free_monitor;
+
+ DBG(("%s: installed backlight monitor\n", __FUNCTION__));
+ sna->mode.backlight_monitor = mon;
+
+ return;
+
+free_monitor:
+ udev_monitor_unref(mon);
+free_udev:
+ udev_unref(u);
+}
+
+static void sna_backlight_drain_uevents(struct sna *sna)
+{
+ if (sna->mode.backlight_monitor == NULL)
+ return;
+
+ sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
+ sna);
+}
+
+static void sna_backlight_close(struct sna *sna)
+{
+ struct udev *u;
+
+ if (sna->mode.backlight_handler == NULL)
+ return;
+
+ xf86RemoveGeneralHandler(sna->mode.backlight_handler);
+
+ u = udev_monitor_get_udev(sna->mode.backlight_monitor);
+ udev_monitor_unref(sna->mode.backlight_monitor);
+ udev_unref(u);
+
+ sna->mode.backlight_handler = NULL;
+ sna->mode.backlight_monitor = NULL;
+}
+#else
+static void sna_backlight_pre_init(struct sna *sna) { }
+static void sna_backlight_drain_uevents(struct sna *sna) { }
+static void sna_backlight_close(struct sna *sna) { }
+#endif
+
static void
sna_output_backlight_set(xf86OutputPtr output, int level)
{
@@ -417,6 +540,12 @@ sna_output_backlight_set(xf86OutputPtr output, int level)
RRDeleteOutputProperty(output->randr_output, backlight_deprecated_atom);
}
}
+
+ /* Consume the uevent notification now so that we don't misconstrue
+ * the change latter when we wake up and the output is in a different
+ * state.
+ */
+ sna_backlight_drain_uevents(to_sna(output->scrn));
}
static int
@@ -820,6 +949,14 @@ sna_crtc_apply(xf86CrtcPtr crtc)
for (i = 0; i < config->num_output; i++) {
xf86OutputPtr output = config->output[i];
+ /* Make sure we mark the output as off (and save the backlight)
+ * before the kernel turns it off due to changing the pipe.
+ * This is necessary as the kernel may turn off the backlight
+ * and we lose track of the user settings.
+ */
+ if (output->crtc == NULL)
+ output->funcs->dpms(output, DPMSModeOff);
+
if (output->crtc != crtc)
continue;
@@ -2374,6 +2511,7 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
{
struct sna *sna = to_sna(output->scrn);
struct sna_output *sna_output = output->driver_private;
+ int old_dpms = sna_output->dpms_mode;
DBG(("%s(%s:%d): dpms=%d (current: %d), active? %d\n",
__FUNCTION__, output->name, sna_output->id,
@@ -2383,7 +2521,7 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
if (!sna_output->id)
return;
- if (sna_output->dpms_mode == dpms)
+ if (old_dpms == dpms)
return;
/* Record the value of the backlight before turning
@@ -2394,11 +2532,12 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
* and reapply it afterwards.
*/
if (sna_output->backlight.iface && dpms != DPMSModeOn) {
- if (sna_output->dpms_mode == DPMSModeOn) {
+ if (old_dpms == DPMSModeOn) {
sna_output->backlight_active_level = sna_output_backlight_get(output);
DBG(("%s: saving current backlight %d\n",
__FUNCTION__, sna_output->backlight_active_level));
}
+ sna_output->dpms_mode = dpms;
sna_output_backlight_set(output, 0);
}
@@ -2407,7 +2546,7 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
sna_output->id,
sna_output->dpms_id,
dpms))
- dpms = sna_output->dpms_mode;
+ dpms = old_dpms;
if (sna_output->backlight.iface && dpms == DPMSModeOn) {
DBG(("%s: restoring previous backlight %d\n",
@@ -2577,9 +2716,9 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
if (val < 0 || val > sna_output->backlight.max)
return FALSE;
+ sna_output->backlight_active_level = val;
if (sna_output->dpms_mode == DPMSModeOn)
sna_output_backlight_set(output, val);
- sna_output->backlight_active_level = val;
return TRUE;
}
@@ -4736,6 +4875,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
drmModeFreeResources(res);
sna_cursor_pre_init(sna);
+ sna_backlight_pre_init(sna);
} else {
if (num_fake == 0)
num_fake = 1;
@@ -4772,6 +4912,7 @@ sna_mode_close(struct sna *sna)
if (sna->flags & SNA_IS_HOSTED)
return;
+ sna_backlight_close(sna);
sna_cursor_close(sna);
for (i = 0; i < sna->mode.num_real_crtc; i++)