Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 Oct 2013 12:40:04 +0000 (UTC)
From:      Aleksandr Rybalko <ray@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r256145 - in user/ed/newcons/sys/dev/vt: . hw/intel hw/ofwfb hw/vga hw/xboxfb
Message-ID:  <201310081240.r98Ce4fU098558@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ray
Date: Tue Oct  8 12:40:04 2013
New Revision: 256145
URL: http://svnweb.freebsd.org/changeset/base/256145

Log:
  o Implement history buffer.
  o Join history buffer with screen buffer. Same type of things.
  o Reimplement buffer as an array of rows. Make it circular, so no overflow
  	tracking.
  o Implement VT_PROCESS mode. Locking of VT switching by owner process.
  o Add debug and deadtimer sysctls. deadtimer - defaulting to 15 seconds, time
  	to wait process answer in VT_PROCESS mode, to do VT switch in case when
  	process hang.
  o Implement later console attach.
  o Fix (partially yet) keyboard allocation.
  o Add drivers priority. Disallow to replace KMS driver with VGA.
  o Add ability to resize terminals.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  user/ed/newcons/sys/dev/vt/hw/intel/intel.c
  user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c
  user/ed/newcons/sys/dev/vt/hw/vga/vga.c
  user/ed/newcons/sys/dev/vt/hw/xboxfb/xboxfb.c
  user/ed/newcons/sys/dev/vt/vt.h
  user/ed/newcons/sys/dev/vt/vt_buf.c
  user/ed/newcons/sys/dev/vt/vt_core.c
  user/ed/newcons/sys/dev/vt/vt_font.c
  user/ed/newcons/sys/dev/vt/vt_history.c

Modified: user/ed/newcons/sys/dev/vt/hw/intel/intel.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/hw/intel/intel.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/hw/intel/intel.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -65,6 +65,8 @@ static vd_bitblt_t	intel_vtbitblt;
 static struct vt_driver intel_vtops = {
 	.vd_init	= intel_vtinit,
 	.vd_bitblt	= intel_vtbitblt,
+	/* Prefer to use KMS, so GENERIC - 10 */
+	.vd_priority	= VD_PRIORITY_GENERIC - 10,
 };
 
 struct intel_softc {

Modified: user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/hw/ofwfb/ofwfb.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -65,6 +65,7 @@ static const struct vt_driver vt_ofwfb_d
 	.vd_init	= ofwfb_init,
 	.vd_blank	= ofwfb_blank,
 	.vd_bitblt	= ofwfb_bitblt,
+	.vd_priority	= VD_PRIORITY_GENERIC,
 };
 
 static struct ofwfb_softc ofwfb_conssoftc;

Modified: user/ed/newcons/sys/dev/vt/hw/vga/vga.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/hw/vga/vga.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/hw/vga/vga.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -81,6 +81,7 @@ static const struct vt_driver vt_vga_dri
 	.vd_blank	= vga_blank,
 	.vd_bitblt	= vga_bitblt,
 	.vd_putchar	= vga_putchar,
+	.vd_priority	= VD_PRIORITY_GENERIC,
 };
 
 /*

Modified: user/ed/newcons/sys/dev/vt/hw/xboxfb/xboxfb.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/hw/xboxfb/xboxfb.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/hw/xboxfb/xboxfb.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -67,6 +67,7 @@ static const struct vt_driver vt_xbox_dr
 	.vd_init	= xbox_init,
 	.vd_blank	= xbox_blank,
 	.vd_bitblt	= xbox_bitblt,
+	.vd_priority	= VD_PRIORITY_GENERIC,
 };
 
 static struct xbox_softc xbox_conssoftc;

Modified: user/ed/newcons/sys/dev/vt/vt.h
==============================================================================
--- user/ed/newcons/sys/dev/vt/vt.h	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/vt.h	Tue Oct  8 12:40:04 2013	(r256145)
@@ -40,10 +40,21 @@
 #include <sys/consio.h>
 #include <sys/kbio.h>
 #include <sys/terminal.h>
+#include <sys/sysctl.h>
 
 #define	VT_MAXWINDOWS	12
 #define	VT_CONSWINDOW	0
 
+#define	SC_DRIVER_NAME	"vt"
+#define	DPRINTF(_l, ...)	if (vt_debug > (_l)) printf( __VA_ARGS__ )
+#define	ISSIGVALID(sig)	((sig) > 0 && (sig) < NSIG)
+
+#define	VT_SYSCTL_INT(_name, _default, _descr)				\
+static int vt_##_name = _default;					\
+SYSCTL_INT(_kern_vt, OID_AUTO, _name, CTLFLAG_RW, &vt_##_name, _default,\
+		_descr);						\
+TUNABLE_INT("kern.vt." #_name, &vt_##_name);
+
 struct vt_driver;
 
 void vt_allocate(struct vt_driver *, void *);
@@ -80,10 +91,9 @@ struct vt_device {
 #define	VDF_ASYNC	0x04	/* vt_timer() running. */
 #define	VDF_INVALID	0x08	/* Entire screen should be re-rendered. */
 #define	VDF_DEAD	0x10	/* Early probing found nothing. */
+#define	VDF_INITIALIZED	0x20	/* vtterm_cnprobe already done. */
 	int			 vd_keyboard;	/* (G) Keyboard index. */
 	unsigned int		 vd_unit;	/* (c) Device unit. */
-	/* XXX: HACK */
-	unsigned int		 vd_scrollpos;	/* (d) Last scroll position. */
 };
 
 /*
@@ -104,27 +114,45 @@ struct vt_bufmask {
 
 struct vt_buf {
 	struct mtx		 vb_lock;	/* Buffer lock. */
-	term_pos_t		 vb_size;	/* (b) Screen dimensions. */
+	term_pos_t		 vb_scr_size;	/* (b) Screen dimensions. */
 	int			 vb_flags;	/* (b) Flags. */
 #define	VBF_CURSOR	0x1	/* Cursor visible. */
 #define	VBF_STATIC	0x2	/* Buffer is statically allocated. */
+#define	VBF_MTX_INIT	0x4	/* Mutex initialized. */
+#define	VBF_SCROLL	0x8	/* scroll locked mode. */
+	int			 vb_history_size;
+#define	VBF_DEFAULT_HISTORY_SIZE	200
+	int			 vb_roffset;	/* (b) History rows offset. */
+	int			 vb_curroffset;	/* (b) Saved rows offset. */
 	term_pos_t		 vb_cursor;	/* (u) Cursor position. */
 	term_rect_t		 vb_dirtyrect;	/* (b) Dirty rectangle. */
 	struct vt_bufmask	 vb_dirtymask;	/* (b) Dirty bitmasks. */
 	term_char_t		*vb_buffer;	/* (u) Data buffer. */
+	term_char_t		**vb_rows;	/* (u) Array of rows */
 };
 
 void vtbuf_copy(struct vt_buf *, const term_rect_t *, const term_pos_t *);
-void vtbuf_fill(struct vt_buf *, const term_rect_t *, term_char_t);
+void vtbuf_fill_locked(struct vt_buf *, const term_rect_t *, term_char_t);
 void vtbuf_init_early(struct vt_buf *);
 void vtbuf_init(struct vt_buf *, const term_pos_t *);
-void vtbuf_grow(struct vt_buf *, const term_pos_t *);
+void vtbuf_grow(struct vt_buf *, const term_pos_t *, int);
 void vtbuf_putchar(struct vt_buf *, const term_pos_t *, term_char_t);
 void vtbuf_cursor_position(struct vt_buf *, const term_pos_t *);
 void vtbuf_cursor_visibility(struct vt_buf *, int);
 void vtbuf_undirty(struct vt_buf *, term_rect_t *, struct vt_bufmask *);
+void vtbuf_sethistory_size(struct vt_buf *, int);
+
+#define	VTBUF_SLCK_ENABLE(vb)	(vb)->vb_flags |= VBF_SCROLL
+#define	VTBUF_SLCK_DISABLE(vb)	(vb)->vb_flags &= ~VBF_SCROLL
+
+#define	VTBUF_MAX_HEIGHT(vb) \
+	((vb)->vb_history_size)
+#define	VTBUF_GET_ROW(vb, r) \
+	((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)])
+#define	VTBUF_GET_FIELD(vb, r, c) \
+	((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)])
 #define	VTBUF_FIELD(vb, r, c) \
-	(vb)->vb_buffer[(r) * (vb)->vb_size.tp_col + (c)]
+	((vb)->vb_rows[((vb)->vb_curroffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)])
 #define	VTBUF_ISCURSOR(vb, r, c) \
 	((vb)->vb_flags & VBF_CURSOR && \
 	(vb)->vb_cursor.tp_row == (r) && (vb)->vb_cursor.tp_col == (c))
@@ -132,26 +160,14 @@ void vtbuf_undirty(struct vt_buf *, term
 	((mask)->vbm_row & ((uint64_t)1 << ((row) % 64)))
 #define	VTBUF_DIRTYCOL(mask, col) \
 	((mask)->vbm_col & ((uint64_t)1 << ((col) % 64)))
+#define	VTBUF_SPACE_CHAR	(' ' | TC_WHITE << 26 | TC_BLACK << 29)
 
-/*
- * Per-window history tracking.
- *
- * XXX: Unimplemented!
- */
-
-struct vt_history {
-	unsigned int	vh_offset;
-};
-
-void vthistory_add(struct vt_history *vh, struct vt_buf *vb,
-    const term_rect_t *r);
 #define	VHS_SET	0
 #define	VHS_CUR	1
 #define	VHS_END	2
-void vthistory_seek(struct vt_history *vh, int offset, int whence);
-void vthistory_getpos(const struct vt_history *vh, unsigned int *offset);
-#define	VTHISTORY_FIELD(vh, r, c) \
-	('?' | (TF_BOLD|TF_REVERSE) << 22 | TC_GREEN << 26 | TC_BLACK << 29)
+int vthistory_seek(struct vt_buf *, int offset, int whence);
+void vthistory_addlines(struct vt_buf *vb, int offset);
+void vthistory_getpos(const struct vt_buf *, unsigned int *offset);
 
 /*
  * Per-window datastructure.
@@ -161,7 +177,6 @@ struct vt_window {
 	struct vt_device	*vw_device;	/* (c) Device. */
 	struct terminal		*vw_terminal;	/* (c) Terminal. */
 	struct vt_buf		 vw_buf;	/* (u) Screen buffer. */
-	struct vt_history	 vw_history;	/* (?) History buffer. */
 	struct vt_font		*vw_font;	/* (d) Graphical font. */
 	unsigned int		 vw_number;	/* (c) Window number. */
 	int			 vw_kbdmode;	/* (?) Keyboard mode. */
@@ -170,8 +185,22 @@ struct vt_window {
 #define	VWF_OPENED	0x2	/* TTY in use. */
 #define	VWF_SCROLL	0x4	/* Keys influence scrollback. */
 #define	VWF_CONSOLE	0x8	/* Kernel message console window. */
+#define	VWF_VTYLOCK	0x10	/* Prevent window switch. */
+#define	VWF_SWWAIT_REL	0x10000	/* Program wait for VT acquire is done. */
+#define	VWF_SWWAIT_ACQ	0x20000	/* Program wait for VT release is done. */
+	pid_t			 vw_pid;	/* Terminal holding process */
+	struct proc		*vw_proc;
+	struct vt_mode		 vw_smode;	/* switch mode */
+	struct callout		 vw_proc_dead_timer;
+	struct vt_window	*vw_switch_to;
 };
 
+#define	VT_AUTO		0		/* switching is automatic */
+#define	VT_PROCESS	1		/* switching controlled by prog */
+#define	VT_KERNEL	255		/* switching controlled in kernel */
+
+#define	IS_VT_PROC_MODE(vw)	((vw)->vw_smode.mode == VT_PROCESS)
+
 /*
  * Per-device driver routines.
  *
@@ -181,6 +210,7 @@ struct vt_window {
  */
 
 typedef int vd_init_t(struct vt_device *vd);
+typedef void vd_postswitch_t(struct vt_device *vd);
 typedef void vd_blank_t(struct vt_device *vd, term_color_t color);
 typedef void vd_bitblt_t(struct vt_device *vd, const uint8_t *src,
     vt_axis_t top, vt_axis_t left, unsigned int width, unsigned int height,
@@ -190,14 +220,23 @@ typedef void vd_putchar_t(struct vt_devi
 
 struct vt_driver {
 	/* Console attachment. */
-	vd_init_t		*vd_init;
+	vd_init_t	*vd_init;
 
 	/* Drawing. */
-	vd_blank_t		*vd_blank;
-	vd_bitblt_t		*vd_bitblt;
+	vd_blank_t	*vd_blank;
+	vd_bitblt_t	*vd_bitblt;
 
 	/* Text mode operation. */
-	vd_putchar_t		*vd_putchar;
+	vd_putchar_t	*vd_putchar;
+
+	/* Update display setting on vt switch. */
+	vd_postswitch_t	*vd_postswitch;
+
+	/* Priority to know which one can override */
+	int		vd_priority;
+#define	VD_PRIORITY_DUMB	10000
+#define	VD_PRIORITY_GENERIC	1000
+#define	VD_PRIORITY_SPECIFIC	100
 };
 
 /*
@@ -222,14 +261,21 @@ static struct vt_device	driver ## _consd
 	.vd_windows = { [VT_CONSWINDOW] =  &driver ## _conswindow, },	\
 	.vd_curwindow = &driver ## _conswindow,				\
 };									\
-static term_char_t	driver ## _constextbuf[(width) * (height)];	\
+static term_char_t	driver ## _constextbuf[(width) * 		\
+	    (VBF_DEFAULT_HISTORY_SIZE)];				\
+static term_char_t	*driver ## _constextbufrows[			\
+	    VBF_DEFAULT_HISTORY_SIZE];					\
 static struct vt_window	driver ## _conswindow = {			\
 	.vw_number = VT_CONSWINDOW,					\
 	.vw_flags = VWF_CONSOLE,					\
 	.vw_buf = {							\
 		.vb_buffer = driver ## _constextbuf,			\
+		.vb_rows = driver ## _constextbufrows,			\
+		.vb_history_size = VBF_DEFAULT_HISTORY_SIZE,		\
+		.vb_curroffset = 0,					\
+		.vb_roffset = 0,					\
 		.vb_flags = VBF_STATIC,					\
-		.vb_size = {						\
+		.vb_scr_size = {					\
 			.tp_row = height,				\
 			.tp_col = width,				\
 		},							\

Modified: user/ed/newcons/sys/dev/vt/vt_buf.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/vt_buf.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/vt_buf.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -43,6 +43,77 @@ static MALLOC_DEFINE(M_VTBUF, "vtbuf", "
 
 #define	VTBUF_LOCK(vb)		mtx_lock_spin(&(vb)->vb_lock)
 #define	VTBUF_UNLOCK(vb)	mtx_unlock_spin(&(vb)->vb_lock)
+/*
+ * line4
+ * line5 <--- curroffset (terminal output to that line)
+ * line0
+ * line1                  <--- roffset (history display from that point)
+ * line2
+ * line3
+ */
+int
+vthistory_seek(struct vt_buf *vb, int offset, int whence)
+{
+	int roffset;
+
+	/* No scrolling if not enabled. */
+	if ((vb->vb_flags & VBF_SCROLL) == 0) {
+		if (vb->vb_roffset != vb->vb_curroffset) {
+			vb->vb_roffset = vb->vb_curroffset;
+			return (1);
+		}
+		return (0); /* No changes */
+	}
+	/*
+	 * Operate on copy of offset value, since it temporary can be bigger
+	 * than amount of rows in buffer.
+	 */
+	roffset = vb->vb_roffset;
+	switch (whence) {
+	case VHS_SET:
+		roffset = offset;
+		break;
+	case VHS_CUR:
+		roffset += offset;
+		break;
+	case VHS_END:
+		/* Go to current offset. */
+		roffset = vb->vb_curroffset;
+		break;
+	}
+
+	if (roffset < 0)
+		roffset = 0;
+	if (roffset >= vb->vb_history_size)
+		/* Still have screen_height rows. */
+		roffset %= VTBUF_MAX_HEIGHT(vb);
+
+	if (vb->vb_roffset != roffset) {
+		vb->vb_roffset = roffset;
+		return (1); /* Offset changed, please update sceen. */
+	}
+	return (0); /* No changes */
+}
+
+void
+vthistory_addlines(struct vt_buf *vb, int offset)
+{
+
+	vb->vb_curroffset += offset;
+	if (vb->vb_curroffset < 0)
+		vb->vb_curroffset = 0;
+	vb->vb_curroffset %= vb->vb_history_size;
+	if ((vb->vb_flags & VBF_SCROLL) == 0) {
+		vb->vb_roffset = vb->vb_curroffset;
+	}
+}
+
+void
+vthistory_getpos(const struct vt_buf *vb, unsigned int *offset)
+{
+
+	*offset = vb->vb_roffset;
+}
 
 static inline uint64_t
 vtbuf_dirty_axis(unsigned int begin, unsigned int end)
@@ -112,7 +183,7 @@ static void
 vtbuf_make_undirty(struct vt_buf *vb)
 {
 
-	vb->vb_dirtyrect.tr_begin = vb->vb_size;
+	vb->vb_dirtyrect.tr_begin = vb->vb_scr_size;
 	vb->vb_dirtyrect.tr_end.tp_row = vb->vb_dirtyrect.tr_end.tp_col = 0;
 	vb->vb_dirtymask.vbm_row = vb->vb_dirtymask.vbm_col = 0;
 }
@@ -134,13 +205,39 @@ vtbuf_copy(struct vt_buf *vb, const term
 	const term_pos_t *p1 = &r->tr_begin;
 	term_rect_t area;
 	unsigned int rows, cols;
-	int pr;
+	int pr, rdiff;
+
+	KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row,
+	    ("vtbuf_copy begin.tp_row %d must be less than screen width %d",
+		r->tr_begin.tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col,
+	    ("vtbuf_copy begin.tp_col %d must be less than screen height %d",
+		r->tr_begin.tp_col, vb->vb_scr_size.tp_col));
+
+	KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row,
+	    ("vtbuf_copy end.tp_row %d must be less than screen width %d",
+		r->tr_end.tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col,
+	    ("vtbuf_copy end.tp_col %d must be less than screen height %d",
+		r->tr_end.tp_col, vb->vb_scr_size.tp_col));
+
+	KASSERT(p2->tp_row < vb->vb_scr_size.tp_row,
+	    ("vtbuf_copy tp_row %d must be less than screen width %d",
+		p2->tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(p2->tp_col < vb->vb_scr_size.tp_col,
+	    ("vtbuf_copy tp_col %d must be less than screen height %d",
+		p2->tp_col, vb->vb_scr_size.tp_col));
 
 	rows = r->tr_end.tp_row - r->tr_begin.tp_row;
+	rdiff = r->tr_begin.tp_row - p2->tp_row;
 	cols = r->tr_end.tp_col - r->tr_begin.tp_col;
-
-	/* Handle overlapping copies. */
-	if (p2->tp_row < p1->tp_row) {
+	if (r->tr_begin.tp_row > p2->tp_row && r->tr_begin.tp_col == 0 &&
+	    r->tr_end.tp_col == vb->vb_scr_size.tp_col && /* Full row. */
+	    (rows + rdiff) == vb->vb_scr_size.tp_row && /* Whole screen. */
+	    rdiff > 0) { /* Only forward dirrection. Do not eat history. */
+		vthistory_addlines(vb, rdiff);
+	} else if (p2->tp_row < p1->tp_row) {
+		/* Handle overlapping copies of line segments. */
 		/* Move data up. */
 		for (pr = 0; pr < rows; pr++)
 			memmove(
@@ -157,74 +254,185 @@ vtbuf_copy(struct vt_buf *vb, const term
 	}
 
 	area.tr_begin = *p2;
-	area.tr_end.tp_row = p2->tp_row + rows;
-	area.tr_end.tp_col = p2->tp_col + cols;
+	area.tr_end.tp_row = MIN(p2->tp_row + rows, vb->vb_scr_size.tp_row);
+	area.tr_end.tp_col = MIN(p2->tp_col + cols, vb->vb_scr_size.tp_col);
 	vtbuf_dirty(vb, &area);
 }
 
-void
+static void
 vtbuf_fill(struct vt_buf *vb, const term_rect_t *r, term_char_t c)
 {
 	unsigned int pr, pc;
+	term_char_t *row;
+
+	for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++) {
+		row = vb->vb_rows[(vb->vb_curroffset + pr) %
+		    VTBUF_MAX_HEIGHT(vb)];
+		for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++) {
+			row[pc] = c;
+		}
+	}
+}
 
-	for (pr = r->tr_begin.tp_row; pr < r->tr_end.tp_row; pr++)
-		for (pc = r->tr_begin.tp_col; pc < r->tr_end.tp_col; pc++)
-			VTBUF_FIELD(vb, pr, pc) = c;
+void
+vtbuf_fill_locked(struct vt_buf *vb, const term_rect_t *r, term_char_t c)
+{
+	KASSERT(r->tr_begin.tp_row < vb->vb_scr_size.tp_row,
+	    ("vtbuf_fill_locked begin.tp_row %d must be < screen width %d",
+		r->tr_begin.tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(r->tr_begin.tp_col < vb->vb_scr_size.tp_col,
+	    ("vtbuf_fill_locked begin.tp_col %d must be < screen height %d",
+		r->tr_begin.tp_col, vb->vb_scr_size.tp_col));
+
+	KASSERT(r->tr_end.tp_row <= vb->vb_scr_size.tp_row,
+	    ("vtbuf_fill_locked end.tp_row %d must be <= screen width %d",
+		r->tr_end.tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(r->tr_end.tp_col <= vb->vb_scr_size.tp_col,
+	    ("vtbuf_fill_locked end.tp_col %d must be <= screen height %d",
+		r->tr_end.tp_col, vb->vb_scr_size.tp_col));
+
+	VTBUF_LOCK(vb);
+	vtbuf_fill(vb, r, c);
+	VTBUF_UNLOCK(vb);
 
 	vtbuf_dirty(vb, r);
 }
 
+static void
+vtbuf_init_rows(struct vt_buf *vb)
+{
+	int r;
+
+	vb->vb_history_size = MAX(vb->vb_history_size, vb->vb_scr_size.tp_row);
+
+	for (r = 0; r < vb->vb_history_size; r++)
+		vb->vb_rows[r] = &vb->vb_buffer[r *
+		    vb->vb_scr_size.tp_col];
+}
+
 void
 vtbuf_init_early(struct vt_buf *vb)
 {
 
 	vb->vb_flags |= VBF_CURSOR;
+	vb->vb_roffset = 0;
+	vb->vb_curroffset = 0;
+
+	vtbuf_init_rows(vb);
 	vtbuf_make_undirty(vb);
-	mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN);
+	if ((vb->vb_flags & VBF_MTX_INIT) == 0) {
+		mtx_init(&vb->vb_lock, "vtbuf", NULL, MTX_SPIN);
+		vb->vb_flags |= VBF_MTX_INIT;
+	}
 }
 
 void
 vtbuf_init(struct vt_buf *vb, const term_pos_t *p)
 {
+	int sz;
+
+	vb->vb_scr_size = *p;
+	vb->vb_history_size = VBF_DEFAULT_HISTORY_SIZE;
+
+	if ((vb->vb_flags & VBF_STATIC) == 0) {
+		sz = vb->vb_history_size * p->tp_col * sizeof(term_char_t);
+		vb->vb_buffer = malloc(sz, M_VTBUF, M_WAITOK);
+
+		sz = vb->vb_history_size * sizeof(term_char_t *);
+		vb->vb_rows = malloc(sz, M_VTBUF, M_WAITOK);
+	}
 
-	vb->vb_size = *p;
-	vb->vb_buffer = malloc(p->tp_row * p->tp_col * sizeof(term_char_t),
-	    M_VTBUF, M_WAITOK);
 	vtbuf_init_early(vb);
 }
 
 void
-vtbuf_grow(struct vt_buf *vb, const term_pos_t *p)
+vtbuf_sethistory_size(struct vt_buf *vb, int size)
+{
+	term_pos_t p;
+
+	/* With same size */
+	p.tp_row = vb->vb_scr_size.tp_row;
+	p.tp_col = vb->vb_scr_size.tp_col;
+	vtbuf_grow(vb, &p, size);
+}
+
+void
+vtbuf_grow(struct vt_buf *vb, const term_pos_t *p, int history_size)
 {
-	term_char_t *old, *new;
+	term_char_t *old, *new, **rows, **oldrows, **copyrows, *row;
+	int bufsize, rowssize, w, h, c, r;
+	term_rect_t rect;
 
-	if (p->tp_row > vb->vb_size.tp_row ||
-	    p->tp_col > vb->vb_size.tp_col) {
+	history_size = MAX(history_size, p->tp_row);
+
+	if (history_size > vb->vb_history_size || p->tp_col >
+	    vb->vb_scr_size.tp_col) {
 		/* Allocate new buffer. */
-		new = malloc(p->tp_row * p->tp_col * sizeof(term_char_t),
-		    M_VTBUF, M_WAITOK|M_ZERO);
+		bufsize = history_size * p->tp_col * sizeof(term_char_t);
+		new = malloc(bufsize, M_VTBUF, M_WAITOK|M_ZERO);
+		rowssize = history_size * sizeof(term_pos_t *);
+		rows = malloc(rowssize, M_VTBUF, M_WAITOK|M_ZERO);
 
 		/* Toggle it. */
 		VTBUF_LOCK(vb);
 		old = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_buffer;
+		oldrows = vb->vb_flags & VBF_STATIC ? NULL : vb->vb_rows;
+		copyrows = vb->vb_rows;
+		w = vb->vb_scr_size.tp_col;
+		h = vb->vb_history_size;
+
+		vb->vb_history_size = history_size;
 		vb->vb_buffer = new;
+		vb->vb_rows = rows;
 		vb->vb_flags &= ~VBF_STATIC;
-		vb->vb_size = *p;
+		vb->vb_scr_size = *p;
+		vtbuf_init_rows(vb);
+
+		/* Copy history and fill extra space. */
+		for (r = 0; r < history_size; r ++) {
+			row = rows[r];
+			if (r < h) { /* Copy. */
+				memmove(rows[r], copyrows[r],
+				    MIN(p->tp_col, w) * sizeof(term_char_t));
+				for (c = MIN(p->tp_col, w); c < p->tp_col;
+				    c++) {
+					row[c] = VTBUF_SPACE_CHAR;
+				}
+			} else { /* Just fill. */
+				rect.tr_begin.tp_col = 0;
+				rect.tr_begin.tp_row = r;
+				rect.tr_end.tp_col = p->tp_col;
+				rect.tr_end.tp_row = p->tp_row;
+				vtbuf_fill(vb, &rect, VTBUF_SPACE_CHAR);
+				break;
+			}
+		}
 		vtbuf_make_undirty(vb);
 		VTBUF_UNLOCK(vb);
-
 		/* Deallocate old buffer. */
-		if (old != NULL)
-			free(old, M_VTBUF);
+		free(old, M_VTBUF);
+		free(oldrows, M_VTBUF);
 	}
 }
 
 void
 vtbuf_putchar(struct vt_buf *vb, const term_pos_t *p, term_char_t c)
 {
+	term_char_t *row;
 
-	if (VTBUF_FIELD(vb, p->tp_row, p->tp_col) != c) {
-		VTBUF_FIELD(vb, p->tp_row, p->tp_col) = c;
+	KASSERT(p->tp_row < vb->vb_scr_size.tp_row,
+	    ("vtbuf_putchar tp_row %d must be less than screen width %d",
+		p->tp_row, vb->vb_scr_size.tp_row));
+	KASSERT(p->tp_col < vb->vb_scr_size.tp_col,
+	    ("vtbuf_putchar tp_col %d must be less than screen height %d",
+		p->tp_col, vb->vb_scr_size.tp_col));
+
+	row = vb->vb_rows[(vb->vb_curroffset + p->tp_row) %
+	    VTBUF_MAX_HEIGHT(vb)];
+	if (row[p->tp_col] != c) {
+		VTBUF_LOCK(vb);
+		row[p->tp_col] = c;
+		VTBUF_UNLOCK(vb);
 		vtbuf_dirty_cell(vb, p);
 	}
 }

Modified: user/ed/newcons/sys/dev/vt/vt_core.c
==============================================================================
--- user/ed/newcons/sys/dev/vt/vt_core.c	Tue Oct  8 12:03:40 2013	(r256144)
+++ user/ed/newcons/sys/dev/vt/vt_core.c	Tue Oct  8 12:40:04 2013	(r256145)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/mutex.h>
+#include <sys/proc.h>
 #include <sys/reboot.h>
 #include <sys/systm.h>
 #include <sys/terminal.h>
@@ -97,8 +98,16 @@ const struct terminal_class vt_termclass
 #define	VT_UNIT(vw)	((vw)->vw_device->vd_unit * VT_MAXWINDOWS + \
 			(vw)->vw_number)
 
+/* XXX while syscons is here. */
+int sc_txtmouse_no_retrace_wait;
+
+static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD, 0, "Newcons parameters");
+VT_SYSCTL_INT(debug, 0, "Newcons debug level");
+VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
+
 static unsigned int vt_unit = 0;
 static MALLOC_DEFINE(M_VT, "vt", "vt device");
+struct vt_device *main_vd = NULL;
 
 /* Boot logo. */
 extern unsigned int vt_logo_width;
@@ -109,29 +118,136 @@ extern unsigned char vt_logo_image[];
 /* Font. */
 extern struct vt_font vt_font_default;
 
+static int signal_vt_rel(struct vt_window *);
+static int signal_vt_acq(struct vt_window *);
+static int finish_vt_rel(struct vt_window *, int, int *);
+static int finish_vt_acq(struct vt_window *);
+static int vt_window_switch(struct vt_window *);
+static int vt_late_window_switch(struct vt_window *);
+static int vt_proc_alive(struct vt_window *);
+static void vt_resize(struct vt_device *);
+
 static void
+vt_switch_timer(void *arg)
+{
+
+	vt_late_window_switch((struct vt_window *)arg);
+}
+
+static int
+vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
+{
+
+	DPRINTF(40, "%s\n", __func__);
+	curvw->vw_switch_to = vw;
+	/* Set timer to allow switch in case when process hang. */
+	callout_reset(&vw->vw_proc_dead_timer, hz * vt_deadtimer,
+	    vt_switch_timer, (void *)vw);
+	/* Notify process about vt switch attempt. */
+	DPRINTF(30, "%s: Notify process.\n", __func__);
+	signal_vt_rel(curvw);
+
+	return (0);
+}
+
+static int
+vt_window_postswitch(struct vt_window *vw)
+{
+
+	signal_vt_acq(vw);
+	return (0);
+}
+
+/* vt_late_window_switch will done VT switching for regular case. */
+static int
+vt_late_window_switch(struct vt_window *vw)
+{
+	int ret;
+
+	callout_stop(&vw->vw_proc_dead_timer);
+
+	ret = vt_window_switch(vw);
+	if (ret)
+		return (ret);
+
+	/* Notify owner process about terminal availability. */
+	if (vw->vw_smode.mode == VT_PROCESS) {
+		ret = vt_window_postswitch(vw);
+	}
+	return (ret);
+}
+
+/* Switch window. */
+static int
+vt_proc_window_switch(struct vt_window *vw)
+{
+	struct vt_window *curvw;
+	struct vt_device *vd;
+	int ret;
+
+	if (vw->vw_flags & VWF_VTYLOCK)
+		return (EBUSY);
+
+	vd = vw->vw_device;
+	curvw = vd->vd_curwindow;
+
+	/* Ask current process permitions to switch away. */
+	if (curvw->vw_smode.mode == VT_PROCESS) {
+		DPRINTF(30, "%s: VT_PROCESS ", __func__);
+		if (vt_proc_alive(curvw) == FALSE) {
+			DPRINTF(30, "Dead. Cleaning.");
+			/* Dead */
+		} else {
+			DPRINTF(30, "%s: Signaling process.\n", __func__);
+			/* Alive, try to ask him. */
+			ret = vt_window_preswitch(vw, curvw);
+			/* Wait for process answer or timeout. */
+			return (ret);
+		}
+		DPRINTF(30, "\n");
+	}
+
+	ret = vt_late_window_switch(vw);
+	return (ret);
+}
+
+/* Switch window ignoring process locking. */
+static int
 vt_window_switch(struct vt_window *vw)
 {
 	struct vt_device *vd = vw->vw_device;
+	struct vt_window *curvw = vd->vd_curwindow;
 	keyboard_t *kbd;
 
 	VT_LOCK(vd);
-	if (vd->vd_curwindow == vw ||
-	    !(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
+	if (curvw == vw) {
+		/* Nothing to do. */
 		VT_UNLOCK(vd);
-		return;
+		return (0);
 	}
+	if (!(vw->vw_flags & (VWF_OPENED|VWF_CONSOLE))) {
+		VT_UNLOCK(vd);
+		return (EINVAL);
+	}
+
 	vd->vd_curwindow = vw;
 	vd->vd_flags |= VDF_INVALID;
 	cv_broadcast(&vd->vd_winswitch);
 	VT_UNLOCK(vd);
 
+	if (vd->vd_driver->vd_postswitch)
+		vd->vd_driver->vd_postswitch(vd);
+
 	/* Restore per-window keyboard mode. */
 	mtx_lock(&Giant);
 	kbd = kbd_get_keyboard(vd->vd_keyboard);
-	if (kbd != NULL)
+	if (kbd != NULL) {
 		kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode);
+	}
 	mtx_unlock(&Giant);
+	DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
+
+	return (0);
 }
 
 static inline void
@@ -163,7 +279,7 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 {
 	struct vt_device *vd = arg;
 	struct vt_window *vw = vd->vd_curwindow;
-	u_int c;
+	int c;
 
 	switch (event) {
 	case KBDIO_KEYINPUT:
@@ -188,7 +304,7 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 		if (c >= F_SCR && c <= MIN(L_SCR, F_SCR + VT_MAXWINDOWS - 1)) {
 			vw = vd->vd_windows[c - F_SCR];
 			if (vw != NULL)
-				vt_window_switch(vw);
+				vt_proc_window_switch(vw);
 			return (0);
 		}
 
@@ -214,10 +330,13 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 			if (state & SLKED) {
 				/* Turn scrolling on. */
 				vw->vw_flags |= VWF_SCROLL;
+				VTBUF_SLCK_ENABLE(&vw->vw_buf);
 			} else {
 				/* Turn scrolling off. */
 				vw->vw_flags &= ~VWF_SCROLL;
-				vthistory_seek(&vw->vw_history, 0, VHS_SET);
+				VTBUF_SLCK_DISABLE(&vw->vw_buf);
+				vthistory_seek(&vw->vw_buf, 0, VHS_END);
+				vd->vd_flags |= VDF_INVALID;
 			}
 			VT_UNLOCK(vd);
 			break;
@@ -233,7 +352,8 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 		case FKEY | F(49): /* Home key. */
 			VT_LOCK(vd);
 			if (vw->vw_flags & VWF_SCROLL) {
-				vthistory_seek(&vw->vw_history, 0, VHS_END);
+				if (vthistory_seek(&vw->vw_buf, 0, VHS_END))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -243,7 +363,8 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 		case FKEY | F(50): /* Arrow up. */
 			VT_LOCK(vd);
 			if (vw->vw_flags & VWF_SCROLL) {
-				vthistory_seek(&vw->vw_history, 1, VHS_CUR);
+				if (vthistory_seek(&vw->vw_buf, -1, VHS_CUR))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -256,8 +377,9 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 				term_pos_t size;
 
 				vt_termsize(vd, vw->vw_font, &size);
-				vthistory_seek(&vw->vw_history, size.tp_row,
-				    VHS_CUR);
+				if (vthistory_seek(&vw->vw_buf, -size.tp_row,
+				    VHS_CUR))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -273,7 +395,8 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 		case FKEY | F(57): /* End key. */
 			VT_LOCK(vd);
 			if (vw->vw_flags & VWF_SCROLL) {
-				vthistory_seek(&vw->vw_history, 0, VHS_SET);
+				if (vthistory_seek(&vw->vw_buf, 0, VHS_SET))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -283,7 +406,8 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 		case FKEY | F(58): /* Arrow down. */
 			VT_LOCK(vd);
 			if (vw->vw_flags & VWF_SCROLL) {
-				vthistory_seek(&vw->vw_history, -1, VHS_CUR);
+				if (vthistory_seek(&vw->vw_buf, 1, VHS_CUR))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -296,8 +420,9 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 				term_pos_t size;
 
 				vt_termsize(vd, vw->vw_font, &size);
-				vthistory_seek(&vw->vw_history, -size.tp_row,
-				    VHS_CUR);
+				if (vthistory_seek(&vw->vw_buf, size.tp_row,
+				    VHS_CUR))
+					vd->vd_flags |= VDF_INVALID;
 				VT_UNLOCK(vd);
 				break;
 			}
@@ -312,15 +437,12 @@ vt_kbdevent(keyboard_t *kbd, int event, 
 			break;
 		}
 	} else if (KEYFLAGS(c) == 0) {
-		c = KEYCHAR(c);
-
 		/* Don't do UTF-8 conversion when doing raw mode. */
 		if (vw->vw_kbdmode == K_XLATE)
-			terminal_input_char(vw->vw_terminal, c);
+			terminal_input_char(vw->vw_terminal, KEYCHAR(c));
 		else
 			terminal_input_raw(vw->vw_terminal, c);
 	}
-	
 	return (0);
 }
 
@@ -333,7 +455,10 @@ vt_allocate_keyboard(struct vt_device *v
 
 	idx0 = kbd_allocate("kbdmux", -1, (void *)&vd->vd_keyboard,
 	    vt_kbdevent, vd);
+	/* XXX: kb_token lost */
+	vd->vd_keyboard = idx0;
 	if (idx0 != -1) {
+		DPRINTF(20, "%s: kbdmux allocated, idx = %d\n", __func__, idx0);
 		k0 = kbd_get_keyboard(idx0);
 
 		for (idx = kbd_find_keyboard2("*", -1, 0);
@@ -350,9 +475,12 @@ vt_allocate_keyboard(struct vt_device *v
 
 			kbdd_ioctl(k0, KBADDKBD, (caddr_t) &ki);
 		}
-	} else
+	} else {
+		DPRINTF(20, "%s: no kbdmux allocated\n", __func__);
 		idx0 = kbd_allocate("*", -1, (void *)&vd->vd_keyboard,
 		    vt_kbdevent, vd);
+	}
+	DPRINTF(20, "%s: vd_keyboard = %d\n", __func__, vd->vd_keyboard);
 
 	return (idx0);
 }
@@ -385,7 +513,7 @@ vtterm_fill(struct terminal *tm, const t
 {
 	struct vt_window *vw = tm->tm_softc;
 
-	vtbuf_fill(&vw->vw_buf, r, c);
+	vtbuf_fill_locked(&vw->vw_buf, r, c);
 }
 
 static void
@@ -393,24 +521,6 @@ vtterm_copy(struct terminal *tm, const t
     const term_pos_t *p)
 {
 	struct vt_window *vw = tm->tm_softc;
-	struct vt_device *vd = vw->vw_device;
-	term_pos_t size;
-
-	/*
-	 * We copy lines into the history buffer when we have to do a
-	 * copy of the entire width of the screen to a region above it.
-	 */
-	vt_termsize(vd, vw->vw_font, &size);
-	if (r->tr_begin.tp_row > p->tp_row &&
-	    r->tr_begin.tp_col == 0 && r->tr_end.tp_col == size.tp_col) {
-		term_rect_t area;
-
-		area.tr_begin.tp_row = p->tp_row;
-		area.tr_begin.tp_col = 0;
-		area.tr_end.tp_row = r->tr_begin.tp_row;
-		area.tr_end.tp_col = size.tp_col;
-		vthistory_add(&vw->vw_history, &vw->vw_buf, &area);
-	}
 
 	vtbuf_copy(&vw->vw_buf, r, p);
 }
@@ -491,18 +601,17 @@ vt_flush(struct vt_device *vd)
 	term_pos_t size;
 	term_rect_t tarea;
 	struct vt_bufmask tmask;
-	unsigned int row, col, scrollpos;
-	term_char_t c;
+	unsigned int row, col;
+	term_char_t *r;
 
 	if (vd->vd_flags & VDF_SPLASH || vw->vw_flags & VWF_BUSY)
 		return;
 
 	vtbuf_undirty(&vw->vw_buf, &tarea, &tmask);
-	vthistory_getpos(&vw->vw_history, &scrollpos);
 	vt_termsize(vd, vf, &size);
 
 	/* Force a full redraw when the screen contents are invalid. */
-	if (vd->vd_scrollpos != scrollpos || vd->vd_flags & VDF_INVALID) {
+	if (vd->vd_flags & VDF_INVALID) {
 		tarea.tr_begin.tp_row = tarea.tr_begin.tp_col = 0;
 		tarea.tr_end = size;
 		tmask.vbm_row = tmask.vbm_col = VBM_DIRTY;
@@ -517,43 +626,22 @@ vt_flush(struct vt_device *vd)
 		    vd->vd_height % vf->vf_height != 0))
 			vd->vd_driver->vd_blank(vd, TC_BLACK);
 
-		/* Draw the scrollback history. */
-		for (row = 0; row < scrollpos; row++) {
-			for (col = 0; col < size.tp_col; col++) {
-				c = VTHISTORY_FIELD(&vw->vw_history, row, col);
-				vt_bitblt_char(vd, vf, c, 0, row, col);
-			}
-		}
-
 		vd->vd_flags &= ~VDF_INVALID;
-		vd->vd_scrollpos = scrollpos;
 	}
 
-	/*
-	 * Clamp the terminal rendering size if it exceeds the window
-	 * size, because of scrollback.
-	 */
-	if (tarea.tr_end.tp_row + scrollpos > size.tp_row) {
-		if (size.tp_row <= scrollpos)
-			/* Terminal completely invisible. */
-			tarea.tr_end.tp_row = 0;
-		else
-			/* Terminal partially visible. */
-			tarea.tr_end.tp_row = size.tp_row - scrollpos;
-	}
 
 	for (row = tarea.tr_begin.tp_row; row < tarea.tr_end.tp_row; row++) {
 		if (!VTBUF_DIRTYROW(&tmask, row))
 			continue;
+		r = VTBUF_GET_ROW(&vw->vw_buf, row);
 		for (col = tarea.tr_begin.tp_col;
 		    col < tarea.tr_end.tp_col; col++) {
 			if (!VTBUF_DIRTYCOL(&tmask, col))
 				continue;
 
-			c = VTBUF_FIELD(&vw->vw_buf, row, col);
-			vt_bitblt_char(vd, vf, c,
+			vt_bitblt_char(vd, vf, r[col],
 			    VTBUF_ISCURSOR(&vw->vw_buf, row, col),
-			    row + scrollpos, col);
+			    row, col);
 		}
 	}
 }

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310081240.r98Ce4fU098558>