modeset.c revision 23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek/***
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek This file is part of systemd.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (at your option) any later version.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek***/
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek/*
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * Modeset Testing
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * The modeset tool attaches to the session of the caller and shows a
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * test-pattern on all displays of this session. It is meant as debugging tool
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * for the grdev infrastructure.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <drm_fourcc.h>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#include <errno.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <getopt.h>
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek#include <linux/kd.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <linux/vt.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <stdbool.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <stdio.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <stdlib.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <string.h>
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek#include <sys/ioctl.h>
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek#include <sys/stat.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <systemd/sd-bus.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <systemd/sd-event.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <systemd/sd-login.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <termios.h>
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include <unistd.h>
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek#include "build.h"
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek#include "bus-util.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include "event-util.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include "grdev.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include "grdev-internal.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include "macro.h"
ae6c3cc009a21df4b51851fb8fe3fde0b7d6d8f0Lennart Poettering#include "sysview.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#include "util.h"
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmektypedef struct Modeset Modeset;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstruct Modeset {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek char *session;
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek char *seat;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek sd_event *event;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek sd_bus *bus;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek sd_event_source *exit_src;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek sysview_context *sysview;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek grdev_context *grdev;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek grdev_session *grdev_session;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek uint8_t r, g, b;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek bool r_up, g_up, b_up;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek bool my_tty : 1;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek bool managed : 1;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek};
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic int modeset_exit_fn(sd_event_source *source, void *userdata) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Modeset *m = userdata;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek if (m->grdev_session)
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek grdev_session_restore(m->grdev_session);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek return 0;
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek}
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic Modeset *modeset_free(Modeset *m) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek if (!m)
45519fd6304aae453d95c6cf11bfc8539c38494cLennart Poettering return NULL;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->grdev_session = grdev_session_free(m->grdev_session);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->grdev = grdev_context_unref(m->grdev);
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek m->sysview = sysview_context_free(m->sysview);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->exit_src = sd_event_source_unref(m->exit_src);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->bus = sd_bus_unref(m->bus);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek m->event = sd_event_unref(m->event);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek free(m->seat);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek free(m->session);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek free(m);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek return NULL;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek}
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-SzmekDEFINE_TRIVIAL_CLEANUP_FUNC(Modeset*, modeset_free);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic bool is_my_tty(const char *session) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek unsigned int vtnr;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek struct stat st;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek long mode;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek int r;
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek /* Using logind's Controller API is highly fragile if there is already
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * a session controller running. If it is registered as controller
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * itself, TakeControl will simply fail. But if its a legacy controller
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * that does not use logind's controller API, we must never register
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * our own controller. Otherwise, we really mess up the VT. Therefore,
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * only run in managed mode if there's no-one else. Furthermore, never
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * try to access graphics devices if there's someone else. Unlike input
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek * devices, graphics devies cannot be shared easily. */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (!isatty(1))
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return false;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (!session)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return false;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_session_get_vt(session, &vtnr);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0 || vtnr < 1 || vtnr > 63)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return false;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek mode = 0;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = ioctl(1, KDGETMODE, &mode);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0 || mode != KD_TEXT)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return false;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = fstat(1, &st);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0 || minor(st.st_rdev) != vtnr)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return false;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return true;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek}
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
45519fd6304aae453d95c6cf11bfc8539c38494cLennart Poetteringstatic int modeset_new(Modeset **out) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek _cleanup_(modeset_freep) Modeset *m = NULL;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek int r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek assert(out);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m = new0(Modeset, 1);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (!m)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return log_oom();
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_pid_get_session(getpid(), &m->session);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Cannot retrieve logind session: %m");
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_session_get_seat(m->session, &m->seat);
a34bf9db5da0fdd6bdb14459e203dbe41ee99614Lennart Poettering if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Cannot retrieve seat of logind session: %m");
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->my_tty = is_my_tty(m->session);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->managed = m->my_tty && geteuid() > 0;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->r = rand() % 0xff;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->g = rand() % 0xff;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->b = rand() % 0xff;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->r_up = m->g_up = m->b_up = true;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_default(&m->event);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_bus_open_system(&m->bus);
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_add_exit(m->event, &m->exit_src, modeset_exit_fn, m);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering /* schedule before sd-bus close */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = sd_event_source_set_priority(m->exit_src, -10);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering r = sysview_context_new(&m->sysview,
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering SYSVIEW_CONTEXT_SCAN_LOGIND |
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek SYSVIEW_CONTEXT_SCAN_DRM,
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->event,
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m->bus,
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek NULL);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek r = grdev_context_new(&m->grdev, m->event, m->bus);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if (r < 0)
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return r;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek *out = m;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek m = NULL;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return 0;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek}
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmekstatic uint8_t next_color(bool *up, uint8_t cur, unsigned int mod) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek uint8_t next;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek /* generate smoothly morphing colors */
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek next = cur + (*up ? 1 : -1) * (rand() % mod);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek if ((*up && next < cur) || (!*up && next > cur)) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek *up = !*up;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek next = cur;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek }
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek return next;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek}
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmekstatic void modeset_draw(Modeset *m, const grdev_display_target *t) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek uint32_t j, k, *b;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek uint8_t *l;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek assert(t->back->format == DRM_FORMAT_XRGB8888 || t->back->format == DRM_FORMAT_ARGB8888);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek assert(!t->rotate);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek assert(!t->flip);
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek l = t->back->maps[0];
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek for (j = 0; j < t->height; ++j) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek for (k = 0; k < t->width; ++k) {
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek b = (uint32_t*)l;
1a7f1b385cd9de8a0da934fadc379860f914ef33Zbigniew Jędrzejewski-Szmek b[k] = (0xff << 24) | (m->r << 16) | (m->g << 8) | m->b;
}
l += t->back->strides[0];
}
}
static void modeset_render(Modeset *m, grdev_display *d) {
const grdev_display_target *t;
m->r = next_color(&m->r_up, m->r, 4);
m->g = next_color(&m->g_up, m->g, 3);
m->b = next_color(&m->b_up, m->b, 2);
GRDEV_DISPLAY_FOREACH_TARGET(d, t) {
modeset_draw(m, t);
grdev_display_flip_target(d, t);
}
grdev_session_commit(m->grdev_session);
}
static void modeset_grdev_fn(grdev_session *session, void *userdata, grdev_event *ev) {
Modeset *m = userdata;
switch (ev->type) {
case GRDEV_EVENT_DISPLAY_ADD:
grdev_display_enable(ev->display_add.display);
break;
case GRDEV_EVENT_DISPLAY_REMOVE:
break;
case GRDEV_EVENT_DISPLAY_CHANGE:
break;
case GRDEV_EVENT_DISPLAY_FRAME:
modeset_render(m, ev->display_frame.display);
break;
}
}
static int modeset_sysview_fn(sysview_context *c, void *userdata, sysview_event *ev) {
unsigned int flags, type;
Modeset *m = userdata;
sysview_device *d;
const char *name;
int r;
switch (ev->type) {
case SYSVIEW_EVENT_SESSION_FILTER:
if (streq_ptr(m->session, ev->session_filter.id))
return 1;
break;
case SYSVIEW_EVENT_SESSION_ADD:
assert(!m->grdev_session);
name = sysview_session_get_name(ev->session_add.session);
flags = 0;
if (m->managed)
flags |= GRDEV_SESSION_MANAGED;
r = grdev_session_new(&m->grdev_session,
m->grdev,
flags,
name,
modeset_grdev_fn,
m);
if (r < 0)
return log_error_errno(r, "Cannot create grdev session: %m");
if (m->managed) {
r = sysview_session_take_control(ev->session_add.session);
if (r < 0)
return log_error_errno(r, "Cannot request session control: %m");
}
grdev_session_enable(m->grdev_session);
break;
case SYSVIEW_EVENT_SESSION_REMOVE:
if (!m->grdev_session)
return 0;
grdev_session_restore(m->grdev_session);
grdev_session_disable(m->grdev_session);
m->grdev_session = grdev_session_free(m->grdev_session);
if (sd_event_get_exit_code(m->event, &r) == -ENODATA)
sd_event_exit(m->event, 0);
break;
case SYSVIEW_EVENT_SESSION_ATTACH:
d = ev->session_attach.device;
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_DRM)
grdev_session_add_drm(m->grdev_session, sysview_device_get_ud(d));
break;
case SYSVIEW_EVENT_SESSION_DETACH:
d = ev->session_detach.device;
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_DRM)
grdev_session_remove_drm(m->grdev_session, sysview_device_get_ud(d));
break;
case SYSVIEW_EVENT_SESSION_REFRESH:
d = ev->session_refresh.device;
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_DRM)
grdev_session_hotplug_drm(m->grdev_session, ev->session_refresh.ud);
break;
case SYSVIEW_EVENT_SESSION_CONTROL:
r = ev->session_control.error;
if (r < 0)
return log_error_errno(r, "Cannot acquire session control: %m");
r = ioctl(1, KDSKBMODE, K_UNICODE);
if (r < 0) {
log_error("Cannot set K_UNICODE on stdout: %m");
return -errno;
}
break;
}
return 0;
}
static int modeset_run(Modeset *m) {
struct termios in_attr, saved_attr;
int r;
assert(m);
if (!m->my_tty) {
log_warning("You need to run this program on a free VT");
return -EACCES;
}
if (!m->managed && geteuid() > 0)
log_warning("You run in unmanaged mode without being root. This is likely to fail..");
printf("modeset - Show test pattern on selected graphics devices\n"
" Running on seat '%s' in user-session '%s'\n"
" Exit by pressing ^C\n\n",
m->seat ? : "seat0", m->session ? : "<none>");
r = sysview_context_start(m->sysview, modeset_sysview_fn, m);
if (r < 0)
goto out;
r = tcgetattr(0, &in_attr);
if (r < 0) {
r = -errno;
goto out;
}
saved_attr = in_attr;
in_attr.c_lflag &= ~ECHO;
r = tcsetattr(0, TCSANOW, &in_attr);
if (r < 0) {
r = -errno;
goto out;
}
r = sd_event_loop(m->event);
tcsetattr(0, TCSANOW, &saved_attr);
printf("exiting..\n");
out:
sysview_context_stop(m->sysview);
return r;
}
static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Show test pattern on all selected graphics devices.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
, program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{},
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
if (argc > optind) {
log_error("Too many arguments");
return -EINVAL;
}
return 1;
}
int main(int argc, char *argv[]) {
_cleanup_(modeset_freep) Modeset *m = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
log_open();
initialize_srand();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = modeset_new(&m);
if (r < 0)
goto finish;
r = modeset_run(m);
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}