OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [mw/] [src/] [drivers/] [vtswitch.c] - Rev 1772

Go to most recent revision | Compare with Previous | Blame | View Log

#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/vt.h>
#include "device.h"
#include "fb.h"
/*
 * VT switch handling code for Linux
 */
 
/* signal to use when VT swithing*/
#ifndef SIGUNUSED
#define SIGUNUSED	SIGUSR1		/* some systems lack SIGUNUSED*/
#endif
 
#define SIGVTSWITCH	SIGUNUSED	/* SIGUSR2 is used by pthreads...*/
 
int	mwvterm;		/* the VT we were started on */
volatile int mwdrawing;		/* nonzero when drawing is happening*/
static int mwcvt, mwocvt;
static int ttyfd = -1;		/* /dev/tty0*/
static int visible = 1;		/* VT visible flag*/
static struct vt_mode mode;	/* terminal mode*/
static SUBDRIVER save;		/* saved subdriver when VT switched*/
 
extern SCREENDEVICE	scrdev;	/* FIXME */
 
/* entry points*/
int 	MwInitVt(void);
int  	MwCurrentVt(void);
int  	MwCheckVtChange(void);
void 	MwRedrawVt(int t);
 
/* local routines*/
static void  	draw_enable(void);
static void 	draw_disable(void);
static void	vt_switch(int sig);
 
/* null subdriver for drawing when switched out*/
static void 	null_drawpixel(PSD psd,MWCOORD x, MWCOORD y, MWPIXELVAL c) {}
static MWPIXELVAL null_readpixel(PSD psd,MWCOORD x, MWCOORD y) { return 0;}
static void	null_drawhorzline(PSD psd,MWCOORD x1,MWCOORD x2,MWCOORD y,
			MWPIXELVAL c) {}
static void	null_drawvertline(PSD psd,MWCOORD x,MWCOORD y1,MWCOORD y2,
			MWPIXELVAL c) {}
static void	null_fillrect(PSD psd,MWCOORD x1,MWCOORD y1,MWCOORD x2,
			MWCOORD y2,MWPIXELVAL c) {}
static void	null_blit(PSD dstpsd,MWCOORD destx,MWCOORD desty,MWCOORD w,
			MWCOORD h,PSD srcpsd,MWCOORD srcx,MWCOORD srcy,
			long op) {}
static void 	null_drawarea(PSD psd, driver_gc_t *gc, int op) {}
static SUBDRIVER nulldriver = {
	NULL,
	null_drawpixel,
	null_readpixel,
	null_drawhorzline,
	null_drawvertline,
	null_fillrect,
	null_blit,
	null_drawarea
};
 
static void
draw_enable(void)
{
	if(visible)
		return;
	visible = 1;
 
	/* restore screen drawing functions*/
	set_subdriver(&scrdev, &save, FALSE);
}
 
static void
draw_disable(void)
{
	if(!visible)
		return;
	visible = 0;
 
	/* save screen drawing functions and reroute drawing*/
	get_subdriver(&scrdev, &save);
 
	/* set null driver*/
	set_subdriver(&scrdev, &nulldriver, FALSE);
}
 
/* Timer handler used to do the VT switch at a time when not drawing */
static void
vt_do_switch(void *arg)
{
    static unsigned short r[16], g[16], b[16];
 
    /*
     * If a drawing function is in progress then we cannot mode
     * switch right now because the drawing function would continue to
     * scribble on the screen after the switch.  So disable further
     * drawing and schedule an alarm to try again in .1 second.
     */
    if(mwdrawing) {
    	draw_disable ();
	GdAddTimer(100, vt_do_switch, NULL);
    	return;
    }
 
    if(visible) {
    	draw_disable ();
	ioctl_getpalette(0, 16, r, g, b);
 
	if(ioctl (ttyfd, VT_RELDISP, 1) == -1)
	    EPRINTF("Error can't switch away from VT: %m\n");
    } else {
	ioctl_setpalette(0, 16, r, g, b);
    	draw_enable ();
 
	if(ioctl (ttyfd, VT_RELDISP, VT_ACKACQ) == -1)
		EPRINTF("Error can't acknowledge VT switch: %m\n");
    }
}
 
/* Signal handler called when kernel switches to or from our tty*/
static void
vt_switch(int sig)
{
	signal(SIGVTSWITCH, vt_switch);
	vt_do_switch(NULL);
}
 
/*
 * Init VT switch catching code
 * 	return 0 on success, -1 on error
 */
int
MwInitVt(void)
{
	ttyfd = open("/dev/tty0", O_RDONLY);
	if(ttyfd == -1)
		return EPRINTF("Error can't open tty0: %m\n");
 
	/* setup new tty mode*/
	if(ioctl (ttyfd, VT_GETMODE, &mode) == -1)
		return EPRINTF("Error can't get VT mode: %m\n");
 
	mode.mode = VT_PROCESS;
	mode.relsig = SIGVTSWITCH;
	mode.acqsig = SIGVTSWITCH;
	signal (SIGVTSWITCH, vt_switch);
	if(ioctl (ttyfd, VT_SETMODE, &mode) == -1)
		return EPRINTF("Error can't set VT mode: %m\n");
 
	mwcvt = mwocvt = mwvterm = MwCurrentVt();
	/*
	 * Note: this hack is required to get Linux
	 * to orient virtual 0,0 with physical 0,0
	 * I have no idea why this kluge is required...
	 */
	MwRedrawVt(mwvterm);
 
	return 0;
}
 
/*
 * This function is used to find out what the current active VT is.
 */
int
MwCurrentVt(void)
{
	struct vt_stat stat;
 
	ioctl(ttyfd, VT_GETSTATE, &stat);
	return stat.v_active;
}
 
/*
 * Check if our VT has changed.  Return 1 if so.
 */
int
MwCheckVtChange(void)
{
	mwcvt = MwCurrentVt();
	if(mwcvt != mwocvt && mwcvt == mwvterm) {
		mwocvt = mwcvt;
		return 1;
	}
	mwocvt = mwcvt;
	return 0;
}
 
/*
 * This function is used to cause a redraw of the text console.
 * FIXME: Switching to another console and
 * back works, but that's a really dirty hack
 */
void
MwRedrawVt(int t)
{
	if(MwCurrentVt() == mwvterm) {
		ioctl(ttyfd, VT_ACTIVATE, t == 1 ? 2 : 1); /* Awful hack!!*/
		ioctl(ttyfd, VT_ACTIVATE, t);
	}
}
 
void
MwExitVt(void)
{
	signal(SIGVTSWITCH, SIG_DFL);
	mode.mode = VT_AUTO;
	mode.relsig = 0;
	mode.acqsig = 0;
	ioctl(ttyfd, VT_SETMODE, &mode);
 
	if(ttyfd != -1)
		close(ttyfd);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.