diff options
author | sghctoma <sghctoma@gmail.com> | 2018-08-30 11:15:39 +0200 |
---|---|---|
committer | sghctoma <sghctoma@gmail.com> | 2018-08-30 11:15:39 +0200 |
commit | 2bd6fbf20ebb055d4871ffb8eedefa7d7aa60ee8 (patch) | |
tree | adcf2c31beb7cff11cdc3e87232cff19e5af458e | |
parent | 633663cddefea5d66e2116573f39ec9aab9e12ab (diff) |
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.
-rw-r--r-- | backend/session/direct-freebsd.c | 42 | ||||
-rw-r--r-- | backend/session/direct-ipc.c | 21 |
2 files changed, 55 insertions, 8 deletions
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); } diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 5fdb95ac..99ffcb1b 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -142,6 +142,7 @@ static void communicate(int sock) { goto error; } +#ifndef __FreeBSD__ struct stat st; if (fstat(fd, &st) < 0) { ret = errno; @@ -157,6 +158,19 @@ static void communicate(int sock) { if (maj == DRM_MAJOR && drmSetMaster(fd)) { ret = errno; } +#else + if (strncmp(msg.path, "/dev/drm/", 9) && + strncmp(msg.path, "/dev/input/event", 16)) { + + ret = ENOTSUP; + goto error; + } + + if (strncmp(msg.path, "/dev/drm/", 9) == 0 && drmSetMaster(fd)) { + ret = errno; + } +#endif + error: send_msg(sock, ret ? -1 : fd, &ret, sizeof(ret)); if (fd >= 0) { @@ -193,8 +207,11 @@ int direct_ipc_open(int sock, const char *path) { send_msg(sock, -1, &msg, sizeof(msg)); - int fd, err; - recv_msg(sock, &fd, &err, sizeof(err)); + int fd, err, ret; + int retry = 0; + do { + ret = recv_msg(sock, &fd, &err, sizeof(err)); + } while (ret == 0 && retry++ < 3); return err ? -err : fd; } |