diff packages/services/gfx/mw/current/src/drivers/vtswitch.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/services/gfx/mw/current/src/drivers/vtswitch.c
@@ -0,0 +1,216 @@
+#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);
+}