Files
psplash/psplash-console.c
2020-01-21 13:16:33 +00:00

188 lines
4.0 KiB
C

/*
* pslash - a lightweight framebuffer splashscreen for embedded devices.
*
* Copyright (c) 2006 Matthew Allum <mallum@o-hand.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
*/
#include "psplash.h"
/* Globals, needed for signal handling */
static int ConsoleFd = -1;
static int VTNum = -1;
static int VTNumInitial = -1;
static int Visible = 1;
static void
vt_request (int UNUSED(sig))
{
DBG("mark, visible:%i", Visible);
if (Visible)
{
/* Allow Switch Away */
if (ioctl (ConsoleFd, VT_RELDISP, 1) < 0)
perror("Error cannot switch away from console");
Visible = 0;
/* FIXME:
* We likely now want to signal the main loop as to exit
* and we've now likely switched to the X tty. Note, this
* seems to happen anyway atm due to select() call getting
* a signal interuption error - not sure if this is really
* reliable however.
*/
}
else
{
if (ioctl (ConsoleFd, VT_RELDISP, VT_ACKACQ))
perror ("Error can't acknowledge VT switch");
Visible = 1;
/* FIXME: need to schedule repaint some how ? */
}
}
static void
psplash_console_ignore_switches (void)
{
struct sigaction act;
struct vt_mode vt_mode;
if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0)
{
perror("Error VT_SETMODE failed");
return;
}
act.sa_handler = SIG_IGN;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGUSR1, &act, 0);
vt_mode.mode = VT_AUTO;
vt_mode.relsig = 0;
vt_mode.acqsig = 0;
if (ioctl(ConsoleFd, VT_SETMODE, &vt_mode) < 0)
perror("Error VT_SETMODE failed");
}
static void
psplash_console_handle_switches (void)
{
struct sigaction act;
struct vt_mode vt_mode;
if (ioctl(ConsoleFd, VT_GETMODE, &vt_mode) < 0)
{
perror("Error VT_SETMODE failed");
return;
}
act.sa_handler = vt_request;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGUSR1, &act, 0);
vt_mode.mode = VT_PROCESS;
vt_mode.relsig = SIGUSR1;
vt_mode.acqsig = SIGUSR1;
if (ioctl(ConsoleFd, VT_SETMODE, &vt_mode) < 0)
perror("Error VT_SETMODE failed");
}
void
psplash_console_switch (void)
{
char vtname[10];
int fd;
struct vt_stat vt_state;
if ((fd = open("/dev/tty0",O_WRONLY,0)) < 0)
{
perror("Error Cannot open /dev/tty0");
return;
}
/* Find next free terminal */
if ((ioctl(fd, VT_OPENQRY, &VTNum) < 0))
{
perror("Error unable to find a free virtual terminal");
close(fd);
return;
}
close(fd);
sprintf(vtname,"/dev/tty%d", VTNum);
if ((ConsoleFd = open(vtname, O_RDWR|O_NDELAY, 0)) < 0)
{
fprintf(stderr, "Error cannot open %s: %s\n", vtname, strerror(errno));
return;
}
if (ioctl(ConsoleFd, VT_GETSTATE, &vt_state) == 0)
VTNumInitial = vt_state.v_active;
/* Switch to new free terminal */
psplash_console_ignore_switches ();
if (ioctl(ConsoleFd, VT_ACTIVATE, VTNum) != 0)
perror("Error VT_ACTIVATE failed");
if (ioctl(ConsoleFd, VT_WAITACTIVE, VTNum) != 0)
perror("Error VT_WAITACTIVE failed\n");
psplash_console_handle_switches ();
if (ioctl(ConsoleFd, KDSETMODE, KD_GRAPHICS) < 0)
perror("Error KDSETMODE KD_GRAPHICS failed\n");
return;
}
void
psplash_console_reset (void)
{
int fd;
struct vt_stat vt_state;
if (ConsoleFd < 0)
return;
/* Back to text mode */
ioctl(ConsoleFd, KDSETMODE, KD_TEXT);
psplash_console_ignore_switches ();
/* Attempt to switch back to initial console if were still active */
ioctl (ConsoleFd, VT_GETSTATE, &vt_state);
if (VTNum == vt_state.v_active)
{
if (VTNumInitial > -1)
{
ioctl (ConsoleFd, VT_ACTIVATE, VTNumInitial);
ioctl (ConsoleFd, VT_WAITACTIVE, VTNumInitial);
VTNumInitial = -1;
}
}
/* Cleanup */
close(ConsoleFd);
if ((fd = open ("/dev/tty0", O_RDWR|O_NDELAY, 0)) >= 0)
{
ioctl (fd, VT_DISALLOCATE, VTNum);
close (fd);
}
return;
}