This puts VT input into raw (unbuffered) mode so that we can detect single key strokes. Also uses KD_GRAPHICS mode so that fbcon gets restored properly on exit and inhibits VT switching since we don't properly get/set drm master. Finally, handle signals and clean up if we catch one. --- common.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- common.h | 6 +++++ configure.ac | 3 +++ drm-atomic.c | 2 +- drm-legacy.c | 2 +- kmscube.c | 3 +++ 6 files changed, 101 insertions(+), 3 deletions(-)
diff --git a/common.c b/common.c index b76c994..c495187 100644 --- a/common.c +++ b/common.c @@ -24,10 +24,20 @@ #include <errno.h> #include <fcntl.h> -#include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <string.h> +#include <signal.h> +#include <termios.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <linux/major.h> #include "common.h" @@ -288,3 +298,79 @@ int link_program(unsigned program) return 0; } + +static struct termios save_tio; + +static void restore_vt(void) +{ + struct vt_mode mode = { .mode = VT_AUTO }; + ioctl(STDIN_FILENO, VT_SETMODE, &mode); + + tcsetattr(STDIN_FILENO, TCSANOW, &save_tio); + ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT); +} + +static void handle_signal(int sig) +{ + restore_vt(); + + raise(sig); +} + +int init_vt(void) +{ + struct termios tio; + struct stat buf; + int ret; + + /* If we're not on a VT, we're probably logged in as root over + * ssh. Skip all this then. */ + ret = fstat(STDIN_FILENO, &buf); + if (ret == -1 || major(buf.st_rdev) != TTY_MAJOR) + return 0; + + /* First, save term io setting so we can restore properly. */ + tcgetattr(STDIN_FILENO, &save_tio); + + /* We don't drop drm master, so block VT switching while we're + * running. Otherwise, switching to X on another VT will crash X when it + * fails to get drm master. */ + struct vt_mode mode = { .mode = VT_PROCESS, .relsig = 0, .acqsig = 0 }; + ret = ioctl(STDIN_FILENO, VT_SETMODE, &mode); + if (ret == -1) { + printf("failed to take control of vt handling\n"); + return -1; + } + + /* Set KD_GRAPHICS to disable fbcon while we render. */ + ret = ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS); + if (ret == -1) { + printf("failed to switch console to graphics mode\n"); + return -1; + } + + atexit(restore_vt); + + /* Set console input to raw mode. */ + tio = save_tio; + tio.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &tio); + + /* Restore console on SIGINT and friends. */ + struct sigaction act = { + .sa_handler = handle_signal, + .sa_flags = SA_RESETHAND + }; + sigaction(SIGINT, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGABRT, &act, NULL); + + return 0; +} + +bool key_pressed(void) +{ + struct pollfd pfd[1] = { { .fd = 0, .events = POLLIN } }; + + return poll(pfd, 1, 0) == 1; +} diff --git a/common.h b/common.h index 11ec26e..e6a3c93 100644 --- a/common.h +++ b/common.h @@ -24,6 +24,8 @@ #ifndef _COMMON_H #define _COMMON_H +#include <stdbool.h> + #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <EGL/egl.h> @@ -130,4 +132,8 @@ init_cube_video(const struct gbm *gbm, const char *video) } #endif +int init_vt(void); +bool key_pressed(void); + + #endif /* _COMMON_H */ diff --git a/configure.ac b/configure.ac index 8397f7b..3ee11ed 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,9 @@ AM_INIT_AUTOMAKE([foreign dist-bzip2]) AC_PROG_CC +# For sigaction +AC_USE_SYSTEM_EXTENSIONS + # Enable quiet compiles on automake 1.11. m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/drm-atomic.c b/drm-atomic.c index 82531d3..4c0b16e 100644 --- a/drm-atomic.c +++ b/drm-atomic.c @@ -191,7 +191,7 @@ static int atomic_run(const struct gbm *gbm, const struct egl *egl) /* Allow a modeset change for the first commit only. */ flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; - while (1) { + while (!key_pressed()) { struct gbm_bo *next_bo; EGLSyncKHR gpu_fence = NULL; /* out-fence from gpu, in-fence to kms */ EGLSyncKHR kms_fence = NULL; /* in-fence to gpu, out-fence from kms */ diff --git a/drm-legacy.c b/drm-legacy.c index a0b419a..d3a9391 100644 --- a/drm-legacy.c +++ b/drm-legacy.c @@ -73,7 +73,7 @@ static int legacy_run(const struct gbm *gbm, const struct egl *egl) return ret; } - while (1) { + while (!key_pressed()) { struct gbm_bo *next_bo; int waiting_for_flip = 1; diff --git a/kmscube.c b/kmscube.c index 3a2c4dd..4615430 100644 --- a/kmscube.c +++ b/kmscube.c @@ -153,5 +153,8 @@ int main(int argc, char *argv[]) glClearColor(0.5, 0.5, 0.5, 1.0); glClear(GL_COLOR_BUFFER_BIT); + if (init_vt()) + return -1; + return drm->run(gbm, egl); } -- 2.14.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev