Subject: Patch to add console scrollback support.
To: None <tech-kern@netbsd.org>
From: justin <lifter@crosswinds.net>
List: tech-kern
Date: 05/31/2001 23:36:04
Hi guys,

I've ported over the work that OpenBSD did with WSCONS to support console
scrollback. The key sequence on i386 is left ctrl+alt+shift+pg_up or pg_down.

The patch is for NetBSD 1.5.1_BETA_2, but I'm going to assume that it should be
pretty easy to apply it to -current. Since I'm not subscribed to the list,
please CC any comments to lifter@crosswinds.net.

If anybody gets this working, or doesn't get it working, please drop me a line
ASAP.

Thanks a lot!

Regards,
Justin Reigle


--- sys/dev/ic/pcdisplay_subr.c.orig	Thu May 31 22:59:33 2001
+++ sys/dev/ic/pcdisplay_subr.c	Thu May 31 21:49:17 2001
@@ -160,6 +160,25 @@
 		scr->mem[off] = c | (attr << 8);
 }
 
+u_int16_t
+pcdisplay_getchar(id, row, col)
+	void *id;
+	int row, col;
+{
+	struct pcdisplayscreen *scr = id;
+	bus_space_tag_t memt = scr->hdl->ph_memt;
+	bus_space_handle_t memh = scr->hdl->ph_memh;
+	int off;
+
+	off = row * scr->type->ncols + col;
+
+	if (scr->active)
+		return (bus_space_read_2(memt, memh,
+					scr->dispoffset + off * 2));
+	else
+		return (scr->mem[off]);
+}
+
 void
 pcdisplay_copycols(id, row, srccol, dstcol, ncols)
 	void *id;
--- sys/dev/ic/pcdisplayvar.h.orig	Thu May 31 22:59:57 2001
+++ sys/dev/ic/pcdisplayvar.h	Thu May 31 21:24:37 2001
@@ -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 {
@@ -90,6 +91,7 @@
 #endif
 int pcdisplay_mapchar __P((void *, int, unsigned int *));
 void	pcdisplay_putchar __P((void *, int, int, u_int, long));
+u_int16_t pcdisplay_getchar __P((void *, int, int));
 void	pcdisplay_copycols __P((void *, int, int, int,int));
 void	pcdisplay_erasecols __P((void *, int, int, int, long));
 void	pcdisplay_copyrows __P((void *, int, int, int));
--- sys/dev/usb/ukbdmap.c.orig	Thu May 31 23:19:23 2001
+++ sys/dev/usb/ukbdmap.c	Thu May 31 23:20:29 2001
@@ -118,10 +118,10 @@
     KC(72),			KS_Pause,
     KC(73),			KS_Insert, 
     KC(74),			KS_Home,
-    KC(75), 			KS_Prior,
+    KC(75), KS_Cmd_ScrollBack,	KS_Prior,
     KC(76),			KS_Delete,
     KC(77),			KS_End,
-    KC(78), 			KS_Next,
+    KC(78), KS_Cmd_ScrollFwd,	KS_Next,
     KC(79),			KS_Right,
     KC(80),			KS_Left,
     KC(81),			KS_Down,
--- sys/dev/ic/vga.c.orig	Thu May 31 23:05:22 2001
+++ sys/dev/ic/vga.c	Thu May 31 21:57:16 2001
@@ -80,6 +80,7 @@
 	/* palette */
 
 	int mindispoffset, maxdispoffset;
+	int vga_rollover;
 };
 
 struct vga_config {
@@ -122,13 +123,16 @@
 static void vga_setfont __P((struct vga_config *, struct vgascreen *));
 
 static int vga_mapchar __P((void *, int, unsigned int *));
+void vga_putchar __P((void *, int, int, u_int, long));
 static int	vga_alloc_attr __P((void *, int, int, int, long *));
 void	vga_copyrows __P((void *, int, int, int));
+void	vga_scrollback __P((void *, void *, int));
+u_int16_t vga_getchar __P((void *, int, int));
 
 const struct wsdisplay_emulops vga_emulops = {
 	pcdisplay_cursor,
 	vga_mapchar,
-	pcdisplay_putchar,
+	vga_putchar,
 	pcdisplay_copycols,
 	pcdisplay_erasecols,
 	vga_copyrows,
@@ -269,7 +273,9 @@
 	vga_alloc_screen,
 	vga_free_screen,
 	vga_show_screen,
-	vga_load_font
+	vga_load_font,
+	vga_scrollback,
+	vga_getchar
 };
 
 /*
@@ -905,6 +911,52 @@
 	return (0);
 }
 
+
+void
+vga_scrollback(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);
+}
+
 static int
 vga_alloc_attr(id, fg, bg, flags, attrp)
 	void *id;
@@ -1193,3 +1245,29 @@
 	*index = idx1;
 	return (res1);
 }
+
+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_scrollback(scr->cfg, scr, 0);
+
+	pcdisplay_putchar(c, row, col, uc, attr);
+}
+
+u_int16_t
+vga_getchar(c, row, col)
+	void *c;
+	int row, col;
+{
+	struct vga_config *vc = c;
+	
+	return (pcdisplay_getchar(vc->active, row, col));
+}	
--- sys/dev/wscons/wsdisplay.c.orig	Thu May 31 23:11:46 2001
+++ sys/dev/wscons/wsdisplay.c	Thu May 31 20:46:32 2001
@@ -1799,6 +1799,29 @@
 	}
 }
 
+
+void
+wsscrollback(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->scrollback) {
+		(*sc->sc_accessops->scrollback)(sc->sc_accesscookie,
+		    sc->sc_focus->scr_dconf->emulcookie, lines);
+	}
+}
+
 /*
  * Switch the console at shutdown.
  */
--- sys/dev/wscons/wsdisplayvar.h.orig	Thu May 31 23:11:56 2001
+++ sys/dev/wscons/wsdisplayvar.h	Thu May 31 20:49:40 2001
@@ -110,6 +110,9 @@
 	int	(*show_screen) __P((void *, void *, int,
 				    void (*) (void *, int, int), void *));
 	int	(*load_font) __P((void *, void *, struct wsdisplay_font *));
+	void	(*scrollback) __P((void *, void *, int));
+	u_int16_t (*getchar) __P((void *, int, int));
+	void	(*pollc) __P((void *, int));
 };
 
 /*
@@ -198,3 +201,9 @@
  * for general use
  */
 void wsdisplay_switchtoconsole __P((void));
+
+void wsscrollback __P((void *, int));
+
+#define WSDISPLAY_SCROLL_BACKWARD	0
+#define WSDISPLAY_SCROLL_FORWARD	1
+#define WSDISPLAY_SCROLL_RESET		2
--- sys/dev/wscons/wskbd.c.orig	Thu May 31 23:12:18 2001
+++ sys/dev/wscons/wskbd.c	Thu May 31 22:29:18 2001
@@ -109,6 +109,7 @@
 #include <dev/wscons/wsksymvar.h>
 #include <dev/wscons/wseventvar.h>
 #include <dev/wscons/wscons_callbacks.h>
+#include <dev/wscons/wsdisplayvar.h>
 
 #include "opt_wsdisplay_compat.h"
 
@@ -580,6 +581,11 @@
 		num = wskbd_translate(sc->id, type, value);
 		if (num > 0) {
 			if (sc->sc_displaydv != NULL) {
+				/* XXX - Shift_R+PGUP(release) emits PrtSc */
+				if (sc->id->t_symbols[0] != KS_Print_Screen) {
+					wsscrollback(sc->sc_displaydv,
+					    WSDISPLAY_SCROLL_RESET);
+				}
 				for (i = 0; i < num; i++)
 					wsdisplay_kbdinput(sc->sc_displaydv,
 						sc->id->t_symbols[i]);
@@ -1299,6 +1305,25 @@
 	    (! MOD_ONESET(sc->id, MOD_COMMAND) &&
 	     ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
 		return (0);
+
+
+#if NWSDISPLAY > 0
+	switch (ksym) {
+	case KS_Cmd_ScrollBack:
+		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
+			wsscrollback(sc->sc_displaydv,
+			  WSDISPLAY_SCROLL_BACKWARD);
+			return (1);
+		}
+
+	case KS_Cmd_ScrollFwd:
+		if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) {
+			wsscrollback(sc->sc_displaydv,
+			  WSDISPLAY_SCROLL_FORWARD);
+			return (1);
+		}
+	}
+#endif
 
 	switch (ksym) {
 #ifdef DDB
--- sys/dev/pckbc/wskbdmap_mfii.c.orig	Thu May 31 23:10:18 2001
+++ sys/dev/pckbc/wskbdmap_mfii.c	Thu May 31 22:36:02 2001
@@ -142,12 +142,12 @@
 #endif
     KC(199),			KS_Home,
     KC(200),			KS_Up,
-    KC(201),			KS_Prior,
+    KC(201), KS_Cmd_ScrollBack, KS_Prior,
     KC(203),			KS_Left,
     KC(205),			KS_Right,
     KC(207),			KS_End,
     KC(208),			KS_Down,
-    KC(209),			KS_Next,
+    KC(209), KS_Cmd_ScrollFwd,  KS_Next,
     KC(210),			KS_Insert,
     KC(211),			KS_Delete,
     KC(219),			KS_Meta_L,