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>