From b10ab1a86f35ab793ba6efb49224d9ecdd1b7dbd Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 9 Dec 2014 09:36:42 -0500 Subject: [PATCH] ecore-drm: added drm launcher that is allow to determine whether to launch with logind or root privilege. Summary: - allow to launch drm backend without systemd-logind with root privilege. - allow to open drm device node via logind, not directly open it, in case exist systemd-logind. - fixes issue that couldn't switch session, because ecore-drm couldn't drop master to drm device with no permission. (allow to switch session appropriate.) Reviewers: gwanglim, devilhorns Subscribers: torori, cedric Differential Revision: https://phab.enlightenment.org/D1704 --- configure.ac | 9 +- src/Makefile_Ecore_Drm.am | 9 +- src/lib/ecore_drm/Ecore_Drm.h | 2 + src/lib/ecore_drm/ecore_drm.c | 16 - src/lib/ecore_drm/ecore_drm_dbus.c | 88 +++-- src/lib/ecore_drm/ecore_drm_device.c | 5 +- src/lib/ecore_drm/ecore_drm_inputs.c | 24 +- src/lib/ecore_drm/ecore_drm_launcher.c | 139 ++++++++ src/lib/ecore_drm/ecore_drm_logind.c | 310 ++++++++++++++++++ src/lib/ecore_drm/ecore_drm_logind.h | 55 ++++ src/lib/ecore_drm/ecore_drm_private.h | 10 +- .../ecore_evas/engines/drm/ecore_evas_drm.c | 19 +- 12 files changed, 607 insertions(+), 79 deletions(-) create mode 100644 src/lib/ecore_drm/ecore_drm_launcher.c create mode 100644 src/lib/ecore_drm/ecore_drm_logind.c create mode 100644 src/lib/ecore_drm/ecore_drm_logind.h diff --git a/configure.ac b/configure.ac index e09213d417..5911192a5e 100644 --- a/configure.ac +++ b/configure.ac @@ -673,13 +673,18 @@ fi AM_CONDITIONAL([HAVE_SYSTEMD_USER_SESSION], [test "x${have_systemd_user_session}" = "xyes"]) AC_SUBST([USER_SESSION_DIR]) - if test "x${have_systemd_pkg}" = "xauto" -o "x${have_systemd_pkg}" = "xyes"; then PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon >= 192 libsystemd-journal >= 192], [have_systemd_pkg="yes"], [have_systemd_pkg="no"]) fi +PKG_CHECK_MODULES(SYSTEMD_LOGIN, [libsystemd-login >= 198], + [have_systemd_login=yes], [have_systemd_login=no]) +AS_IF([test "x$have_systemd_login" = "xyes"], + [AC_DEFINE([HAVE_SYSTEMD_LOGIN], [1], [Have systemd-login])]) +AM_CONDITIONAL(HAVE_SYSTEMD_LOGIN, test "x$have_systemd_login" = "xyes") + # check for systemd library if requested if test "x${want_systemd}" = "xyes" -a "x${have_systemd_pkg}" = "xno"; then AC_MSG_ERROR([Systemd dependencie requested but not found]) @@ -3072,7 +3077,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eeze]) EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eo]) EFL_INTERNAL_DEPEND_PKG([ECORE_DRM], [eina]) -EFL_DEPEND_PKG([ECORE_DRM], [DRM], [libdrm >= 2.4 xkbcommon >= 0.3.0 libsystemd-login >= 192 gbm]) +EFL_DEPEND_PKG([ECORE_DRM], [DRM], [libdrm >= 2.4 xkbcommon >= 0.3.0 gbm]) EFL_EVAL_PKGS([ECORE_DRM]) diff --git a/src/Makefile_Ecore_Drm.am b/src/Makefile_Ecore_Drm.am index 8867f37d69..b5582778a9 100644 --- a/src/Makefile_Ecore_Drm.am +++ b/src/Makefile_Ecore_Drm.am @@ -16,10 +16,17 @@ lib/ecore_drm/ecore_drm_inputs.c \ lib/ecore_drm/ecore_drm_output.c \ lib/ecore_drm/ecore_drm_tty.c \ lib/ecore_drm/ecore_drm_device.c \ -lib/ecore_drm/ecore_drm_dbus.c \ +lib/ecore_drm/ecore_drm_launcher.c \ lib/ecore_drm/ecore_drm.c \ +lib/ecore_drm/ecore_drm_logind.h \ lib/ecore_drm/ecore_drm_private.h +if HAVE_SYSTEMD_LOGIN +lib_ecore_drm_libecore_drm_la_SOURCES += \ +lib/ecore_drm/ecore_drm_logind.c \ +lib/ecore_drm/ecore_drm_dbus.c +endif + lib_ecore_drm_libecore_drm_la_CPPFLAGS = \ -I$(top_builddir)/src/lib/efl \ @ECORE_DRM_CFLAGS@ \ diff --git a/src/lib/ecore_drm/Ecore_Drm.h b/src/lib/ecore_drm/Ecore_Drm.h index 80efaf5574..3238a20adf 100644 --- a/src/lib/ecore_drm/Ecore_Drm.h +++ b/src/lib/ecore_drm/Ecore_Drm.h @@ -194,4 +194,6 @@ EAPI Eina_Bool ecore_drm_sprites_crtc_supported(Ecore_Drm_Output *output, unsign EAPI Ecore_Drm_Fb *ecore_drm_fb_create(Ecore_Drm_Device *dev, int width, int height); EAPI void ecore_drm_fb_destroy(Ecore_Drm_Fb *fb); +EAPI Eina_Bool ecore_drm_launcher_connect(Ecore_Drm_Device *dev); +EAPI void ecore_drm_launcher_disconnect(Ecore_Drm_Device *dev); #endif diff --git a/src/lib/ecore_drm/ecore_drm.c b/src/lib/ecore_drm/ecore_drm.c index c341c197d2..6413270a08 100644 --- a/src/lib/ecore_drm/ecore_drm.c +++ b/src/lib/ecore_drm/ecore_drm.c @@ -6,7 +6,6 @@ /* local variables */ static int _ecore_drm_init_count = 0; -static char *sid; /* external variables */ int _ecore_drm_log_dom = -1; @@ -65,12 +64,6 @@ ecore_drm_init(void) if (!eina_log_domain_level_check(_ecore_drm_log_dom, EINA_LOG_LEVEL_DBG)) eina_log_domain_level_set("ecore_drm", EINA_LOG_LEVEL_DBG); - /* get sd-login properties we need */ - if (sd_pid_get_session(getpid(), &sid) < 0) goto sd_err; - - /* try to init dbus */ - if (!_ecore_drm_dbus_init(sid)) goto dbus_err; - /* try to init eeze */ if (!eeze_init()) goto eeze_err; @@ -78,10 +71,6 @@ ecore_drm_init(void) return _ecore_drm_init_count; eeze_err: - _ecore_drm_dbus_shutdown(); -dbus_err: - free(sid); -sd_err: eina_log_domain_unregister(_ecore_drm_log_dom); _ecore_drm_log_dom = -1; log_err: @@ -115,9 +104,6 @@ ecore_drm_shutdown(void) /* close eeze */ eeze_shutdown(); - /* cleanup dbus */ - _ecore_drm_dbus_shutdown(); - /* shutdown ecore_event */ ecore_event_shutdown(); @@ -131,8 +117,6 @@ ecore_drm_shutdown(void) /* shutdown eina */ eina_shutdown(); - free(sid); - /* return init count */ return _ecore_drm_init_count; } diff --git a/src/lib/ecore_drm/ecore_drm_dbus.c b/src/lib/ecore_drm/ecore_drm_dbus.c index 222b5e9a2c..bfac33f31b 100644 --- a/src/lib/ecore_drm/ecore_drm_dbus.c +++ b/src/lib/ecore_drm/ecore_drm_dbus.c @@ -175,7 +175,7 @@ _ecore_drm_dbus_session_release(const char *session) return EINA_TRUE; } -static void +void _ecore_drm_dbus_device_release(uint32_t major, uint32_t minor) { Eldbus_Proxy *proxy; @@ -199,11 +199,35 @@ _ecore_drm_dbus_device_release(uint32_t major, uint32_t minor) eldbus_proxy_send(proxy, msg, NULL, NULL, -1); } -static int -_ecore_drm_dbus_device_take(uint32_t major, uint32_t minor, Eldbus_Message_Cb callback, const void *data) +static void +_cb_device_taken(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + const char *errname, *errmsg; + Ecore_Drm_Open_Cb callback = NULL; + Eina_Bool b = EINA_FALSE; + int fd = -1; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + goto eldbus_err; + } + + /* DBUS_TYPE_UNIX_FD == 'h' */ + if (!eldbus_message_arguments_get(msg, "hb", &fd, &b)) + ERR("\tCould not get UNIX_FD from eldbus message: %d %d", fd, b); + +eldbus_err: + callback = (Ecore_Drm_Open_Cb)eldbus_pending_data_del(pending, "callback"); + if (callback) callback(data, fd, b); +} + +int +_ecore_drm_dbus_device_take(uint32_t major, uint32_t minor, Ecore_Drm_Open_Cb callback, void *data) { Eldbus_Proxy *proxy; Eldbus_Message *msg; + Eldbus_Pending *pending; /* try to get the Session proxy */ if (!(proxy = eldbus_proxy_get(dobj, "org.freedesktop.login1.Session"))) @@ -219,11 +243,45 @@ _ecore_drm_dbus_device_take(uint32_t major, uint32_t minor, Eldbus_Message_Cb ca } eldbus_message_arguments_append(msg, "uu", major, minor); - eldbus_proxy_send(proxy, msg, callback, data, -1); + pending = eldbus_proxy_send(proxy, msg, _cb_device_taken, data, -1); + if (callback) eldbus_pending_data_set(pending, "callback", callback); return 1; } +int +_ecore_drm_dbus_device_take_no_pending(uint32_t major, uint32_t minor, Eina_Bool *paused_out, double timeout) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg, *reply; + Eina_Bool b; + int fd; + + /* try to get the Session proxy */ + if (!(proxy = eldbus_proxy_get(dobj, "org.freedesktop.login1.Session"))) + { + ERR("Could not get eldbus session proxy"); + return -1; + } + + if (!(msg = eldbus_proxy_method_call_new(proxy, "TakeDevice"))) + { + ERR("Could not create method call for proxy"); + return -1; + } + + if (!eldbus_message_arguments_append(msg, "uu", major, minor)) + return -1; + + reply = eldbus_proxy_send_and_block(proxy, msg, timeout); + + if (!eldbus_message_arguments_get(reply, "hb", &fd, &b)) + return -1; + + if (paused_out) *paused_out = b; + return fd; +} + int _ecore_drm_dbus_init(const char *session) { @@ -343,25 +401,3 @@ _ecore_drm_dbus_shutdown(void) return _dbus_init_count; } - -void -_ecore_drm_dbus_device_open(const char *device, Eldbus_Message_Cb callback, const void *data) -{ - struct stat st; - - if (stat(device, &st) < 0) return; - if (!S_ISCHR(st.st_mode)) return; - - _ecore_drm_dbus_device_take(major(st.st_rdev), minor(st.st_rdev), callback, data); -} - -void -_ecore_drm_dbus_device_close(const char *device) -{ - struct stat st; - - if (stat(device, &st) < 0) return; - if (!S_ISCHR(st.st_mode)) return; - - _ecore_drm_dbus_device_release(major(st.st_rdev), minor(st.st_rdev)); -} diff --git a/src/lib/ecore_drm/ecore_drm_device.c b/src/lib/ecore_drm/ecore_drm_device.c index e8ca0521fa..957c439e03 100644 --- a/src/lib/ecore_drm/ecore_drm_device.c +++ b/src/lib/ecore_drm/ecore_drm_device.c @@ -254,7 +254,8 @@ ecore_drm_device_open(Ecore_Drm_Device *dev) /* check for valid device */ if ((!dev) || (!dev->drm.name)) return EINA_FALSE; - dev->drm.fd = open(dev->drm.name, O_RDWR | O_CLOEXEC); + /* DRM device node is needed immediately to keep going. */ + dev->drm.fd = _ecore_drm_launcher_device_open_no_pending(dev->drm.name, O_RDWR); if (dev->drm.fd < 0) return EINA_FALSE; DBG("Opened Device %s : %d", dev->drm.name, dev->drm.fd); @@ -319,7 +320,7 @@ ecore_drm_device_close(Ecore_Drm_Device *dev) if (dev->drm.hdlr) ecore_main_fd_handler_del(dev->drm.hdlr); dev->drm.hdlr = NULL; - close(dev->drm.fd); + _ecore_drm_launcher_device_close(dev->drm.name, dev->drm.fd); /* reset device fd */ dev->drm.fd = -1; diff --git a/src/lib/ecore_drm/ecore_drm_inputs.c b/src/lib/ecore_drm/ecore_drm_inputs.c index f03af36cca..a1ca008d80 100644 --- a/src/lib/ecore_drm/ecore_drm_inputs.c +++ b/src/lib/ecore_drm/ecore_drm_inputs.c @@ -57,29 +57,18 @@ flag_err: } static void -_cb_device_opened(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) +_cb_device_opened(void *data, int fd, Eina_Bool paused EINA_UNUSED) { Ecore_Drm_Device_Open_Data *d; Ecore_Drm_Evdev *edev; Eina_Bool b = EINA_FALSE; - const char *errname, *errmsg; - int fd = -1; if (!(d = data)) return; - if (eldbus_message_error_get(msg, &errname, &errmsg)) - { - ERR("Eldbus Message Error: %s %s", errname, errmsg); - ERR("\tFailed to open device: %s", d->node); - return; - } - - /* DBG("Input Device Opened: %s", d->node); */ - - /* DBUS_TYPE_UNIX_FD == 'h' */ - if (!eldbus_message_arguments_get(msg, "hb", &fd, &b)) + if (fd < 0) { ERR("\tCould not get UNIX_FD from eldbus message: %d %d", fd, b); + ERR("\tFailed to open device: %s", d->node); goto cleanup; } @@ -100,7 +89,7 @@ _cb_device_opened(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending goto cleanup; release: - _ecore_drm_dbus_device_close(d->node); + _ecore_drm_launcher_device_close(d->node, fd); cleanup: eina_stringshare_del(d->node); free(d); @@ -162,7 +151,8 @@ _device_add(Ecore_Drm_Input *input, const char *device) DBG("\tDevice Path: %s", data->node); - _ecore_drm_dbus_device_open(data->node, _cb_device_opened, data); + if (!_ecore_drm_launcher_device_open(data->node, _cb_device_opened, data, O_RDWR | O_NONBLOCK)) + goto dev_err; return EINA_TRUE; @@ -311,7 +301,7 @@ ecore_drm_inputs_destroy(Ecore_Drm_Device *dev) EINA_LIST_FREE(seat->devices, edev) { - _ecore_drm_dbus_device_close(edev->path); + _ecore_drm_launcher_device_close(edev->path, edev->fd); _ecore_drm_evdev_device_destroy(edev); } } diff --git a/src/lib/ecore_drm/ecore_drm_launcher.c b/src/lib/ecore_drm/ecore_drm_launcher.c new file mode 100644 index 0000000000..e2d64d580b --- /dev/null +++ b/src/lib/ecore_drm/ecore_drm_launcher.c @@ -0,0 +1,139 @@ +#include "ecore_drm_private.h" +#include "ecore_drm_logind.h" + +static Eina_Bool logind = EINA_FALSE; + +EAPI Eina_Bool +ecore_drm_launcher_connect(Ecore_Drm_Device *dev) +{ + if (!(logind = _ecore_drm_logind_connect(dev))) + { + DBG("Launcher: Not Support loignd\n"); + if (geteuid() == 0) + { + DBG("Launcher: Try to keep going with root privilege\n"); + if (!ecore_drm_tty_open(dev, NULL)) + { + ERR("Launcher: failed to open tty with root privilege\n"); + return EINA_FALSE; + } + } + else + { + ERR("Launcher: Need Root Privilege or logind\n"); + return EINA_FALSE; + } + } + DBG("Launcher: Success Connect\n"); + + return EINA_TRUE; +} + +EAPI void +ecore_drm_launcher_disconnect(Ecore_Drm_Device *dev) +{ + if (logind) + { + logind = EINA_FALSE; + _ecore_drm_logind_disconnect(dev); + } + else + { + ecore_drm_tty_close(dev); + } +} + +static int +_device_flags_set(int fd, int flags) +{ + int fl; + + fl = fcntl(fd, F_GETFL); + if (fl < 0) + return -1; + + if (flags & O_NONBLOCK) + fl |= O_NONBLOCK; + + if (fcntl(fd, F_SETFL, fl) < 0) + return -1; + + fl = fcntl(fd, F_GETFD); + if (fl < 0) + return -1; + + if (!(flags & O_CLOEXEC)) + fl &= ~FD_CLOEXEC; + + if (fcntl(fd, F_SETFD, fl) < 0) + return -1; + + return fd; +} + +Eina_Bool +_ecore_drm_launcher_device_open(const char *device, Ecore_Drm_Open_Cb callback, void *data, int flags) +{ + int fd = -1; + struct stat s; + + if (logind) + { + if (!_ecore_drm_logind_device_open(device, callback, data)) + return EINA_FALSE; + } + else + { + fd = open(device, flags | O_CLOEXEC); + if (fd < 0) return EINA_FALSE; + if (fstat(fd, &s) == -1) + { + close(fd); + fd = -1; + return EINA_FALSE; + } + + callback(data, fd, EINA_FALSE); + } + + return EINA_TRUE; +} + +int +_ecore_drm_launcher_device_open_no_pending(const char *device, int flags) +{ + int fd = -1; + struct stat s; + + if (logind) + { + fd = _ecore_drm_logind_device_open_no_pending(device); + if ((fd = _device_flags_set(fd, flags)) == -1) + { + _ecore_drm_logind_device_close(device); + return -1; + } + } + else + { + fd = open(device, flags, flags | O_CLOEXEC); + if (fd < 0) return fd; + if (fstat(fd, &s) == -1) + { + close(fd); + return -1; + } + } + + DBG("Device opened %s", device); + return fd; +} + +void +_ecore_drm_launcher_device_close(const char *device, int fd) +{ + if (logind) + return _ecore_drm_logind_device_close(device); + + close(fd); +} diff --git a/src/lib/ecore_drm/ecore_drm_logind.c b/src/lib/ecore_drm/ecore_drm_logind.c new file mode 100644 index 0000000000..a3c6c1ef79 --- /dev/null +++ b/src/lib/ecore_drm/ecore_drm_logind.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include "ecore_drm_private.h" +#include "ecore_drm_logind.h" + +#ifndef KDSKBMUTE +# define KDSKBMUTE 0x4B51 +#endif + +static char *sid; + +static Eina_Bool +_ecore_drm_logind_cb_vt_switch(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Drm_Device *dev; + Ecore_Event_Key *ev; + int keycode; + int vt; + + dev = data; + ev = event; + keycode = ev->keycode - 8; + + if ((ev->modifiers & ECORE_EVENT_MODIFIER_CTRL) && + (ev->modifiers & ECORE_EVENT_MODIFIER_ALT) && + (keycode >= KEY_F1) && (keycode <= KEY_F8)) + { + vt = (keycode - KEY_F1 + 1); + + if (ioctl(dev->tty.fd, VT_ACTIVATE, vt) < 0) + ERR("Failed to activate vt: %m"); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_drm_logind_cb_vt_signal(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Drm_Device *dev; + Ecore_Event_Signal_User *ev; + siginfo_t sigdata; + + dev = data; + ev = event; + + sigdata = ev->data; + if (sigdata.si_code != SI_KERNEL) return ECORE_CALLBACK_RENEW; + + if (ev->number == 1) + { + Ecore_Drm_Input *input; + Ecore_Drm_Output *output; + Ecore_Drm_Sprite *sprite; + Eina_List *l; + + /* disable inputs (suspends) */ + EINA_LIST_FOREACH(dev->inputs, l, input) + ecore_drm_inputs_disable(input); + + /* disable hardware cursor */ + EINA_LIST_FOREACH(dev->outputs, l, output) + ecore_drm_output_cursor_size_set(output, 0, 0, 0); + + /* disable sprites */ + EINA_LIST_FOREACH(dev->sprites, l, sprite) + ecore_drm_sprites_fb_set(sprite, 0, 0); + + if (!ecore_drm_tty_release(dev)) + ERR("Could not release VT: %m"); + } + else if (ev->number == 2) + { + if (ecore_drm_tty_acquire(dev)) + { + Ecore_Drm_Output *output; + Ecore_Drm_Input *input; + Eina_List *l; + + /* set output mode */ + EINA_LIST_FOREACH(dev->outputs, l, output) + ecore_drm_output_enable(output); + + /* enable inputs */ + EINA_LIST_FOREACH(dev->inputs, l, input) + ecore_drm_inputs_enable(input); + } + else + ERR("Could not acquire VT: %m"); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_drm_logind_tty_setup(Ecore_Drm_Device *dev) +{ + struct stat st; + int kmode; + struct vt_mode vtmode = { 0 }; + + if (fstat(dev->tty.fd, &st) == -1) + { + ERR("Failed to get stats for tty: %m"); + return EINA_FALSE; + } + + if (ioctl(dev->tty.fd, KDGETMODE, &kmode)) + { + ERR("Could not get tty mode: %m"); + return EINA_FALSE; + } + + if (ioctl(dev->tty.fd, VT_ACTIVATE, minor(st.st_rdev)) < 0) + { + ERR("Failed to activate vt: %m"); + return EINA_FALSE; + } + + if (ioctl(dev->tty.fd, VT_WAITACTIVE, minor(st.st_rdev)) < 0) + { + ERR("Failed to wait active: %m"); + return EINA_FALSE; + } + + /* NB: Don't set this. This Turns OFF keyboard on the VT */ + /* if (ioctl(dev->tty.fd, KDSKBMUTE, 1) && */ + /* ioctl(dev->tty.fd, KDSKBMODE, K_OFF)) */ + /* { */ + /* ERR("Could not set K_OFF keyboard mode: %m"); */ + /* return EINA_FALSE; */ + /* } */ + + if (kmode != KD_GRAPHICS) + { + if (ioctl(dev->tty.fd, KDSETMODE, KD_GRAPHICS)) + { + ERR("Could not set graphics mode: %m"); + goto err_kmode; + } + } + + vtmode.mode = VT_PROCESS; + vtmode.waitv = 0; + vtmode.relsig = SIGUSR1; + vtmode.acqsig = SIGUSR2; + if (ioctl(dev->tty.fd, VT_SETMODE, &vtmode) < 0) + { + ERR("Could not set Terminal Mode: %m"); + goto err_setmode; + } + + return EINA_TRUE; +err_setmode: + ioctl(dev->tty.fd, KDSETMODE, KD_TEXT); +err_kmode: + return EINA_FALSE; +} + + +static Eina_Bool +_ecore_drm_logind_vt_open(Ecore_Drm_Device *dev, const char *name) +{ + char tty[32] = ""; + + /* check for valid device */ + if ((!dev) || (!dev->drm.name)) return EINA_FALSE; + + /* assign default tty fd of -1 */ + dev->tty.fd = -1; + + if (!name) + { + char *env; + + if ((env = getenv("ECORE_DRM_TTY"))) + snprintf(tty, sizeof(tty), "%s", env); + else + dev->tty.fd = dup(STDIN_FILENO); + } + else + snprintf(tty, sizeof(tty), "%s", name); + + if (dev->tty.fd < 0) + { + DBG("Trying to Open Tty: %s", tty); + + dev->tty.fd = open(tty, O_RDWR | O_NOCTTY); + if (dev->tty.fd < 0) + { + DBG("Failed to Open Tty: %m"); + return EINA_FALSE; + } + } + + /* save tty name */ + dev->tty.name = eina_stringshare_add(tty); + + /* FIXME */ + if (!_ecore_drm_logind_tty_setup(dev)) + { + close(dev->tty.fd); + dev->tty.fd = -1; + return EINA_FALSE; + } + + /* setup handler for signals */ + dev->tty.event_hdlr = + ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, + _ecore_drm_logind_cb_vt_signal, dev); + + /* setup handler for key event of vt switch */ + dev->tty.switch_hdlr = + ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, + _ecore_drm_logind_cb_vt_switch, dev); + + /* set current tty into env */ + setenv("ECORE_DRM_TTY", tty, 1); + + return EINA_TRUE; +} + +static void +_ecore_drm_logind_vt_close(Ecore_Drm_Device *dev) +{ + struct vt_mode mode = { 0 }; + + ioctl(dev->tty.fd, KDSETMODE, KD_TEXT); + mode.mode = VT_AUTO; + ioctl(dev->tty.fd, VT_SETMODE, &mode); + + if (dev->tty.event_hdlr) ecore_event_handler_del(dev->tty.event_hdlr); + dev->tty.event_hdlr = NULL; + + if (dev->tty.switch_hdlr) ecore_event_handler_del(dev->tty.switch_hdlr); + dev->tty.switch_hdlr = NULL; + + if (dev->tty.name) eina_stringshare_del(dev->tty.name); + dev->tty.name = NULL; + + unsetenv("ECORE_DRM_TTY"); +} + +Eina_Bool +_ecore_drm_logind_connect(Ecore_Drm_Device *dev) +{ + /* get sd-login properties we need */ + if (sd_pid_get_session(getpid(), &sid) < 0) return EINA_FALSE; + + /* try to init dbus */ + if (!_ecore_drm_dbus_init(sid)) + { + free(sid); + return EINA_FALSE; + } + + if (!_ecore_drm_logind_vt_open(dev, NULL)) + { + free(sid); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +void +_ecore_drm_logind_disconnect(Ecore_Drm_Device *dev) +{ + _ecore_drm_logind_vt_close(dev); + _ecore_drm_dbus_shutdown(); +} + +Eina_Bool +_ecore_drm_logind_device_open(const char *device, Ecore_Drm_Open_Cb callback, void *data) +{ + struct stat st; + + if (stat(device, &st) < 0) return EINA_FALSE; + if (!S_ISCHR(st.st_mode)) return EINA_FALSE; + + if (_ecore_drm_dbus_device_take(major(st.st_rdev), minor(st.st_rdev), callback, data) < 0) + return EINA_FALSE; + + return EINA_TRUE; +} + +int +_ecore_drm_logind_device_open_no_pending(const char *device) +{ + struct stat st; + + if (stat(device, &st) < 0) return EINA_FALSE; + if (!S_ISCHR(st.st_mode)) return EINA_FALSE; + + return _ecore_drm_dbus_device_take_no_pending(major(st.st_rdev), minor(st.st_rdev), NULL, -1); +} + +void +_ecore_drm_logind_device_close(const char *device) +{ + struct stat st; + + if (stat(device, &st) < 0) return; + if (!S_ISCHR(st.st_mode)) return; + + _ecore_drm_dbus_device_release(major(st.st_rdev), minor(st.st_rdev)); +} diff --git a/src/lib/ecore_drm/ecore_drm_logind.h b/src/lib/ecore_drm/ecore_drm_logind.h new file mode 100644 index 0000000000..4315722161 --- /dev/null +++ b/src/lib/ecore_drm/ecore_drm_logind.h @@ -0,0 +1,55 @@ +#ifndef _ECORE_DRM_LOGIN_H_ +# define _ECORE_DRM_LOGIN_H_ + +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif + +#ifdef HAVE_SYSTEMD_LOGIN +# include + +Eina_Bool _ecore_drm_logind_connect(Ecore_Drm_Device *dev); +void _ecore_drm_logind_disconnect(Ecore_Drm_Device *dev); +Eina_Bool _ecore_drm_logind_device_open(const char *device, Ecore_Drm_Open_Cb callback, void *data); +int _ecore_drm_logind_device_open_no_pending(const char *device); +void _ecore_drm_logind_device_close(const char *device); + +int _ecore_drm_dbus_init(const char *session); +int _ecore_drm_dbus_shutdown(void); +int _ecore_drm_dbus_device_take(uint32_t major, uint32_t minor, Ecore_Drm_Open_Cb callback, void *data); +int _ecore_drm_dbus_device_take_no_pending(uint32_t major, uint32_t minor, Eina_Bool *paused_out, double timeout); +void _ecore_drm_dbus_device_release(uint32_t major, uint32_t minor); + +#else +static inline Eina_Bool +_ecore_drm_logind_connect(Ecore_Drm_Device *dev EINA_UNUSED) +{ + return EINA_FALSE; +} + +static inline void +_ecore_drm_logind_disconnect(Ecore_Drm_Device *dev EINA_UNUSED) +{ + return; +} + +static inline Eina_Bool +_ecore_drm_logind_device_open(const char *device EINA_UNUSED, Ecore_Drm_Open_Cb callback EINA_UNUSED, void *data EINA_UNUSED) +{ + return EINA_FALSE; +} + +static inline int +_ecore_drm_logind_device_open_no_pending(const char *device EINA_UNUSED) +{ + return -1; +} + +static inline void +_ecore_drm_logind_device_close(const char *device EINA_UNUSED) +{ + return; +} +#endif + +#endif diff --git a/src/lib/ecore_drm/ecore_drm_private.h b/src/lib/ecore_drm/ecore_drm_private.h index fe769a4c6f..7a3c0a0564 100644 --- a/src/lib/ecore_drm/ecore_drm_private.h +++ b/src/lib/ecore_drm/ecore_drm_private.h @@ -21,7 +21,6 @@ # include //# include -# include # include # include @@ -228,10 +227,11 @@ struct _Ecore_Drm_Sprite unsigned int formats[]; }; -int _ecore_drm_dbus_init(const char *session); -int _ecore_drm_dbus_shutdown(void); -void _ecore_drm_dbus_device_open(const char *device, Eldbus_Message_Cb callback, const void *data); -void _ecore_drm_dbus_device_close(const char *device); +typedef void (*Ecore_Drm_Open_Cb)(void *data, int fd, Eina_Bool b); + +Eina_Bool _ecore_drm_launcher_device_open(const char *device, Ecore_Drm_Open_Cb callback, void *data, int flags); +int _ecore_drm_launcher_device_open_no_pending(const char *device, int flags); +void _ecore_drm_launcher_device_close(const char *device, int fd); Ecore_Drm_Evdev *_ecore_drm_evdev_device_create(Ecore_Drm_Seat *seat, const char *path, int fd); void _ecore_drm_evdev_device_destroy(Ecore_Drm_Evdev *evdev); diff --git a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c index ce6ce8445a..776939e91f 100644 --- a/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c +++ b/src/modules/ecore_evas/engines/drm/ecore_evas_drm.c @@ -474,6 +474,12 @@ _ecore_evas_drm_init(const char *device) goto dev_err; } + if (!ecore_drm_launcher_connect(dev)) + { + ERR("Could not connect DRM launcher"); + goto launcher_err; + } + /* try to open the graphics card */ if (!ecore_drm_device_open(dev)) { @@ -481,13 +487,6 @@ _ecore_evas_drm_init(const char *device) goto dev_open_err; } - /* try to open the tty */ - if (!ecore_drm_tty_open(dev, NULL)) - { - ERR("Could not open tty: %m"); - goto tty_open_err; - } - /* try to create sprites */ if (!ecore_drm_sprites_create(dev)) { @@ -516,11 +515,11 @@ _ecore_evas_drm_init(const char *device) output_err: ecore_drm_sprites_destroy(dev); sprite_err: - ecore_drm_tty_close(dev); -tty_open_err: ecore_drm_device_close(dev); dev_open_err: ecore_drm_device_free(dev); + ecore_drm_launcher_disconnect(dev); +launcher_err: dev_err: ecore_drm_shutdown(); return --_ecore_evas_init_count; @@ -534,9 +533,9 @@ _ecore_evas_drm_shutdown(void) ecore_drm_sprites_destroy(dev); /* NB: No need to free outputs here. Is done in device free */ ecore_drm_inputs_destroy(dev); - ecore_drm_tty_close(dev); ecore_drm_device_close(dev); ecore_drm_device_free(dev); + ecore_drm_launcher_disconnect(dev); ecore_drm_shutdown(); ecore_event_evas_shutdown();