date and time created 92/07/13 00:43:48 by torek
authorChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:43:48 +0000 (07:43 -0800)
committerChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:43:48 +0000 (07:43 -0800)
SCCS-vsn: sys/sparc/rcons/rcons_kern.c 7.1
SCCS-vsn: sys/sparc/rcons/rcons_subr.c 7.1

usr/src/sys/sparc/rcons/rcons_kern.c [new file with mode: 0644]
usr/src/sys/sparc/rcons/rcons_subr.c [new file with mode: 0644]

diff --git a/usr/src/sys/sparc/rcons/rcons_kern.c b/usr/src/sys/sparc/rcons/rcons_kern.c
new file mode 100644 (file)
index 0000000..82534d8
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)rcons_kern.c        7.1 (Berkeley) %G%
+ *
+ * from: $Header: rcons_kern.c,v 1.26 92/07/09 08:01:28 torek Exp $
+ */
+
+#include "sys/param.h"
+#include "sys/device.h"
+#include "sys/fbio.h"
+#include "sys/kernel.h"
+#include "sys/systm.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+
+#include "machine/fbvar.h"
+#include "machine/autoconf.h"
+
+#include "../dev/kbd.h"
+
+#include "raster.h"
+
+extern struct tty *fbconstty;
+
+static void rcons_belltmr(void *);
+
+extern void rcons_puts(struct fbdevice *, char *, int);
+extern void rcons_font(struct fbdevice *);
+
+extern int (*v_putc)();
+extern void ttrstrt(void *);
+
+static struct fbdevice *myfbdevicep;
+
+static void
+rcons_cnputc(c)
+       int c;
+{
+       char buf[1];
+
+       if (c == '\n')
+               rcons_puts(myfbdevicep, "\r\n", 2);
+       else {
+               buf[0] = c;
+               rcons_puts(myfbdevicep, buf, 1);
+       }
+}
+
+static void
+rcons_output(tp)
+       register struct tty *tp;
+{
+       register int s, n, i;
+       char buf[OBUFSIZ];
+
+       s = spltty();
+       if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+               splx(s);
+               return;
+       }
+       tp->t_state |= TS_BUSY;
+       splx(s);
+       n = q_to_b(&tp->t_outq, buf, sizeof(buf));
+       for (i = 0; i < n; ++i)
+               buf[i] &= 0177;         /* strip parity (argh) */
+       rcons_puts(myfbdevicep, buf, n);
+
+       s = spltty();
+       tp->t_state &= ~TS_BUSY;
+       /* Come back if there's more to do */
+       if (tp->t_outq.c_cc) {
+               tp->t_state |= TS_TIMEOUT;
+               timeout(ttrstrt, tp, 1);
+       }
+       if (tp->t_outq.c_cc <= tp->t_lowat) {
+               if (tp->t_state&TS_ASLEEP) {
+                       tp->t_state &= ~TS_ASLEEP;
+                       wakeup((caddr_t)&tp->t_outq);
+               }
+               selwakeup(&tp->t_wsel);
+       }
+       splx(s);
+}
+
+/* Ring the console bell */
+void
+rcons_bell(fb)
+       register struct fbdevice *fb;
+{
+       register int i, s;
+
+       if (fb->fb_bits & FB_VISBELL) {
+               /* invert the screen twice */
+               for (i = 0; i < 2; ++i)
+                       raster_op(fb->fb_sp, 0, 0,
+                           fb->fb_sp->width, fb->fb_sp->height,
+                           RAS_INVERT, (struct raster *) 0, 0, 0);
+       }
+
+       s = splhigh();
+       if (fb->fb_belldepth++) {
+               if (fb->fb_belldepth > 3)
+                       fb->fb_belldepth = 3;
+               splx(s);
+       } else {
+               fb->fb_ringing = 1;
+               splx(s);
+               (void) kbd_docmd(KBD_CMD_BELL, 0);
+               /* XXX Chris doesn't like the following divide */
+               timeout(rcons_belltmr, fb, hz/10);
+       }
+}
+
+/* Bell timer service routine */
+static void
+rcons_belltmr(p)
+       void *p;
+{
+       register struct fbdevice *fb = p;
+       register int s = splhigh(), i;
+
+       if (fb->fb_ringing) {
+               fb->fb_ringing = 0;
+               i = --fb->fb_belldepth;
+               splx(s);
+               (void) kbd_docmd(KBD_CMD_NOBELL, 0);
+               if (i != 0)
+                       /* XXX Chris doesn't like the following divide */
+                       timeout(rcons_belltmr, fb, hz/30);
+       } else {
+               fb->fb_ringing = 1;
+               splx(s);
+               (void) kbd_docmd(KBD_CMD_BELL, 0);
+               timeout(rcons_belltmr, fb, hz/10);
+       }
+}
+
+static int
+rcons_a2int(cp, deflt)
+       register char *cp;
+       register int deflt;
+{
+       register int i = 0;
+
+       if (*cp == '\0')
+               return (deflt);
+       while (*cp != '\0')
+               i = i * 10 + *cp++ - '0';
+       return (i);
+}
+
+void
+rcons_init(fb)
+       register struct fbdevice *fb;
+{
+       /* XXX this should go away */
+       static struct raster xxxraster;
+       register struct raster *rp = fb->fb_sp = &xxxraster;
+       register struct fbtype *ft = &fb->fb_type;
+       register struct winsize *ws;
+       register int i;
+       static int row, col;
+       char buf[100];
+
+       myfbdevicep = fb;
+
+       fb->fb_maxcol =
+           rcons_a2int(getpropstring(optionsnode, "screen-#columns"), 80);
+       fb->fb_maxrow =
+           rcons_a2int(getpropstring(optionsnode, "screen-#rows"), 34);
+
+       /* XXX mostly duplicates of data in other places */
+       rp->width = ft->fb_width;
+       rp->height = ft->fb_height;
+       rp->depth = ft->fb_depth;
+       if (fb->fb_linebytes & 0x3) {
+               printf("rcons_init: linebytes assumption botched (0x%x)\n",
+                   fb->fb_linebytes);
+               return;
+       }
+       rp->linelongs = fb->fb_linebytes >> 2;
+       rp->pixels = (u_long *)fb->fb_pixels;
+
+       fb->fb_ras_blank = RAS_CLEAR;
+
+       /* Setup the static font */
+       rcons_font(fb);
+
+       /* Impose upper bounds on fb_max{row,col} */
+       i = ft->fb_height / fb->fb_font->height;
+       if (fb->fb_maxrow > i)
+               fb->fb_maxrow = i;
+       i = ft->fb_width / fb->fb_font->width;
+       if (fb->fb_maxcol > i)
+               fb->fb_maxcol = i;
+
+       /* Let the system know how big the console is */
+       ws = &fbconstty->t_winsize;
+       ws->ws_row = fb->fb_maxrow;
+       ws->ws_col = fb->fb_maxcol;
+       ws->ws_xpixel = ft->fb_width;
+       ws->ws_ypixel = ft->fb_height;
+
+       /* Center emulator screen (but align x origin to 32 bits) */
+       fb->fb_xorigin =
+           ((ft->fb_width - fb->fb_maxcol * fb->fb_font->width) / 2) & ~0x1f;
+       fb->fb_yorigin =
+           (ft->fb_height - fb->fb_maxrow * fb->fb_font->height) / 2;
+
+       /* Emulator width and height used for scrolling */
+       fb->fb_emuwidth = fb->fb_maxcol * fb->fb_font->width;
+       if (fb->fb_emuwidth & 0x1f) {
+               /* Pad to 32 bits */
+               i = (fb->fb_emuwidth + 0x1f) & ~0x1f;
+               /* Make sure emulator width isn't too wide */
+               if (fb->fb_xorigin + i <= ft->fb_width)
+                       fb->fb_emuwidth = i;
+       }
+       fb->fb_emuheight = fb->fb_maxrow * fb->fb_font->height;
+
+       /* Determine addresses of prom emulator row and column */
+       fb->fb_row = fb->fb_col = NULL;
+       sprintf(buf, "' line# >body >user %x !", &fb->fb_row);
+       rominterpret(buf);
+       sprintf(buf, "' column# >body >user %x !", &fb->fb_col);
+       rominterpret(buf);
+       if (fb->fb_row == NULL || fb->fb_col == NULL) {
+               /* Can't find addresses; use private copies */
+               fb->fb_row = &row;
+               fb->fb_col = &col;
+               row = col = 0;
+               rcons_clear2eop(fb);    /* clear the display */
+               rcons_cursor(fb);       /* and draw the initial cursor */
+       } else {
+               /* Prom emulator cursor is currently visible */
+               fb->fb_bits |= FB_CURSOR;
+       }
+
+       /* Initialization done; hook us up */
+       v_putc = (int (*)())rcons_cnputc;
+       fbconstty->t_oproc = rcons_output;
+       fbconstty->t_stop = (void (*)()) nullop;
+}
diff --git a/usr/src/sys/sparc/rcons/rcons_subr.c b/usr/src/sys/sparc/rcons/rcons_subr.c
new file mode 100644 (file)
index 0000000..6bf410d
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)rcons_subr.c        7.1 (Berkeley) %G%
+ *
+ * from: $Header: rcons_subr.c,v 1.36 92/06/17 06:23:39 torek Exp $
+ */
+
+#ifdef KERNEL
+#include "sys/param.h"
+#include "sys/fbio.h"
+#include "sys/device.h"
+#include "machine/fbvar.h"
+#else
+#include <sys/types.h>
+#include "myfbdevice.h"
+#endif
+
+#include "raster.h"
+
+void rcons_text(struct fbdevice *, char *, int);
+void rcons_pctrl(struct fbdevice *, int);
+void rcons_esc(struct fbdevice *, int);
+void rcons_doesc(struct fbdevice *, int);
+void rcons_cursor(struct fbdevice *);
+void rcons_invert(struct fbdevice *, int);
+void rcons_clear2eop(struct fbdevice *);
+void rcons_clear2eol(struct fbdevice *);
+void rcons_scroll(struct fbdevice *, int);
+void rcons_delchar(struct fbdevice *, int);
+void rcons_delline(struct fbdevice *, int);
+void rcons_insertchar(struct fbdevice *, int);
+void rcons_insertline(struct fbdevice *, int);
+
+extern void rcons_bell(struct fbdevice *);
+
+#define RCONS_ISPRINT(c) ((c) >= ' ' && (c) <= '~')
+#define RCONS_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+
+/* Output (or at least handle) a string sent to the console */
+void
+rcons_puts(fb, str, n)
+       register struct fbdevice *fb;
+       register char *str;
+       register int n;
+{
+       register int c, i, j;
+       register char *cp;
+
+       /* Jump scroll */
+       /* XXX maybe this should be an option? */
+       if ((fb->fb_bits & FB_INESC) == 0) {
+               /* Count newlines up to an escape sequence */
+               i = 0;
+               j = 0;
+               for (cp = str; j++ < n && *cp != '\033'; ++cp) {
+                       if (*cp == '\n')
+                               ++i;
+                       else if (*cp == '\013')
+                               --i;
+               }
+
+               /* Only jump scroll two or more rows */
+               if (*fb->fb_row + i >= fb->fb_maxrow + 1) {
+                       /* Erase the cursor (if necessary) */
+                       if (fb->fb_bits & FB_CURSOR)
+                               rcons_cursor(fb);
+
+                       rcons_scroll(fb, i);
+               }
+       }
+
+       /* Process characters */
+       while (--n >= 0) {
+               c = *str;
+               if (c == '\033') {
+                       /* Start an escape (perhaps aborting one in progress) */
+                       fb->fb_bits |= FB_INESC | FB_P0_DEFAULT | FB_P1_DEFAULT;
+                       fb->fb_bits &= ~(FB_P0 | FB_P1);
+
+                       /* Most parameters default to 1 */
+                       fb->fb_p0 = fb->fb_p1 = 1;
+               } else if (fb->fb_bits & FB_INESC) {
+                       rcons_esc(fb, c);
+               } else {
+                       /* Erase the cursor (if necessary) */
+                       if (fb->fb_bits & FB_CURSOR)
+                               rcons_cursor(fb);
+
+                       /* Display the character */
+                       if (RCONS_ISPRINT(c)) {
+                               /* Try to output as much as possible */
+                               j = fb->fb_maxcol - (*fb->fb_col + 1);
+                               if (j > n)
+                                       j = n;
+                               for (i = 1; i < j && RCONS_ISPRINT(str[i]); ++i)
+                                       continue;
+                               rcons_text(fb, str, i);
+                               --i;
+                               str += i;
+                               n -= i;
+                       } else
+                               rcons_pctrl(fb, c);
+               }
+               ++str;
+       }
+       /* Redraw the cursor (if necessary) */
+       if ((fb->fb_bits & FB_CURSOR) == 0)
+               rcons_cursor(fb);
+}
+
+/* Actually write a string to the frame buffer */
+void
+rcons_text(fb, str, n)
+       register struct fbdevice *fb;
+       register char *str;
+       register int n;
+{
+       register int x, y, op;
+
+       x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
+       y = *fb->fb_row * fb->fb_font->height +
+           fb->fb_font_ascent + fb->fb_yorigin;
+       op = RAS_SRC;
+       if (((fb->fb_bits & FB_STANDOUT) != 0) ^
+           ((fb->fb_bits & FB_INVERT) != 0))
+               op = RAS_NOT(op);
+       raster_textn(fb->fb_sp, x, y, op, fb->fb_font, str, n);
+       *fb->fb_col += n;
+       if (*fb->fb_col >= fb->fb_maxcol) {
+               *fb->fb_col = 0;
+               (*fb->fb_row)++;
+       }
+       if (*fb->fb_row >= fb->fb_maxrow)
+               rcons_scroll(fb, 1);
+}
+
+/* Handle a control character sent to the console */
+void
+rcons_pctrl(fb, c)
+       register struct fbdevice *fb;
+       register int c;
+{
+
+       switch (c) {
+
+       case '\r':      /* Carriage return */
+               *fb->fb_col = 0;
+               break;
+
+       case '\b':      /* Backspace */
+               if (*fb->fb_col > 0)
+                       (*fb->fb_col)--;
+               break;
+
+       case '\013':    /* Vertical tab */
+               if (*fb->fb_row > 0)
+                       (*fb->fb_row)--;
+               break;
+
+       case '\f':      /* Formfeed */
+               *fb->fb_row = *fb->fb_col = 0;
+               rcons_clear2eop(fb);
+               break;
+
+       case '\n':      /* Linefeed */
+               (*fb->fb_row)++;
+               if (*fb->fb_row >= fb->fb_maxrow)
+                       rcons_scroll(fb, 1);
+               break;
+
+       case '\007':    /* Bell */
+               rcons_bell(fb);
+               break;
+
+       case '\t':      /* Horizontal tab */
+               *fb->fb_col = (*fb->fb_col + 8) & ~7;
+               if (*fb->fb_col >= fb->fb_maxcol)
+                       *fb->fb_col = fb->fb_maxcol - 1;
+               break;
+       }
+}
+
+/* Handle the next character in an escape sequence */
+void
+rcons_esc(fb, c)
+       register struct fbdevice *fb;
+       register int c;
+{
+
+       if (c == '[') {
+               /* Parameter 0 */
+               fb->fb_bits &= ~FB_P1;
+               fb->fb_bits |= FB_P0;
+       } else if (c == ';') {
+               /* Parameter 1 */
+               fb->fb_bits &= ~FB_P0;
+               fb->fb_bits |= FB_P1;
+       } else if (RCONS_ISDIGIT(c)) {
+               /* Add a digit to a parameter */
+               if (fb->fb_bits & FB_P0) {
+                       /* Parameter 0 */
+                       if (fb->fb_bits & FB_P0_DEFAULT) {
+                               fb->fb_bits &= ~FB_P0_DEFAULT;
+                               fb->fb_p0 = 0;
+                       }
+                       fb->fb_p0 *= 10;
+                       fb->fb_p0 += c - '0';
+               } else if (fb->fb_bits & FB_P1) {
+                       /* Parameter 1 */
+                       if (fb->fb_bits & FB_P1_DEFAULT) {
+                               fb->fb_bits &= ~FB_P1_DEFAULT;
+                               fb->fb_p1 = 0;
+                       }
+                       fb->fb_p1 *= 10;
+                       fb->fb_p1 += c - '0';
+               }
+       } else {
+               /* Erase the cursor (if necessary) */
+               if (fb->fb_bits & FB_CURSOR)
+                       rcons_cursor(fb);
+
+               /* Process the completed escape sequence */
+               rcons_doesc(fb, c);
+               fb->fb_bits &= ~FB_INESC;
+       }
+}
+
+/* Process a complete escape sequence */
+void
+rcons_doesc(fb, c)
+       register struct fbdevice *fb;
+       register int c;
+{
+
+#ifdef notdef
+       /* XXX add escape sequence to enable visual (and audible) bell */
+       fb->fb_bits = FB_VISBELL;
+#endif
+
+       switch (c) {
+
+       case '@':
+               /* Insert Character (ICH) */
+               rcons_insertchar(fb, fb->fb_p0);
+               break;
+
+       case 'A':
+               /* Cursor Up (CUU) */
+               *fb->fb_row -= fb->fb_p0;
+               if (*fb->fb_row < 0)
+                       *fb->fb_row = 0;
+               break;
+
+       case 'B':
+               /* Cursor Down (CUD) */
+               *fb->fb_row += fb->fb_p0;
+               if (*fb->fb_row >= fb->fb_maxrow)
+                       *fb->fb_row = fb->fb_maxrow - 1;
+               break;
+
+       case 'C':
+               /* Cursor Forward (CUF) */
+               *fb->fb_col += fb->fb_p0;
+               if (*fb->fb_col >= fb->fb_maxcol)
+                       *fb->fb_col = fb->fb_maxcol - 1;
+               break;
+
+       case 'D':
+               /* Cursor Backward (CUB) */
+               *fb->fb_col -= fb->fb_p0;
+               if (*fb->fb_col < 0)
+                       *fb->fb_col = 0;
+               break;
+
+       case 'E':
+               /* Cursor Next Line (CNL) */
+               *fb->fb_col = 0;
+               *fb->fb_row += fb->fb_p0;
+               if (*fb->fb_row >= fb->fb_maxrow)
+                       *fb->fb_row = fb->fb_maxrow - 1;
+               break;
+
+       case 'f':
+               /* Horizontal And Vertical Position (HVP) */
+       case 'H':
+               /* Cursor Position (CUP) */
+               *fb->fb_col = fb->fb_p1 - 1;
+               if (*fb->fb_col < 0)
+                       *fb->fb_col = 0;
+               else if (*fb->fb_col >= fb->fb_maxcol)
+                       *fb->fb_col = fb->fb_maxcol - 1;
+
+               *fb->fb_row = fb->fb_p0 - 1;
+               if (*fb->fb_row < 0)
+                       *fb->fb_row = 0;
+               else if (*fb->fb_row >= fb->fb_maxrow)
+                       *fb->fb_row = fb->fb_maxrow - 1;
+               break;
+
+       case 'J':
+               /* Erase in Display (ED) */
+               rcons_clear2eop(fb);
+               break;
+
+       case 'K':
+               /* Erase in Line (EL) */
+               rcons_clear2eol(fb);
+               break;
+
+       case 'L':
+               /* Insert Line (IL) */
+               rcons_insertline(fb, fb->fb_p0);
+               break;
+
+       case 'M':
+               /* Delete Line (DL) */
+               rcons_delline(fb, fb->fb_p0);
+               break;
+
+       case 'P':
+               /* Delete Character (DCH) */
+               rcons_delchar(fb, fb->fb_p0);
+               break;
+
+       case 'm':
+               /* Select Graphic Rendition (SGR); */
+               /* (defaults to zero) */
+               if (fb->fb_bits & FB_P0_DEFAULT)
+                       fb->fb_p0 = 0;
+               if (fb->fb_p0)
+                       fb->fb_bits |= FB_STANDOUT;
+               else
+                       fb->fb_bits &= ~FB_STANDOUT;
+               break;
+
+       case 'p':
+               /* Black On White (SUNBOW) */
+               rcons_invert(fb, 0);
+               break;
+
+       case 'q':
+               /* White On Black (SUNWOB) */
+               rcons_invert(fb, 1);
+               break;
+
+       case 'r':
+               /* Set scrolling (SUNSCRL) */
+               /* (defaults to zero) */
+               if (fb->fb_bits & FB_P0_DEFAULT)
+                       fb->fb_p0 = 0;
+               /* XXX not implemented yet */
+               fb->fb_scroll = fb->fb_p0;
+               break;
+
+       case 's':
+               /* Reset terminal emulator (SUNRESET) */
+               fb->fb_bits &= ~FB_STANDOUT;
+               fb->fb_scroll = 0;
+               if (fb->fb_bits & FB_INVERT)
+                       rcons_invert(fb, 0);
+               break;
+       }
+}
+
+/* Paint (or unpaint) the cursor */
+void
+rcons_cursor(fb)
+       register struct fbdevice *fb;
+{
+       register int x, y;
+
+       x = *fb->fb_col * fb->fb_font->width + fb->fb_xorigin;
+       y = *fb->fb_row * fb->fb_font->height + fb->fb_yorigin;
+       raster_op(fb->fb_sp, x, y,
+#ifdef notdef
+           /* XXX This is the right way but too slow */
+           fb->fb_font->chars[(int)' '].r->width,
+           fb->fb_font->chars[(int)' '].r->height,
+#else
+           fb->fb_font->width, fb->fb_font->height,
+#endif
+           RAS_INVERT, (struct raster *) 0, 0, 0);
+       fb->fb_bits ^= FB_CURSOR;
+}
+
+/* Possibly change to SUNWOB or SUNBOW mode */
+void
+rcons_invert(fb, wob)
+       struct fbdevice *fb;
+       int wob;
+{
+       if (((fb->fb_bits & FB_INVERT) != 0) ^ wob) {
+               /* Invert the display */
+               raster_op(fb->fb_sp, 0, 0, fb->fb_sp->width, fb->fb_sp->height,
+                   RAS_INVERT, (struct raster *) 0, 0, 0);
+
+               /* Swap things around */
+               fb->fb_ras_blank = RAS_NOT(fb->fb_ras_blank);
+               fb->fb_bits ^= FB_INVERT;
+       }
+}
+
+/* Clear to the end of the page */
+void
+rcons_clear2eop(fb)
+       register struct fbdevice *fb;
+{
+       register int y;
+
+       if (*fb->fb_col == 0 && *fb->fb_row == 0) {
+               /* Clear the entire frame buffer */
+               raster_op(fb->fb_sp, 0, 0,
+                   fb->fb_sp->width, fb->fb_sp->height,
+                   fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+       } else {
+               /* Only clear what needs to be cleared */
+               rcons_clear2eol(fb);
+               y = (*fb->fb_row + 1) * fb->fb_font->height;
+
+               raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin + y,
+                   fb->fb_emuwidth, fb->fb_emuheight - y,
+                   fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+       }
+}
+
+/* Clear to the end of the line */
+void
+rcons_clear2eol(fb)
+       register struct fbdevice *fb;
+{
+       register int x;
+
+       x = *fb->fb_col * fb->fb_font->width;
+
+       raster_op(fb->fb_sp,
+           fb->fb_xorigin + x,
+           *fb->fb_row * fb->fb_font->height + fb->fb_yorigin,
+           fb->fb_emuwidth - x, fb->fb_font->height,
+           fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}
+
+/* Scroll up one line */
+void
+rcons_scroll(fb, n)
+       register struct fbdevice *fb;
+       register int n;
+{
+       register int ydiv;
+
+       /* Can't scroll more than the whole screen */
+       if (n > fb->fb_maxrow)
+               n = fb->fb_maxrow;
+
+       /* Calculate new row */
+       *fb->fb_row -= n;
+       if (*fb->fb_row < 0)
+               *fb->fb_row  = 0;
+
+       /* Calculate number of pixels to scroll */
+       ydiv = fb->fb_font->height * n;
+
+       raster_op(fb->fb_sp, fb->fb_xorigin, fb->fb_yorigin,
+           fb->fb_emuwidth, fb->fb_emuheight - ydiv,
+           RAS_SRC, fb->fb_sp, fb->fb_xorigin, ydiv + fb->fb_yorigin);
+
+       raster_op(fb->fb_sp,
+           fb->fb_xorigin, fb->fb_yorigin + fb->fb_emuheight - ydiv,
+           fb->fb_emuwidth, ydiv, fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}
+
+/* Delete characters */
+void
+rcons_delchar(fb, n)
+       register struct fbdevice *fb;
+       register int n;
+{
+       register int tox, fromx, y, width;
+
+       /* Can't delete more chars than there are */
+       if (n > fb->fb_maxcol - *fb->fb_col)
+               n = fb->fb_maxcol - *fb->fb_col;
+
+       fromx = (*fb->fb_col + n) * fb->fb_font->width;
+       tox = *fb->fb_col * fb->fb_font->width;
+       y = *fb->fb_row * fb->fb_font->height;
+       width = n * fb->fb_font->width;
+
+       raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
+           fb->fb_emuwidth - fromx, fb->fb_font->height,
+           RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
+
+       raster_op(fb->fb_sp,
+           fb->fb_emuwidth - width + fb->fb_xorigin, y + fb->fb_yorigin,
+           width, fb->fb_font->height,
+           fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}
+
+/* Delete a number of lines */
+void
+rcons_delline(fb, n)
+       register struct fbdevice *fb;
+       register int n;
+{
+       register int fromy, toy, height;
+
+       /* Can't delete more lines than there are */
+       if (n > fb->fb_maxrow - *fb->fb_row)
+               n = fb->fb_maxrow - *fb->fb_row;
+
+       fromy = (*fb->fb_row + n) * fb->fb_font->height;
+       toy = *fb->fb_row * fb->fb_font->height;
+       height = fb->fb_font->height * n;
+
+       raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
+           fb->fb_emuwidth, fb->fb_emuheight - fromy, RAS_SRC,
+           fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
+
+       raster_op(fb->fb_sp,
+           fb->fb_xorigin, fb->fb_emuheight - height + fb->fb_yorigin,
+           fb->fb_emuwidth, height,
+           fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}
+
+/* Insert some characters */
+void
+rcons_insertchar(fb, n)
+       register struct fbdevice *fb;
+       register int n;
+{
+       register int tox, fromx, y;
+
+       /* Can't insert more chars than can fit */
+       if (n > fb->fb_maxcol - *fb->fb_col)
+               n = fb->fb_maxcol - *fb->fb_col;
+
+       tox = (*fb->fb_col + n) * fb->fb_font->width;
+       fromx = *fb->fb_col * fb->fb_font->width;
+       y = *fb->fb_row * fb->fb_font->height;
+
+       raster_op(fb->fb_sp, tox + fb->fb_xorigin, y + fb->fb_yorigin,
+           fb->fb_emuwidth - tox, fb->fb_font->height,
+           RAS_SRC, fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin);
+
+       raster_op(fb->fb_sp, fromx + fb->fb_xorigin, y + fb->fb_yorigin,
+           fb->fb_font->width * n, fb->fb_font->height,
+           fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}
+
+/* Insert some lines */
+void
+rcons_insertline(fb, n)
+       register struct fbdevice *fb;
+       register int n;
+{
+       register int fromy, toy;
+
+       /* Can't insert more lines than can fit */
+       if (n > fb->fb_maxrow - *fb->fb_row)
+               n = fb->fb_maxrow - *fb->fb_row;
+
+       toy = (*fb->fb_row + n) * fb->fb_font->height;
+       fromy = *fb->fb_row * fb->fb_font->height;
+
+       raster_op(fb->fb_sp, fb->fb_xorigin, toy + fb->fb_yorigin,
+           fb->fb_emuwidth, fb->fb_emuheight - toy,
+           RAS_SRC, fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin);
+
+       raster_op(fb->fb_sp, fb->fb_xorigin, fromy + fb->fb_yorigin,
+           fb->fb_emuwidth, fb->fb_font->height * n,
+           fb->fb_ras_blank, (struct raster *) 0, 0, 0);
+}