From 2bd6fbf20ebb055d4871ffb8eedefa7d7aa60ee8 Mon Sep 17 00:00:00 2001 From: sghctoma Date: Thu, 30 Aug 2018 11:15:39 +0200 Subject: Fix that major(st_rdev) have no meaning on FreeBSD The major device number does not indicate the device type on FreeBSD, and AFAIK the only way to differentiate between DRM, input, and other devices is checking the fd path. This commit implements that. The drmDropmaster and drmSetmaster calls are necessary, because the implicit drop (that should occur when the DRM fd is closed) seems not to be working in some scenarios (e.g. if you have a tmux session running - maybe the fd is retained somehow by tmux?). This is a problem, because once you exit the compositor, you can't start it (or any other program that wants to be DRM master) again until you close all your tmux sessions. --- backend/session/direct-freebsd.c | 42 ++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'backend/session/direct-freebsd.c') diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 63e1be01..1ef76f7a 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -40,12 +40,6 @@ static int direct_session_open(struct wlr_session *base, const char *path) { return fd; } - struct stat st; - if (fstat(fd, &st) < 0) { - close(fd); - return -errno; - } - return fd; } @@ -59,6 +53,20 @@ static void direct_session_close(struct wlr_session *base, int fd) { return; } + char *name; + name = devname(st.st_rdev, S_IFCHR); + if (name == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to get device name"); + close(fd); + return; + } + + if (strncmp(name, "drm/", 4) == 0) { + direct_ipc_dropmaster(session->sock, fd); + } else if (strncmp(name, "input/event", 11)) { + ioctl(fd, EVIOCREVOKE, 0); + } + close(fd); } @@ -79,6 +87,8 @@ static void direct_session_destroy(struct wlr_session *base) { ioctl(session->tty_fd, KDSETMODE, KD_TEXT); ioctl(session->tty_fd, VT_SETMODE, &mode); + ioctl(session->tty_fd, VT_ACTIVATE, 1); + if (errno) { wlr_log(WLR_ERROR, "Failed to restore tty"); } @@ -97,9 +107,29 @@ static int vt_handler(int signo, void *data) { if (session->base.active) { session->base.active = false; wlr_signal_emit_safe(&session->base.session_signal, session); + + char *name; + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + name = devname(dev->dev, S_IFCHR); + if (name != NULL && strncmp(name, "drm/", 4) == 0) { + direct_ipc_dropmaster(session->sock, dev->fd); + } + } + ioctl(session->tty_fd, VT_RELDISP, 1); } else { ioctl(session->tty_fd, VT_RELDISP, VT_ACKACQ); + + char *name; + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + name = devname(dev->dev, S_IFCHR); + if (name != NULL && strncmp(name, "drm/", 4) == 0) { + direct_ipc_setmaster(session->sock, dev->fd); + } + } + session->base.active = true; wlr_signal_emit_safe(&session->base.session_signal, session); } -- cgit v1.2.3 From d948bffd3e7b283870dcbd7f1a5dd2aaea1950ec Mon Sep 17 00:00:00 2001 From: sghctoma Date: Sun, 2 Sep 2018 20:01:13 +0200 Subject: Activate last active VT after compositor exit The VT the compositor was started from was not activated after exiting the compositor, which resulted in arriving on a blank VT. This commit fixes that by introducing a new field in direct_session struct that stores the last active VT so that it can be activated in direct_session_destroy. --- backend/session/direct-freebsd.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'backend/session/direct-freebsd.c') diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 1ef76f7a..7784296b 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -23,6 +23,7 @@ const struct session_impl session_direct; struct direct_session { struct wlr_session base; int tty_fd; + int old_tty; int old_kbmode; int sock; pid_t child; @@ -87,7 +88,7 @@ static void direct_session_destroy(struct wlr_session *base) { ioctl(session->tty_fd, KDSETMODE, KD_TEXT); ioctl(session->tty_fd, VT_SETMODE, &mode); - ioctl(session->tty_fd, VT_ACTIVATE, 1); + ioctl(session->tty_fd, VT_ACTIVATE, session->old_tty); if (errno) { wlr_log(WLR_ERROR, "Failed to restore tty"); @@ -138,11 +139,15 @@ static int vt_handler(int signo, void *data) { } static bool setup_tty(struct direct_session *session, struct wl_display *display) { - int fd = -1, tty = -1, tty0_fd = -1; + int fd = -1, tty = -1, tty0_fd = -1, old_tty = 1; if ((tty0_fd = open("/dev/ttyv0", O_RDWR | O_CLOEXEC)) < 0) { wlr_log_errno(WLR_ERROR, "Could not open /dev/ttyv0 to find a free vt"); goto error; } + if (ioctl(tty0_fd, VT_GETACTIVE, &old_tty) != 0) { + wlr_log_errno(WLR_ERROR, "Could not get active vt"); + goto error; + } if (ioctl(tty0_fd, VT_OPENQRY, &tty) != 0) { wlr_log_errno(WLR_ERROR, "Could not find a free vt"); goto error; @@ -198,13 +203,16 @@ static bool setup_tty(struct direct_session *session, struct wl_display *display session->base.vtnr = tty; session->tty_fd = fd; + session->old_tty = old_tty; session->old_kbmode = old_kbmode; return true; error: - // Drop back to tty 1, better than hanging in a useless blank console - ioctl(fd, VT_ACTIVATE, 1); + // In case we could not get the last active one, drop back to tty 1, + // better than hanging in a useless blank console. Otherwise activate the + // last active. + ioctl(fd, VT_ACTIVATE, old_tty); close(fd); return false; } -- cgit v1.2.3 From 7a5d3c4d3bf8c2f21fcec65182f1563f4c857408 Mon Sep 17 00:00:00 2001 From: sghctoma Date: Fri, 7 Sep 2018 16:37:25 +0200 Subject: Implement device type discovery using ioctl calls This commit implements device type discovery by calling two ioctls (DRM_IOCTL_VERSION and EVIOCGVERSION) on the device. These iocts are specific to drm and input devices respectively, therefore we can determine the device type based on which one returns an error. --- backend/session/direct-freebsd.c | 34 +++++++++------------------------- backend/session/direct-ipc.c | 10 ++++++---- 2 files changed, 15 insertions(+), 29 deletions(-) (limited to 'backend/session/direct-freebsd.c') diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 7784296b..cecfb0c1 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "backend/session/direct-ipc.h" #include "util/signal.h" @@ -47,24 +48,11 @@ static int direct_session_open(struct wlr_session *base, const char *path) { static void direct_session_close(struct wlr_session *base, int fd) { struct direct_session *session = wl_container_of(base, session, base); - struct stat st; - if (fstat(fd, &st) < 0) { - wlr_log_errno(WLR_ERROR, "Stat failed"); - close(fd); - return; - } - - char *name; - name = devname(st.st_rdev, S_IFCHR); - if (name == NULL) { - wlr_log_errno(WLR_ERROR, "Failed to get device name"); - close(fd); - return; - } - - if (strncmp(name, "drm/", 4) == 0) { + int ev; + struct drm_version dv = {0}; + if (ioctl(fd, DRM_IOCTL_VERSION, &dv) == 0) { direct_ipc_dropmaster(session->sock, fd); - } else if (strncmp(name, "input/event", 11)) { + } else if (ioctl(fd, EVIOCGVERSION, &ev) == 0) { ioctl(fd, EVIOCREVOKE, 0); } @@ -104,16 +92,15 @@ static void direct_session_destroy(struct wlr_session *base) { static int vt_handler(int signo, void *data) { struct direct_session *session = data; + struct drm_version dv = {0}; + struct wlr_device *dev; if (session->base.active) { session->base.active = false; wlr_signal_emit_safe(&session->base.session_signal, session); - char *name; - struct wlr_device *dev; wl_list_for_each(dev, &session->base.devices, link) { - name = devname(dev->dev, S_IFCHR); - if (name != NULL && strncmp(name, "drm/", 4) == 0) { + if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) { direct_ipc_dropmaster(session->sock, dev->fd); } } @@ -122,11 +109,8 @@ static int vt_handler(int signo, void *data) { } else { ioctl(session->tty_fd, VT_RELDISP, VT_ACKACQ); - char *name; - struct wlr_device *dev; wl_list_for_each(dev, &session->base.devices, link) { - name = devname(dev->dev, S_IFCHR); - if (name != NULL && strncmp(name, "drm/", 4) == 0) { + if (ioctl(dev->fd, DRM_IOCTL_VERSION, &dv) == 0) { direct_ipc_setmaster(session->sock, dev->fd); } } diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 99ffcb1b..302b639e 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -3,6 +3,7 @@ #define __BSD_VISIBLE 1 #define INPUT_MAJOR 0 #endif +#include #include #include #include @@ -159,14 +160,15 @@ static void communicate(int sock) { ret = errno; } #else - if (strncmp(msg.path, "/dev/drm/", 9) && - strncmp(msg.path, "/dev/input/event", 16)) { - + int ev; + struct drm_version dv = {0}; + if (ioctl(fd, EVIOCGVERSION, &ev) == -1 && + ioctl(fd, DRM_IOCTL_VERSION, &dv) == -1) { ret = ENOTSUP; goto error; } - if (strncmp(msg.path, "/dev/drm/", 9) == 0 && drmSetMaster(fd)) { + if (dv.version_major != 0 && drmSetMaster(fd)) { ret = errno; } #endif -- cgit v1.2.3