svn commit: r256145 - in user/ed/newcons/sys/dev/vt: . hw/intel hw/ofwfb hw/vga hw/xboxfb
Aleksandr Rybalko
ray at FreeBSD.org
Tue Oct 8 12:40:05 UTC 2013
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 ***
More information about the svn-src-user
mailing list