Subject: kern/17243: scrolling support for wscons
To: None <gnats-bugs@gnats.netbsd.org>
From: David Ferlier <krp@freeshell.org>
List: netbsd-bugs
Date: 06/13/2002 03:23:52
>Number:         17243
>Category:       kern
>Synopsis:       support the scroll on wscons terminals
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Jun 12 18:23:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     David Ferlier
>Release:        NetBSD 1.6A
>Organization:
none
>Environment:

cpu0:Intem Pentium/MMX (586-class), 166.20 MHz

NetBSD cobaye 1.6A NetBSD 1.6A (COBAYE) #11: Thu Jun 13 02:03:22 CEST 2002     root@cobaye:/usr/src/sys/arch/i386/compile/COBAYE i386

Machine: i386
>Description:

A first try to add the ability to scroll back on wscons terminals.
Keys to scroll back are Shift (right or left) + PgUp/PgDown. (we can change that if we want). I handle the event in wskbd_translate, but there's surely a better way to do this.

The attached patch works on a 1.6A box (i386). There are no apparent bugs (though there could be some).

Besides this feature, i'd like to add an option in wsconsctl which would allow to customize the number of lines to scroll back. And maybe this option would be settable for each terminal. I will finish it soon.

>How-To-Repeat:
not relevant ...
>Fix:

Index: sys/dev/ic/vga.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/vga.c,v
retrieving revision 1.50
diff -u -r1.50 vga.c
--- vga.c	2002/04/04 13:08:35	1.50
+++ vga.c	2002/06/13 00:09:03
@@ -92,6 +92,8 @@
 	/* palette */
 
 	int mindispoffset, maxdispoffset;
+	int vga_rollover;
+	int visibleoffset;
 };
 
 static int vgaconsole, vga_console_type, vga_console_attached;
@@ -109,13 +111,15 @@
 static void vga_setfont(struct vga_config *, struct vgascreen *);
 
 static int vga_mapchar(void *, int, unsigned int *);
+void vga_putchar __P((void *, int, int, u_int, long));
 static int vga_alloc_attr(void *, int, int, int, long *);
 static void vga_copyrows(void *, int, int, int);
+void vga_scroll __P((void *, void *, int));
 
 const struct wsdisplay_emulops vga_emulops = {
 	pcdisplay_cursor,
 	vga_mapchar,
-	pcdisplay_putchar,
+	vga_putchar,
 	pcdisplay_copycols,
 	pcdisplay_erasecols,
 	vga_copyrows,
@@ -256,7 +260,8 @@
 	vga_alloc_screen,
 	vga_free_screen,
 	vga_show_screen,
-	vga_load_font
+	vga_load_font,
+	vga_scroll
 };
 
 /*
@@ -501,6 +506,9 @@
 		scr->pcs.dispoffset = scr->mindispoffset;
 	}
 
+	scr->pcs.visibleoffset = scr->pcs.dispoffset;
+	scr->vga_rollover = 0;
+
 	scr->pcs.vc_crow = cpos / type->ncols;
 	scr->pcs.vc_ccol = cpos % type->ncols;
 	pcdisplay_cursor_init(&scr->pcs, existing);
@@ -1290,3 +1298,65 @@
 	*index = idx1;
 	return (res1);
 }
+
+void
+vga_scroll(v, cookie, lines)
+	void *v;
+	void *cookie;
+	int lines;
+{
+	struct vga_config *vc = v;
+	struct vgascreen *scr = cookie;
+	struct vga_handle *vh = &vc->hdl;
+
+	if (lines == 0) {
+		if (scr->pcs.visibleoffset == scr->pcs.dispoffset)
+			return;
+
+		scr->pcs.visibleoffset = scr->pcs.dispoffset;	/* reset */
+	}
+	else {
+		int vga_scr_end;
+		int margin = scr->pcs.type->ncols * 2;
+		int ul, we, p, st;
+
+		vga_scr_end = (scr->pcs.dispoffset + scr->pcs.type->ncols *
+		    scr->pcs.type->nrows * 2);
+		if (scr->vga_rollover > vga_scr_end + margin) {
+			ul = vga_scr_end;
+			we = scr->vga_rollover + scr->pcs.type->ncols * 2;
+		} else {
+			ul = 0;
+			we = 0x8000;
+		}
+		p = (scr->pcs.visibleoffset - ul + we) % we + lines *
+		    (scr->pcs.type->ncols * 2);
+		st = (scr->pcs.dispoffset - ul + we) % we;
+		if (p < margin)
+			p = 0;
+		if (p > st - margin)
+			p = st;
+		scr->pcs.visibleoffset = (p + ul) % we;
+	}
+	
+	/* update visible position */
+	vga_6845_write(vh, startadrh, scr->pcs.visibleoffset >> 9);
+	vga_6845_write(vh, startadrl, scr->pcs.visibleoffset >> 1);
+}
+
+void
+vga_putchar(c, row, col, uc, attr)
+	void *c;
+	int row;
+	int col;
+	u_int uc;
+	long attr;
+{
+	struct vgascreen *scr = c;
+
+	if (scr->pcs.visibleoffset != scr->pcs.dispoffset)
+		vga_scroll(scr->cfg, scr, WSDISPLAY_SCROLL_BACKWARD);
+
+	pcdisplay_putchar(c, row, col, uc, attr);
+}
+
Index: sys/dev/ic/pcdisplayvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/pcdisplayvar.h,v
retrieving revision 1.8
diff -u -r1.8 pcdisplayvar.h
--- pcdisplayvar.h	2000/01/25 02:44:03	1.8
+++ pcdisplayvar.h	2002/06/13 00:09:05
@@ -49,6 +49,7 @@
 	int vc_ccol, vc_crow;	/* current cursor position */
 
 	int dispoffset; /* offset of displayed area in video mem */
+	int visibleoffset;
 };
 
 struct pcdisplay_handle {
Index: sys/dev/wscons/wsdisplay.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsdisplay.c,v
retrieving revision 1.63
diff -u -r1.63 wsdisplay.c
--- wsdisplay.c	2002/04/07 09:25:47	1.63
+++ wsdisplay.c	2002/06/13 00:09:25
@@ -397,6 +397,29 @@
 	vdevgone(maj, mn, mn, VCHR);
 }
 
+void
+wsscroll(arg, op)
+	void *arg;
+	int op;
+{
+	struct wsdisplay_softc *sc = arg;
+	int lines;
+
+	if (op == WSDISPLAY_SCROLL_RESET)
+		lines = 0;
+	else {
+		lines = sc->sc_focus->scr_dconf->scrdata->nrows - 1;
+		if (op == WSDISPLAY_SCROLL_BACKWARD)
+			lines = -lines;
+	}
+
+	if (sc->sc_accessops->scroll) {
+		(*sc->sc_accessops->scroll)(sc->sc_accesscookie,
+		    sc->sc_focus->scr_dconf->emulcookie, lines);
+	}
+}
+
+
 int
 wsdisplay_delscreen(struct wsdisplay_softc *sc, int idx, int flags)
 {
Index: sys/dev/wscons/wsdisplayvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wsdisplayvar.h,v
retrieving revision 1.20
diff -u -r1.20 wsdisplayvar.h
--- wsdisplayvar.h	2001/10/13 15:56:15	1.20
+++ wsdisplayvar.h	2002/06/13 00:09:28
@@ -106,6 +106,7 @@
 	int	(*show_screen)(void *, void *, int,
 				    void (*) (void *, int, int), void *);
 	int	(*load_font)(void *, void *, struct wsdisplay_font *);
+	void	(*scroll) __P((void *, void *, int));
 	void	(*pollc)(void *, int);
 };
 
@@ -188,6 +189,12 @@
 
 int wsdisplay_cfg_ioctl(struct wsdisplay_softc *sc, u_long cmd, caddr_t data,
 			int flag, struct proc *p);
+
+void wsscroll __P((void *v, int op));
+
+#define WSDISPLAY_SCROLL_BACKWARD	0
+#define WSDISPLAY_SCROLL_FORWARD	1
+#define WSDISPLAY_SCROLL_RESET		2
 
 /*
  * for general use
Index: sys/dev/wscons/wskbd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/wscons/wskbd.c,v
retrieving revision 1.61
diff -u -r1.61 wskbd.c
--- wskbd.c	2002/03/17 19:41:06	1.61
+++ wskbd.c	2002/06/13 00:09:42
@@ -113,6 +113,7 @@
 #include <dev/wscons/wskbdvar.h>
 #include <dev/wscons/wsksymdef.h>
 #include <dev/wscons/wsksymvar.h>
+#include <dev/wscons/wsdisplayvar.h>
 #include <dev/wscons/wseventvar.h>
 #include <dev/wscons/wscons_callbacks.h>
 
@@ -579,6 +580,9 @@
 		num = wskbd_translate(sc->id, type, value);
 		if (num > 0) {
 			if (sc->sc_base.me_dispdv != NULL) {
+				if (sc->id->t_symbols [0] != KS_Print_Screen) {
+					wsscroll (sc->sc_base.me_dispdv, WSDISPLAY_SCROLL_RESET);
+				}
 				for (i = 0; i < num; i++)
 					wsdisplay_kbdinput(
 						sc->sc_base.me_dispdv,
@@ -1465,6 +1469,26 @@
 	case KS_Num_Lock:
 		update_modifier(id, type, 1, MOD_NUMLOCK);
 		break;
+
+	case KS_Prior:
+		if (type == WSCONS_EVENT_KEY_DOWN) {
+			if (MOD_ONESET (sc->id, MOD_ANYSHIFT)) {
+				wsscroll(sc->sc_base.me_dispdv,
+				    WSDISPLAY_SCROLL_BACKWARD);
+				return (1);
+			} else
+				break;
+		}
+
+	case KS_Next:
+		if (type == WSCONS_EVENT_KEY_DOWN) {
+			if (MOD_ONESET (sc->id, MOD_ANYSHIFT)) {
+				wsscroll(sc->sc_base.me_dispdv,
+				    WSDISPLAY_SCROLL_FORWARD);
+				return (1);
+			} else 
+				break;
+		}
 
 #if NWSDISPLAY > 0
 	case KS_Hold_Screen:

>Release-Note:
>Audit-Trail:
>Unformatted: