From 696a73c8b50a4101133a48bd4a015e59455944c4 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 5 Jun 2014 22:43:37 +0100 Subject: [PATCH] sna: Hook up a backlight udev monitor for external changes Changes to the backlights are notified through uevents. Hooking up a udev monitor to listen out for external changes to the backlight (e.g. through ACPI function keys, or by the user writing to /sys/class/backlight directly) is easier than enabling polling on the backlight sysfs file using X's select() mechanism. Reported-by: Alexander Mezin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=79699 Signed-off-by: Chris Wilson --- src/sna/sna.h | 5 +++ src/sna/sna_display.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/src/sna/sna.h b/src/sna/sna.h index 7845cd1..0739f7b 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 3453c95..b67f8eb 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -4790,6 +4790,119 @@ sna_crtc_config_notify(ScreenPtr screen) #define sna_setup_provider(scrn) #endif +#if HAVE_UDEV +static void +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), + 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_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_close(struct sna *sna) { } +#endif + bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna) { drmModeResPtr res; @@ -4849,6 +4962,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; @@ -4885,6 +4999,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++) -- 1.7.9.5