Module Name:    src
Committed By:   martin
Date:           Sun Feb 12 12:27:26 UTC 2023

Modified Files:
        src/sys/arch/vax/conf [netbsd-10]: GENERIC INSTALL VAX780 files.vax
        src/sys/arch/vax/include [netbsd-10]: qdreg.h
        src/sys/arch/vax/vax [netbsd-10]: conf.c
        src/sys/arch/vax/vsa [netbsd-10]: smg.c
Added Files:
        src/sys/arch/vax/vsa [netbsd-10]: gpx.c

Log Message:
Pull up following revision(s) (requested by tsutsui in ticket #79):

        sys/arch/vax/conf/GENERIC: revision 1.217
        sys/arch/vax/conf/VAX780: revision 1.34
        sys/arch/vax/conf/files.vax: revision 1.126
        sys/arch/vax/vsa/smg.c: revision 1.63
        sys/arch/vax/include/qdreg.h: revision 1.7
        sys/arch/vax/vax/conf.c: revision 1.69
        sys/arch/vax/conf/INSTALL: revision 1.76
        sys/arch/vax/vsa/gpx.c: revision 1.1

Add a support for gpx(4) color framebuffer found on VAXstation 3100.

Ported from OpenBSD/vax. Note smg(4) monochrome onboard framebuffer
driver is also changed attached only if gpx(4) is not installed
or flags 1 is specified in config files, as OpenBSD did.

Tested on my VAXstation 3100/m30 with and without 8bpp gpx(4).

Revied on port-vax@ and "Please go ahead!" from ragge@.
https://mail-index.netbsd.org/port-vax/2023/01/thread1.html#004147


To generate a diff of this commit:
cvs rdiff -u -r1.216 -r1.216.4.1 src/sys/arch/vax/conf/GENERIC
cvs rdiff -u -r1.75 -r1.75.24.1 src/sys/arch/vax/conf/INSTALL
cvs rdiff -u -r1.33 -r1.33.4.1 src/sys/arch/vax/conf/VAX780
cvs rdiff -u -r1.125 -r1.125.30.1 src/sys/arch/vax/conf/files.vax
cvs rdiff -u -r1.6 -r1.6.4.1 src/sys/arch/vax/include/qdreg.h
cvs rdiff -u -r1.68 -r1.68.48.1 src/sys/arch/vax/vax/conf.c
cvs rdiff -u -r0 -r1.1.2.2 src/sys/arch/vax/vsa/gpx.c
cvs rdiff -u -r1.61.6.1 -r1.61.6.2 src/sys/arch/vax/vsa/smg.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/vax/conf/GENERIC
diff -u src/sys/arch/vax/conf/GENERIC:1.216 src/sys/arch/vax/conf/GENERIC:1.216.4.1
--- src/sys/arch/vax/conf/GENERIC:1.216	Thu Sep 29 10:10:10 2022
+++ src/sys/arch/vax/conf/GENERIC	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.216 2022/09/29 10:10:10 riastradh Exp $
+# $NetBSD: GENERIC,v 1.216.4.1 2023/02/12 12:27:26 martin Exp $
 #
 # GENERIC machine description file
 # 
@@ -22,7 +22,7 @@ include 	"arch/vax/conf/std.vax"
 
 options 	INCLUDE_CONFIG_FILE	# embed config file in kernel binary
 
-#ident 		"GENERIC-$Revision: 1.216 $"
+#ident 		"GENERIC-$Revision: 1.216.4.1 $"
 
 # Here are all different supported CPU types listed.
 #options 	VAX8800		# VAX 8500, 8530, 8550, 8700, 8800
@@ -185,6 +185,7 @@ si1		at vsbus0 csr 0x200c0180 # VS2000/3
 asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
 asc0		at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr
 smg0		at vsbus0 csr 0x200f0000 # Small monochrome display ctlr.
+gpx0		at vsbus0 csr 0x3c000000 # VS3100 GPX display option
 #clr0		at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics
 spx0		at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90.
 lcg0		at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics
@@ -271,6 +272,7 @@ uk*		at scsibus? target? lun?
 
 # VAXstation graphics support
 wsdisplay*	at smg0
+wsdisplay*	at gpx0
 wsdisplay*	at spx0
 wsdisplay*	at lcg0
 #wsdisplay*	at clr0

Index: src/sys/arch/vax/conf/INSTALL
diff -u src/sys/arch/vax/conf/INSTALL:1.75 src/sys/arch/vax/conf/INSTALL:1.75.24.1
--- src/sys/arch/vax/conf/INSTALL:1.75	Mon Jan 20 18:38:21 2020
+++ src/sys/arch/vax/conf/INSTALL	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-#	$NetBSD: INSTALL,v 1.75 2020/01/20 18:38:21 thorpej Exp $
+#	$NetBSD: INSTALL,v 1.75.24.1 2023/02/12 12:27:26 martin Exp $
 #
 # INSTALL kernel; all supported devices but nothing fancy.
 #
@@ -139,6 +139,7 @@ si1		at vsbus0 csr 0x200c0180 # VS2000/3
 asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
 asc0		at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr
 smg0		at vsbus0 csr 0x200f0000 # Small monochrome display ctlr.
+gpx0		at vsbus0 csr 0x3c000000 # VS3100 GPX display option
 #clr0		at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics
 spx0		at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90.
 #lcg0		at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics
@@ -217,6 +218,7 @@ cd*		at scsibus? target? lun?
 
 # VAXstation graphics support
 wsdisplay*	at smg0
+wsdisplay*	at gpx0
 wsdisplay*	at spx0
 #wsdisplay*	at lcg0
 #wsdisplay*	at clr0

Index: src/sys/arch/vax/conf/VAX780
diff -u src/sys/arch/vax/conf/VAX780:1.33 src/sys/arch/vax/conf/VAX780:1.33.4.1
--- src/sys/arch/vax/conf/VAX780:1.33	Sun Aug  7 02:52:30 2022
+++ src/sys/arch/vax/conf/VAX780	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-# $NetBSD: VAX780,v 1.33 2022/08/07 02:52:30 simonb Exp $
+# $NetBSD: VAX780,v 1.33.4.1 2023/02/12 12:27:26 martin Exp $
 #
 # 11/780,750,730 machine description file
 # 
@@ -171,6 +171,7 @@ ubi0		at mainbus0		# 11/730 direct unibu
 #asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
 #asc0		at vsbus0 csr 0x26000080 # VS4000/90 and 4000/10x SCSI-ctlr
 #smg0		at vsbus0 csr 0x200f0000 # Small monochrome display ctlr.
+#gpx0		at vsbus0 csr 0x3c000000 # VS3100 GPX display option
 #clr0		at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics
 #spx0		at vsbus0 csr 0x38000000 # Low Cost SPX on VS4000/90.
 #lcg0		at vsbus0 csr 0x21801000 # VS4000/60 (or VLC) graphics
@@ -251,6 +252,7 @@ mt*		at mscpbus? drive?	# MSCP tape
 
 # VAXstation graphics support
 #wsdisplay*	at smg0
+#wsdisplay*	at gpx0
 #wsdisplay*	at spx0
 #wsdisplay*	at lcg0
 #wsdisplay*	at clr0

Index: src/sys/arch/vax/conf/files.vax
diff -u src/sys/arch/vax/conf/files.vax:1.125 src/sys/arch/vax/conf/files.vax:1.125.30.1
--- src/sys/arch/vax/conf/files.vax:1.125	Sat Dec 29 11:30:12 2018
+++ src/sys/arch/vax/conf/files.vax	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-#	$NetBSD: files.vax,v 1.125 2018/12/29 11:30:12 maxv Exp $
+#	$NetBSD: files.vax,v 1.125.30.1 2023/02/12 12:27:26 martin Exp $
 #
 # new style config file for vax architecture
 #
@@ -149,7 +149,7 @@ attach	cpu at xmi with cpu_xmi
 attach	mem at xmi with mem_xmi
 
 attach	dz at vsbus with dz_vsbus
-file	arch/vax/vsa/dz_vsbus.c		dz_vsbus | smg
+file	arch/vax/vsa/dz_vsbus.c		dz_vsbus | smg | gpx
 
 attach	lkkbd at dz with dzkbd
 file	dev/dec/dzkbd.c			dzkbd needs-flag
@@ -190,6 +190,11 @@ device	smg: displaydev, wsemuldisplaydev
 attach	smg at vsbus
 file	arch/vax/vsa/smg.c		smg needs-flag
 
+# GPX framebuffer on VS3100.
+device	gpx: displaydev, wsemuldisplaydev, rasops8
+attach	gpx at vsbus
+file	arch/vax/vsa/gpx.c		gpx needs-flag
+
 # Monochrome QVSS framebuffer on qbus (VCB01)
 device	qv {}: displaydev, wsemuldisplaydev
 attach	qv at uba

Index: src/sys/arch/vax/include/qdreg.h
diff -u src/sys/arch/vax/include/qdreg.h:1.6 src/sys/arch/vax/include/qdreg.h:1.6.4.1
--- src/sys/arch/vax/include/qdreg.h:1.6	Tue Aug 17 22:00:31 2021
+++ src/sys/arch/vax/include/qdreg.h	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: qdreg.h,v 1.6 2021/08/17 22:00:31 andvar Exp $	*/
+/*	$NetBSD: qdreg.h,v 1.6.4.1 2023/02/12 12:27:26 martin Exp $	*/
 /*-
  * Copyright (c) 1982, 1986 The Regents of the University of California.
  * All rights reserved.
@@ -172,10 +172,12 @@
 /* VIPER logical function unit codes */
 
 #define LF_ZEROS		0x0000
+#define LF_NOT_D		0x0003
 #define LF_D_XOR_S		0x0006
-#define LF_SOURCE		0x000A
-#define LF_D_OR_S		0x000E
-#define LF_ONES 		0x000F
+#define LF_SOURCE		0x000a
+#define LF_D			0x000c
+#define LF_D_OR_S		0x000d
+#define LF_ONES 		0x000f
 #define INV_M1_M2		0x0030
 #define FULL_SRC_RESOLUTION	0X00C0 /* makes second pass like first pass */
 

Index: src/sys/arch/vax/vax/conf.c
diff -u src/sys/arch/vax/vax/conf.c:1.68 src/sys/arch/vax/vax/conf.c:1.68.48.1
--- src/sys/arch/vax/vax/conf.c:1.68	Sun Jul  5 02:10:53 2015
+++ src/sys/arch/vax/vax/conf.c	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: conf.c,v 1.68 2015/07/05 02:10:53 matt Exp $	*/
+/*	$NetBSD: conf.c,v 1.68.48.1 2023/02/12 12:27:26 martin Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986 The Regents of the University of California.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.68 2015/07/05 02:10:53 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.68.48.1 2023/02/12 12:27:26 martin Exp $");
 
 #include "opt_cputype.h"
 
@@ -45,12 +45,28 @@ __KERNEL_RCSID(0, "$NetBSD: conf.c,v 1.6
  */
 #include <dev/cons.h>
 
+#include "gpx.h"
 #include "lcg.h"
 #include "qv.h"
 #include "smg.h"
 #include "spx.h"
 #include "wskbd.h"
 
+#if NGPX > 0
+#if NWSKBD > 0
+#define gpxcngetc wskbd_cngetc
+#else
+static int
+gpxcngetc(dev_t dev)
+{
+	return 0;
+}
+#endif
+
+#define gpxcnputc wsdisplay_cnputc
+#define gpxcnpollc nullcnpollc
+#endif /* NGPX > 0 */
+
 #if NLCG > 0
 #if NWSKBD > 0
 #define lcgcngetc wskbd_cngetc
@@ -110,6 +126,7 @@ spxcngetc(dev_t dev)
 
 cons_decl(gen);
 cons_decl(dz);
+cons_decl(gpx);
 cons_decl(qd);
 cons_decl(lcg);
 cons_decl(qv);
@@ -133,6 +150,9 @@ struct	consdev constab[]={
 	cons_init(qd),
 #endif
 #endif
+#if NGPX
+	cons_init(gpx),
+#endif
 #if NLCG
 	cons_init(lcg),
 #endif

Index: src/sys/arch/vax/vsa/smg.c
diff -u src/sys/arch/vax/vsa/smg.c:1.61.6.1 src/sys/arch/vax/vsa/smg.c:1.61.6.2
--- src/sys/arch/vax/vsa/smg.c:1.61.6.1	Mon Feb  6 16:48:44 2023
+++ src/sys/arch/vax/vsa/smg.c	Sun Feb 12 12:27:26 2023
@@ -1,4 +1,4 @@
-/*	$NetBSD: smg.c,v 1.61.6.1 2023/02/06 16:48:44 martin Exp $ */
+/*	$NetBSD: smg.c,v 1.61.6.2 2023/02/12 12:27:26 martin Exp $ */
 /*
  * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
  * All rights reserved.
@@ -25,7 +25,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61.6.1 2023/02/06 16:48:44 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61.6.2 2023/02/12 12:27:26 martin Exp $");
+
+#include "opt_wsfont.h"
+#include "dzkbd.h"
+#include "wsdisplay.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61
 #include <machine/vsbus.h>
 #include <machine/sid.h>
 #include <machine/ka420.h>
+#include <machine/scb.h>
 
 #include <dev/cons.h>
 
@@ -52,9 +57,6 @@ __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61
 #include <dev/wscons/wscons_callbacks.h>
 #include <dev/wsfont/wsfont.h>
 
-#include "dzkbd.h"
-#include "opt_wsfont.h"
-
 /* Screen hardware defs */
 #define SM_COLS		128	/* char width of screen */
 #define SM_ROWS		57	/* rows of char on screen */
@@ -187,34 +189,67 @@ static	struct smg_screen *curscr;
 static	callout_t smg_cursor_ch;
 
 int
-smg_match(device_t parent, cfdata_t match, void *aux)
+smg_match(device_t parent, cfdata_t cf, void *aux)
 {
 	struct vsbus_attach_args * const va = aux;
 	volatile uint16_t *ccmd;
 	volatile uint16_t *cfgtst;
 	uint16_t tmp, tmp2;
 
-	if (vax_boardtype == VAX_BTYP_49 || vax_boardtype == VAX_BTYP_53)
+	switch (vax_boardtype) {
+	default:
 		return 0;
 
-	ccmd = (uint16_t *)va->va_addr;
-	cfgtst = (uint16_t *)vax_map_physmem(VS_CFGTST, 1);
-	/*
-	 * Try to find the cursor chip by testing the flip-flop.
-	 * If nonexistent, no glass tty.
-	 */
-	ccmd[0] = CUR_CMD_HSHI|CUR_CMD_FOPB;
-	DELAY(300000);
-	tmp = cfgtst[0];
-	ccmd[0] = CUR_CMD_TEST|CUR_CMD_HSHI;
-	DELAY(300000);
-	tmp2 = cfgtst[0];
-	vax_unmap_physmem((vaddr_t)cfgtst, 1);
-
-	if (tmp2 != tmp)
-		return 20; /* Using periodic interrupt */
-	else
-		return 0;
+	case VAX_BTYP_410:
+	case VAX_BTYP_420:
+	case VAX_BTYP_43:
+		if (va->va_paddr != KA420_CUR_BASE)
+			return 0;
+
+		/* not present on microvaxes */
+		if ((vax_confdata & KA420_CFG_MULTU) != 0)
+			return 0;
+		/*
+		 * If the color option board is present, do not attach
+		 * unless we are explicitely asked to via device flags.
+		 */
+		if ((vax_confdata & KA420_CFG_VIDOPT) != 0 &&
+		    (cf->cf_flags & 1) == 0)
+			return 0;
+		break;
+	}
+
+	/* when already running as console, always fake things */
+	if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0
+#if NWSDISPLAY > 0
+	    && cn_tab->cn_putc == wsdisplay_cnputc
+#endif
+	) {
+		struct vsbus_softc *sc = device_private(parent);
+
+		sc->sc_mask = 0x08;
+		scb_fake(0x44, 0x15);
+		return 20;
+	} else {
+		/*
+		 * Try to find the cursor chip by testing the flip-flop.
+		 * If nonexistent, no glass tty.
+		 */
+		ccmd = (uint16_t *)va->va_addr;
+		cfgtst = (uint16_t *)vax_map_physmem(VS_CFGTST, 1);
+		ccmd[0] = CUR_CMD_HSHI|CUR_CMD_FOPB;
+		DELAY(300000);
+		tmp = cfgtst[0];
+		ccmd[0] = CUR_CMD_TEST|CUR_CMD_HSHI;
+		DELAY(300000);
+		tmp2 = cfgtst[0];
+		vax_unmap_physmem((vaddr_t)cfgtst, 1);
+
+		if (tmp2 != tmp)
+			return 20; /* Using periodic interrupt */
+		else
+			return 0;
+	}
 }
 
 void
@@ -234,7 +269,13 @@ smg_attach(device_t parent, device_t sel
 	if (curscr == NULL)
 		callout_init(&smg_cursor_ch, 0);
 	curscr = &smg_conscreen;
-	aa.console = (vax_confdata & (KA420_CFG_L3CON|KA420_CFG_MULTU)) == 0;
+	aa.console =
+#if NWSDISPLAY > 0
+	    (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0 &&
+	    cn_tab->cn_putc == wsdisplay_cnputc;
+#else
+	    (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0;
+#endif
 
 	aa.scrdata = &smg_screenlist;
 	aa.accessops = &smg_accessops;
@@ -581,9 +622,15 @@ smgcninit(struct consdev *cndev)
 {
 	int fcookie;
 	struct wsdisplay_font *console_font;
-	extern void lkccninit(struct consdev *);
-	extern int lkccngetc(dev_t);
+	extern vaddr_t virtual_avail;
 	extern int dz_vsbus_lk201_cnattach(int);
+
+	sm_addr = (void *)virtual_avail;
+	ioaccess((vaddr_t)sm_addr, SMADDR, (SMSIZE / VAX_NBPG));
+	virtual_avail += SMSIZE;
+
+	virtual_avail = round_page(virtual_avail);
+
 	/* Clear screen */
 	memset(sm_addr, 0, 128*864);
 
@@ -618,7 +665,6 @@ smgcninit(struct consdev *cndev)
 void
 smgcnprobe(struct consdev *cndev)
 {
-	extern vaddr_t virtual_avail;
 	extern const struct cdevsw wsdisplay_cdevsw;
 
 	switch (vax_boardtype) {
@@ -628,12 +674,9 @@ smgcnprobe(struct consdev *cndev)
 		if ((vax_confdata & KA420_CFG_L3CON) ||
 		    (vax_confdata & KA420_CFG_MULTU))
 			break; /* doesn't use graphics console */
-		sm_addr = (void *)virtual_avail;
-		virtual_avail += SMSIZE;
-		ioaccess((vaddr_t)sm_addr, SMADDR, (SMSIZE/VAX_NBPG));
 		cndev->cn_pri = CN_INTERNAL;
-		cndev->cn_dev = makedev(cdevsw_lookup_major(&wsdisplay_cdevsw),
-					0);
+		cndev->cn_dev =
+		    makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
 		break;
 
 	default:

Added files:

Index: src/sys/arch/vax/vsa/gpx.c
diff -u /dev/null src/sys/arch/vax/vsa/gpx.c:1.1.2.2
--- /dev/null	Sun Feb 12 12:27:26 2023
+++ src/sys/arch/vax/vsa/gpx.c	Sun Feb 12 12:27:26 2023
@@ -0,0 +1,1361 @@
+/*	$NetBSD: gpx.c,v 1.1.2.2 2023/02/12 12:27:26 martin Exp $ */
+/*	$OpenBSD: gpx.c,v 1.25 2014/12/23 21:39:12 miod Exp $	*/
+/*
+ * Copyright (c) 2006 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice, this permission notice, and the disclaimer below
+ * appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*-
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)qd.c	7.1 (Berkeley) 6/28/91
+ */
+
+/************************************************************************
+*									*
+*			Copyright (c) 1985-1988 by			*
+*		Digital Equipment Corporation, Maynard, MA		*
+*			All rights reserved.				*
+*									*
+*   This software is furnished under a license and may be used and	*
+*   copied  only  in accordance with the terms of such license and	*
+*   with the  inclusion  of  the  above  copyright  notice.   This	*
+*   software  or  any  other copies thereof may not be provided or	*
+*   otherwise made available to any other person.  No title to and	*
+*   ownership of the software is hereby transferred.			*
+*									*
+*   The information in this software is subject to change  without	*
+*   notice  and should not be construed as a commitment by Digital	*
+*   Equipment Corporation.						*
+*									*
+*   Digital assumes no responsibility for the use  or  reliability	*
+*   of its software on equipment which is not supplied by Digital.	*
+*									*
+*************************************************************************/
+
+/*
+ * Driver for the GPX color option on VAXstation 3100, based on the
+ * MicroVAX II qdss driver.
+ *
+ * The frame buffer memory itself is not directly accessible (unlike
+ * the on-board monochrome smg frame buffer), and writes through the
+ * Dragon chip can only happen in multiples of 16 pixels, horizontally.
+ *
+ * Because of this limitation, the font image is copied to offscreen
+ * memory (which there is plenty of), and screen to screen blt operations
+ * are done for everything.
+ */
+
+#include "dzkbd.h"
+#include "wsdisplay.h"
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+
+#include <machine/sid.h>
+#include <machine/cpu.h>
+#include <machine/ka420.h>
+#include <machine/scb.h>
+#include <machine/vsbus.h>
+#include <machine/qdreg.h>
+
+#include <dev/cons.h>
+
+#include <dev/dec/dzreg.h>
+#include <dev/dec/dzvar.h>
+#include <dev/dec/dzkbdvar.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wscons_callbacks.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+#include <dev/wsfont/wsfont.h>
+
+#if 0
+#include <dev/ic/bt458reg.h>
+#include <dev/ic/dc503reg.h>
+#endif
+
+#define	GPXADDR		0x3c000000	/* base address on VAXstation 3100 */
+
+#define	GPX_ADDER_OFFSET	0x0000
+#define	GPX_VDAC_OFFSET		0x0300
+#define	GPX_CURSOR_OFFSET	0x0400	/* DC503 */
+#define	GPX_READBACK_OFFSET	0x0500
+
+#define	GPX_WIDTH	1024
+#define	GPX_VISHEIGHT	864
+#define	GPX_HEIGHT	2048
+
+/* XXX these should be in <dev/ic/bt458reg.h> */
+/*
+ * Brooktree Bt451, Bt457, Bt458 register definitions
+ */
+#define BT_OV0	0x00		/* overlay 0 */
+#define BT_OV1	0x01		/* overlay 1 */
+#define BT_OV2	0x02		/* overlay 2 */
+#define BT_OV3	0x03		/* overlay 3 */
+#define BT_RMR	0x04		/* read mask */
+#define BT_BMR	0x05		/* blink mask */
+#define BT_CR	0x06		/* control */
+#define BT_CTR	0x07		/* control/test */
+
+#define BTCR_MPLX_5		0x80	/* multiplex select, 5:1 */
+#define BTCR_MPLX_4		0x00	/* multiplex select, 4:1 */
+#define BTCR_RAMENA		0x40	/* use color palette RAM */
+#define BTCR_BLINK_M		0x30	/* blink mask */
+#define BTCR_BLINK_1648		0x00	/*  16 on, 48 off */
+#define BTCR_BLINK_1616		0x10	/*  16 on, 16 off */
+#define BTCR_BLINK_3232		0x20	/*  32 on, 32 off */
+#define BTCR_BLINK_6464		0x30	/*  64 on, 64 off */
+#define BTCR_BLINKENA_OV1	0x08	/* OV1 blink enable */
+#define BTCR_BLINKENA_OV0	0x04	/* OV0 blink enable */
+#define BTCR_DISPENA_OV1	0x02	/* OV1 display enable */
+#define BTCR_DISPENA_OV0	0x01	/* OV0 display enable */
+
+#define BTCTR_R_ENA		0x01	/* red channel enable */
+#define BTCTR_G_ENA		0x02	/* green channel enable */
+#define BTCTR_B_ENA		0x04	/* blue channel enable */
+#define BTCTR_NIB_M		0x08	/* nibble mask: */
+#define BTCTR_NIB_LOW		0x08	/*  low */
+#define BTCTR_NIB_HIGH		0x00	/*  high */
+
+/* 4 plane option RAMDAC */
+struct	ramdac4 {
+	uint16_t	colormap[16];
+	uint8_t		unknown[0x20];
+	uint16_t	cursormap[4];
+	uint8_t		unknown2[0x18];
+	uint16_t	control;
+#define	RAMDAC4_INIT	0x0047
+#define	RAMDAC4_ENABLE	0x0002
+};
+
+/* 8 plane option RAMDAC - Bt458 or compatible */
+struct	ramdac8 {
+	uint16_t	address;
+	uint16_t	cmapdata;
+	uint16_t	control;
+	uint16_t	omapdata;
+};
+
+static int gpx_match(device_t, cfdata_t, void *);
+static void gpx_attach(device_t, device_t, void *);
+
+struct	gpx_screen {
+	struct rasops_info ss_ri;
+	int		ss_console;
+	u_int		ss_depth;
+	u_int		ss_gpr;		/* font glyphs per row */
+	struct adder	*ss_adder;
+	void		*ss_vdac;
+	uint8_t		ss_cmap[256 * 3];
+#if 0
+	struct dc503reg	*ss_cursor;
+	uint16_t	ss_curcmd;
+#endif
+};
+
+/* for console */
+struct gpx_screen gpx_consscr;
+
+struct	gpx_softc {
+	device_t sc_dev;
+	struct gpx_screen *sc_scr;
+	int	sc_nscreens;
+};
+
+CFATTACH_DECL_NEW(gpx, sizeof(struct gpx_softc),
+    gpx_match, gpx_attach, NULL, NULL);
+
+struct wsscreen_descr gpx_stdscreen = {
+	"std",
+};
+
+const struct wsscreen_descr *_gpx_scrlist[] = {
+	&gpx_stdscreen,
+};
+
+const struct wsscreen_list gpx_screenlist = {
+	sizeof(_gpx_scrlist) / sizeof(struct wsscreen_descr *),
+	_gpx_scrlist,
+};
+
+static int gpx_ioctl(void *, void *, u_long, void *, int, struct lwp *);
+static paddr_t gpx_mmap(void *, void *, off_t, int);
+static int gpx_alloc_screen(void *, const struct wsscreen_descr *,
+    void **, int *, int *, long *);
+static void gpx_free_screen(void *, void *);
+static int gpx_show_screen(void *, void *, int,
+    void (*) (void *, int, int), void *);
+
+const struct wsdisplay_accessops gpx_accessops = {
+	.ioctl = gpx_ioctl,
+	.mmap = gpx_mmap,
+	.alloc_screen = gpx_alloc_screen,
+	.free_screen = gpx_free_screen,
+	.show_screen = gpx_show_screen,
+	.load_font = NULL
+};
+
+static void gpx_clear_screen(struct gpx_screen *);
+static void gpx_copyrect(struct gpx_screen *, int, int, int, int, int, int);
+static void gpx_fillrect(struct gpx_screen *, int, int, int, int, long, u_int);
+static int gpx_getcmap(struct gpx_screen *, struct wsdisplay_cmap *);
+static void gpx_loadcmap(struct gpx_screen *, int, int);
+static int gpx_putcmap(struct gpx_screen *, struct wsdisplay_cmap *);
+static void gpx_resetcmap(struct gpx_screen *);
+static void gpx_reset_viper(struct gpx_screen *);
+static int gpx_setup_screen(struct gpx_screen *);
+static void gpx_upload_font(struct gpx_screen *);
+static int gpx_viper_write(struct gpx_screen *, u_int, uint16_t);
+static int gpx_wait(struct gpx_screen *, int);
+
+static void gpx_copycols(void *, int, int, int, int);
+static void gpx_copyrows(void *, int, int, int);
+static void gpx_do_cursor(struct rasops_info *);
+static void gpx_erasecols(void *, int, int, int, long);
+static void gpx_eraserows(void *, int, int, long);
+static void gpx_putchar(void *, int, int, u_int, long);
+
+/*
+ * Autoconf glue
+ */
+
+int
+gpx_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct vsbus_attach_args *va = aux;
+	volatile struct adder *adder;
+	vaddr_t tmp;
+	u_int depth;
+	u_short status;
+
+	switch (vax_boardtype) {
+	default:
+		return 0;
+
+	case VAX_BTYP_410:
+	case VAX_BTYP_420:
+	case VAX_BTYP_43:
+		if (va->va_paddr != GPXADDR)
+			return 0;
+
+		/* not present on microvaxes */
+		if ((vax_confdata & KA420_CFG_MULTU) != 0)
+			return 0;
+
+		if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
+			return 0;
+		break;
+	}
+
+	/* Check for hardware */
+	adder = (volatile struct adder *)
+	    vax_map_physmem(va->va_paddr + GPX_ADDER_OFFSET, 1);
+	if (adder == NULL)
+		return 0;
+	adder->status = 0;
+	status = adder->status;
+	vax_unmap_physmem((vaddr_t)adder, 1);
+	if (status == offsetof(struct adder, status))
+		return 0;
+
+	/* Check for a recognized color depth */
+	tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
+	if (tmp == 0L)
+		return 0;
+	depth = (*(volatile uint16_t *)tmp) & 0x00f0;
+	vax_unmap_physmem(tmp, 1);
+	if (depth != 0x00f0 && depth != 0x0080)
+		return 0;
+
+	/* when already running as console, always fake things */
+	if ((vax_confdata & KA420_CFG_L3CON) == 0
+#if NWSDISPLAY > 0
+	    && cn_tab->cn_putc == wsdisplay_cnputc
+#endif
+	) {
+		struct vsbus_softc *sc = device_private(parent);
+		sc->sc_mask = 0x08;
+		scb_fake(0x44, 0x15);
+	} else {
+		adder = (struct adder *)vax_map_physmem(va->va_paddr +
+		    GPX_ADDER_OFFSET, 1);
+		if (adder == NULL)
+			return 0;
+		adder->interrupt_enable = FRAME_SYNC;
+		DELAY(100000);	/* enough to get a retrace interrupt */
+		adder->interrupt_enable = 0;
+		vax_unmap_physmem((vaddr_t)adder, 1);
+	}
+	return 20;
+}
+
+void
+gpx_attach(device_t parent, device_t self, void *aux)
+{
+	struct gpx_softc *sc = device_private(self);
+	struct vsbus_attach_args *va = aux;
+	struct gpx_screen *scr;
+	struct wsemuldisplaydev_attach_args aa;
+	int console;
+	vaddr_t tmp;
+
+	sc->sc_dev = self;
+	console =
+#if NWSDISPLAY > 0
+	    (vax_confdata & KA420_CFG_L3CON) == 0 &&
+	    cn_tab->cn_putc == wsdisplay_cnputc;
+#else
+	    (vax_confdata & KA420_CFG_L3CON) == 0;
+#endif
+	if (console) {
+		scr = &gpx_consscr;
+		sc->sc_nscreens = 1;
+	} else {
+		scr = kmem_zalloc(sizeof(*scr), KM_SLEEP);
+
+		tmp = vax_map_physmem(va->va_paddr + GPX_READBACK_OFFSET, 1);
+		if (tmp == 0L) {
+			printf(": can not probe depth\n");
+			goto bad1;
+		}
+		scr->ss_depth = (*(uint16_t *)tmp & 0x00f0) == 0x00f0 ? 4 : 8;
+		vax_unmap_physmem(tmp, 1);
+
+		scr->ss_adder = (struct adder *)vax_map_physmem(va->va_paddr +
+		    GPX_ADDER_OFFSET, 1);
+		if (scr->ss_adder == NULL) {
+			aprint_error(": can not map frame buffer registers\n");
+			goto bad1;
+		}
+
+		scr->ss_vdac = (void *)vax_map_physmem(va->va_paddr +
+		    GPX_VDAC_OFFSET, 1);
+		if (scr->ss_vdac == NULL) {
+			aprint_error(": can not map RAMDAC\n");
+			goto bad2;
+		}
+
+#if 0
+		scr->ss_cursor =
+		    (struct dc503reg *)vax_map_physmem(va->va_paddr +
+		    GPX_CURSOR_OFFSET, 1);
+		if (scr->ss_cursor == NULL) {
+			aprint_error(": can not map cursor chip\n");
+			goto bad3;
+		}
+#endif
+
+		if (gpx_setup_screen(scr) != 0) {
+			aprint_error(": initialization failed\n");
+			goto bad4;
+		}
+	}
+	sc->sc_scr = scr;
+
+	aprint_normal("\n");
+	aprint_normal_dev(self, "%dx%d %d plane color framebuffer\n",
+	    GPX_WIDTH, GPX_VISHEIGHT, scr->ss_depth);
+
+	aa.console = console;
+	aa.scrdata = &gpx_screenlist;
+	aa.accessops = &gpx_accessops;
+	aa.accesscookie = sc;
+
+	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
+
+	return;
+
+ bad4:
+#if 0
+	vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1);
+ bad3:
+#endif
+	vax_unmap_physmem((vaddr_t)scr->ss_vdac, 1);
+ bad2:
+	vax_unmap_physmem((vaddr_t)scr->ss_adder, 1);
+ bad1:
+	kmem_free(scr, sizeof(*scr));
+}
+
+/*
+ * wsdisplay accessops
+ */
+
+int
+gpx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
+{
+	struct gpx_softc *sc = v;
+	struct gpx_screen *ss = sc->sc_scr;
+	struct wsdisplay_fbinfo *wdf;
+	struct wsdisplay_cmap *cm;
+	int error;
+
+	switch (cmd) {
+	case WSDISPLAYIO_GTYPE:
+		*(u_int *)data = WSDISPLAY_TYPE_GPX;
+		break;
+
+	case WSDISPLAYIO_GINFO:
+		wdf = (struct wsdisplay_fbinfo *)data;
+		wdf->height = ss->ss_ri.ri_height;
+		wdf->width = ss->ss_ri.ri_width;
+		wdf->depth = ss->ss_depth;
+		wdf->cmsize = 1 << ss->ss_depth;
+		break;
+
+	case WSDISPLAYIO_GETCMAP:
+		cm = (struct wsdisplay_cmap *)data;
+		error = gpx_getcmap(ss, cm);
+		if (error != 0)
+			return error;
+		break;
+	case WSDISPLAYIO_PUTCMAP:
+		cm = (struct wsdisplay_cmap *)data;
+		error = gpx_putcmap(ss, cm);
+		if (error != 0)
+			return error;
+		gpx_loadcmap(ss, cm->index, cm->count);
+		break;
+
+	case WSDISPLAYIO_GVIDEO:
+	case WSDISPLAYIO_SVIDEO:
+		break;
+
+	case WSDISPLAYIO_LINEBYTES:	/* no linear mapping */
+		return -1;
+
+	default:
+		return EPASSTHROUGH;
+	}
+	return 0;
+}
+
+paddr_t
+gpx_mmap(void *v, void *vs, off_t offset, int prot)
+{
+
+	return -1;
+}
+
+int
+gpx_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+    int *curxp, int *curyp, long *defattrp)
+{
+	struct gpx_softc *sc = v;
+	struct gpx_screen *ss = sc->sc_scr;
+	struct rasops_info *ri = &ss->ss_ri;
+
+	if (sc->sc_nscreens > 0)
+		return ENOMEM;
+
+	*cookiep = ri;
+	*curxp = *curyp = 0;
+	ri->ri_ops.allocattr(ri, 0, 0, 0, defattrp);
+	sc->sc_nscreens++;
+
+	return 0;
+}
+
+void
+gpx_free_screen(void *v, void *cookie)
+{
+	struct gpx_softc *sc = v;
+
+	sc->sc_nscreens--;
+}
+
+int
+gpx_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg)
+{
+
+	return 0;
+}
+
+/*
+ * wsdisplay emulops
+ */
+
+void
+gpx_putchar(void *v, int row, int col, u_int uc, long attr)
+{
+	struct rasops_info *ri = v;
+	struct gpx_screen *ss = ri->ri_hw;
+	struct wsdisplay_font *font = ri->ri_font;
+	int dx, dy, sx, sy, fg, bg, ul;
+
+	rasops_unpack_attr(attr, &fg, &bg, &ul);
+
+	/* find where to output the glyph... */
+	dx = col * font->fontwidth + ri->ri_xorigin;
+	dy = row * font->fontheight + ri->ri_yorigin;
+	/* ... and where to pick it from */
+	uc -= font->firstchar;
+	sx = (uc % ss->ss_gpr) * font->stride * NBBY;
+	sy = GPX_HEIGHT - (1 + uc / ss->ss_gpr) * font->fontheight;
+
+	/* setup VIPER operand control registers */
+	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
+	gpx_viper_write(ss, SRC1_OCR_B,
+	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, DST_OCR_B,
+	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, MASK_1, 0xffff);
+	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
+	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
+	ss->ss_adder->x_clip_min = 0;
+	ss->ss_adder->x_clip_max = GPX_WIDTH;
+	ss->ss_adder->y_clip_min = 0;
+	ss->ss_adder->y_clip_max = GPX_VISHEIGHT;
+	/* load DESTINATION origin and vectors */
+	ss->ss_adder->fast_dest_dy = 0;
+	ss->ss_adder->slow_dest_dx = 0;
+	ss->ss_adder->error_1 = 0;
+	ss->ss_adder->error_2 = 0;
+	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+	gpx_wait(ss, RASTEROP_COMPLETE);
+	ss->ss_adder->destination_x = dx;
+	ss->ss_adder->fast_dest_dx = font->fontwidth;
+	ss->ss_adder->destination_y = dy;
+	ss->ss_adder->slow_dest_dy = font->fontheight;
+	/* load SOURCE origin and vectors */
+	ss->ss_adder->source_1_x = sx;
+	ss->ss_adder->source_1_y = sy;
+	ss->ss_adder->source_1_dx = font->fontwidth;
+	ss->ss_adder->source_1_dy = font->fontheight;
+	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
+
+	if (ul != 0) {
+		gpx_fillrect(ss, dx, dy + font->fontheight - 2, font->fontwidth,
+		    1, attr, LF_R3);	/* fg fill */
+	}
+}
+
+void
+gpx_copycols(void *v, int row, int src, int dst, int cnt)
+{
+	struct rasops_info *ri = v;
+	struct gpx_screen *ss = ri->ri_hw;
+	struct wsdisplay_font *font = ri->ri_font;
+	int sx, y, dx, w, h;
+
+	sx = ri->ri_xorigin + src * font->fontwidth;
+	dx = ri->ri_xorigin + dst * font->fontwidth;
+	w = cnt * font->fontwidth;
+	y = ri->ri_yorigin + row * font->fontheight;
+	h = font->fontheight;
+
+	gpx_copyrect(ss, sx, y, dx, y, w, h);
+}
+
+void
+gpx_erasecols(void *v, int row, int col, int cnt, long attr)
+{
+	struct rasops_info *ri = v;
+	struct gpx_screen *ss = ri->ri_hw;
+	struct wsdisplay_font *font = ri->ri_font;
+	int x, y, dx, dy;
+
+	x = ri->ri_xorigin + col * font->fontwidth;
+	dx = cnt * font->fontwidth;
+	y = ri->ri_yorigin + row * font->fontheight;
+	dy = font->fontheight;
+
+	gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
+}
+
+void
+gpx_copyrows(void *v, int src, int dst, int cnt)
+{
+	struct rasops_info *ri = v;
+	struct gpx_screen *ss = ri->ri_hw;
+	struct wsdisplay_font *font = ri->ri_font;
+	int x, sy, dy, w, h;
+
+	x = ri->ri_xorigin;
+	w = ri->ri_emustride;
+	sy = ri->ri_yorigin + src * font->fontheight;
+	dy = ri->ri_yorigin + dst * font->fontheight;
+	h = cnt * font->fontheight;
+
+	gpx_copyrect(ss, x, sy, x, dy, w, h);
+}
+
+void
+gpx_eraserows(void *v, int row, int cnt, long attr)
+{
+	struct rasops_info *ri = v;
+	struct gpx_screen *ss = ri->ri_hw;
+	struct wsdisplay_font *font = ri->ri_font;
+	int x, y, dx, dy;
+
+	x = ri->ri_xorigin;
+	dx = ri->ri_emustride;
+	y = ri->ri_yorigin + row * font->fontheight;
+	dy = cnt * font->fontheight;
+
+	gpx_fillrect(ss, x, y, dx, dy, attr, LF_R2); /* bg fill */
+}
+
+void
+gpx_do_cursor(struct rasops_info *ri)
+{
+	struct gpx_screen *ss = ri->ri_hw;
+	int x, y, w, h;
+
+	x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
+	y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
+	w = ri->ri_font->fontwidth;
+	h = ri->ri_font->fontheight;
+
+	gpx_fillrect(ss, x, y, w, h, WSCOL_WHITE << 24, LF_R4);	/* invert */
+}
+
+/*
+ * low-level programming routines
+ */
+
+int
+gpx_wait(struct gpx_screen *ss, int bits)
+{
+	int i;
+
+	ss->ss_adder->status = 0;
+	for (i = 100000; i != 0; i--) {
+		if ((ss->ss_adder->status & bits) == bits)
+			break;
+		DELAY(1);
+	}
+
+	return i == 0;
+}
+
+int
+gpx_viper_write(struct gpx_screen *ss, u_int reg, uint16_t val)
+{
+	if (gpx_wait(ss, ADDRESS_COMPLETE) == 0 &&
+	    gpx_wait(ss, TX_READY) == 0) {
+		ss->ss_adder->id_data = val;
+		ss->ss_adder->command = ID_LOAD | reg;
+		return 0;
+	}
+#ifdef DEBUG
+	if (ss->ss_console == 0)	/* don't make things worse! */
+		printf("gpx_viper_write failure, reg %x val %x\n", reg, val);
+#endif
+	return 1;
+}
+
+/* Initialize the damned beast. Straight from qdss. */
+void
+gpx_reset_viper(struct gpx_screen *ss)
+{
+	int i;
+
+	ss->ss_adder->interrupt_enable = 0;
+	ss->ss_adder->command = CANCEL;
+	/* set monitor timing */
+	ss->ss_adder->x_scan_count_0 = 0x2800;
+	ss->ss_adder->x_scan_count_1 = 0x1020;
+	ss->ss_adder->x_scan_count_2 = 0x003a;
+	ss->ss_adder->x_scan_count_3 = 0x38f0;
+	ss->ss_adder->x_scan_count_4 = 0x6128;
+	ss->ss_adder->x_scan_count_5 = 0x093a;
+	ss->ss_adder->x_scan_count_6 = 0x313c;
+	ss->ss_adder->sync_phase_adj = 0x0100;
+	ss->ss_adder->x_scan_conf = 0x00c8;
+	/*
+	 * got a bug in second pass ADDER! lets take care of it...
+	 *
+	 * normally, just use the code in the following bug fix code, but to
+	 * make repeated demos look pretty, load the registers as if there was
+	 * no bug and then test to see if we are getting sync
+	 */
+	ss->ss_adder->y_scan_count_0 = 0x135f;
+	ss->ss_adder->y_scan_count_1 = 0x3363;
+	ss->ss_adder->y_scan_count_2 = 0x2366;
+	ss->ss_adder->y_scan_count_3 = 0x0388;
+	/*
+	 * if no sync, do the bug fix code
+	 */
+	if (gpx_wait(ss, FRAME_SYNC) != 0) {
+		/*
+		 * First load all Y scan registers with very short frame and
+		 * wait for scroll service.  This guarantees at least one SYNC
+		 * to fix the pass 2 Adder initialization bug (synchronizes
+		 * XCINCH with DMSEEDH)
+		 */
+		ss->ss_adder->y_scan_count_0 = 0x01;
+		ss->ss_adder->y_scan_count_1 = 0x01;
+		ss->ss_adder->y_scan_count_2 = 0x01;
+		ss->ss_adder->y_scan_count_3 = 0x01;
+		/* delay at least 1 full frame time */
+		gpx_wait(ss, FRAME_SYNC);
+		gpx_wait(ss, FRAME_SYNC);
+		/*
+		 * now load the REAL sync values (in reverse order just to
+		 * be safe).
+		 */
+		ss->ss_adder->y_scan_count_3 = 0x0388;
+		ss->ss_adder->y_scan_count_2 = 0x2366;
+		ss->ss_adder->y_scan_count_1 = 0x3363;
+		ss->ss_adder->y_scan_count_0 = 0x135f;
+	}
+	/* zero the index registers */
+	ss->ss_adder->x_index_pending = 0;
+	ss->ss_adder->y_index_pending = 0;
+	ss->ss_adder->x_index_new = 0;
+	ss->ss_adder->y_index_new = 0;
+	ss->ss_adder->x_index_old = 0;
+	ss->ss_adder->y_index_old = 0;
+	ss->ss_adder->pause = 0;
+	/* set rasterop mode to normal pen down */
+	ss->ss_adder->rasterop_mode =
+	    DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+	/* set the rasterop registers to default values */
+	ss->ss_adder->source_1_dx = 1;
+	ss->ss_adder->source_1_dy = 1;
+	ss->ss_adder->source_1_x = 0;
+	ss->ss_adder->source_1_y = 0;
+	ss->ss_adder->destination_x = 0;
+	ss->ss_adder->destination_y = 0;
+	ss->ss_adder->fast_dest_dx = 1;
+	ss->ss_adder->fast_dest_dy = 0;
+	ss->ss_adder->slow_dest_dx = 0;
+	ss->ss_adder->slow_dest_dy = 1;
+	ss->ss_adder->error_1 = 0;
+	ss->ss_adder->error_2 = 0;
+	/* scale factor = UNITY */
+	ss->ss_adder->fast_scale = UNITY;
+	ss->ss_adder->slow_scale = UNITY;
+	/* set the source 2 parameters */
+	ss->ss_adder->source_2_x = 0;
+	ss->ss_adder->source_2_y = 0;
+	ss->ss_adder->source_2_size = 0x0022;
+	/* initialize plane addresses for eight vipers */
+	for (i = 0; i < 8; i++) {
+		gpx_viper_write(ss, CS_UPDATE_MASK, 1 << i);
+		gpx_viper_write(ss, PLANE_ADDRESS, i);
+	}
+	/* initialize the external registers. */
+	gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
+	gpx_viper_write(ss, CS_SCROLL_MASK, 0x00ff);
+	/* initialize resolution mode */
+	gpx_viper_write(ss, MEMORY_BUS_WIDTH, 0x000c);	/* bus width = 16 */
+	gpx_viper_write(ss, RESOLUTION_MODE, 0x0000);	/* one bit/pixel */
+	/* initialize viper registers */
+	gpx_viper_write(ss, SCROLL_CONSTANT,
+	    SCROLL_ENABLE | VIPER_LEFT | VIPER_UP);
+	gpx_viper_write(ss, SCROLL_FILL, 0x0000);
+	/* set clipping and scrolling limits to full screen */
+	gpx_wait(ss, ADDRESS_COMPLETE);
+	ss->ss_adder->x_clip_min = 0;
+	ss->ss_adder->x_clip_max = GPX_WIDTH;
+	ss->ss_adder->y_clip_min = 0;
+	ss->ss_adder->y_clip_max = GPX_HEIGHT;
+	ss->ss_adder->scroll_x_min = 0;
+	ss->ss_adder->scroll_x_max = GPX_WIDTH;
+	ss->ss_adder->scroll_y_min = 0;
+	ss->ss_adder->scroll_y_max = GPX_HEIGHT;
+	gpx_wait(ss, FRAME_SYNC);	/* wait at LEAST 1 full frame */
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->x_index_pending = 0;
+	ss->ss_adder->y_index_pending = 0;
+	ss->ss_adder->x_index_new = 0;
+	ss->ss_adder->y_index_new = 0;
+	ss->ss_adder->x_index_old = 0;
+	ss->ss_adder->y_index_old = 0;
+	gpx_wait(ss, ADDRESS_COMPLETE);
+	gpx_viper_write(ss, LEFT_SCROLL_MASK, 0x0000);
+	gpx_viper_write(ss, RIGHT_SCROLL_MASK, 0x0000);
+	/* set source and the mask register to all ones */
+	gpx_viper_write(ss, SOURCE, 0xffff);
+	gpx_viper_write(ss, MASK_1, 0xffff);
+	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+	/* initialize Operand Control Register banks for fill command */
+	gpx_viper_write(ss, SRC1_OCR_A, EXT_NONE | INT_M1_M2  | NO_ID | WAIT);
+	gpx_viper_write(ss, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
+	gpx_viper_write(ss, DST_OCR_A, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+	gpx_viper_write(ss, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
+	gpx_viper_write(ss, SRC2_OCR_B, EXT_NONE | INT_M1_M2  | NO_ID | NO_WAIT);
+	gpx_viper_write(ss, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
+
+	/*
+	 * Init Logic Unit Function registers.
+	 */
+	/* putchar */
+	gpx_viper_write(ss, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
+	/* erase{cols,rows} */
+	gpx_viper_write(ss, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_ZEROS);
+	/* underline */
+	gpx_viper_write(ss, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_ONES);
+	/* cursor */
+	gpx_viper_write(ss, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_NOT_D);
+}
+
+/* Clear the whole screen. Straight from qdss. */
+void
+gpx_clear_screen(struct gpx_screen *ss)
+{
+
+	ss->ss_adder->x_limit = GPX_WIDTH;
+	ss->ss_adder->y_limit = GPX_HEIGHT;
+	ss->ss_adder->y_offset_pending = 0;
+	gpx_wait(ss, FRAME_SYNC);	/* wait at LEAST 1 full frame */
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_offset_pending = GPX_VISHEIGHT;
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_offset_pending = 2 * GPX_VISHEIGHT;
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_scroll_constant = SCROLL_ERASE;
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->y_offset_pending = 0;	 /* back to normal */
+	gpx_wait(ss, FRAME_SYNC);
+	gpx_wait(ss, FRAME_SYNC);
+	ss->ss_adder->x_limit = GPX_WIDTH;
+	ss->ss_adder->y_limit = GPX_VISHEIGHT;
+}
+
+int
+gpx_setup_screen(struct gpx_screen *ss)
+{
+	struct rasops_info *ri = &ss->ss_ri;
+	int cookie;
+
+	memset(ri, 0, sizeof(*ri));
+	ri->ri_depth = 8;	/* masquerade as a 8 bit device for rasops */
+	ri->ri_width = GPX_WIDTH;
+	ri->ri_height = GPX_VISHEIGHT;
+	ri->ri_stride = GPX_WIDTH;
+	ri->ri_flg = RI_CENTER;		/* no RI_CLEAR as ri_bits is NULL! */
+	ri->ri_hw = ss;
+	if (ss == &gpx_consscr)
+		ri->ri_flg |= RI_NO_AUTO;
+
+	/*
+	 * We can not let rasops select our font, because we need to use
+	 * a font with right-to-left bit order on this frame buffer.
+	 */
+	wsfont_init();
+	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
+	    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
+	if (cookie < 0)
+		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L,
+		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
+	if (cookie < 0)
+		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
+		    WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
+	if (cookie < 0)
+		return -1;
+	if (wsfont_lock(cookie, &ri->ri_font) != 0)
+		return -1;
+	ri->ri_wsfcookie = cookie;
+
+	/*
+	 * Ask for an unholy big display, rasops will trim this to more
+	 * reasonable values.
+	 */
+	if (rasops_init(ri, 160, 160) != 0)
+		return -1;
+
+	/*
+	 * Override the rasops emulops.
+	 */
+	ri->ri_ops.copyrows = gpx_copyrows;
+	ri->ri_ops.copycols = gpx_copycols;
+	ri->ri_ops.eraserows = gpx_eraserows;
+	ri->ri_ops.erasecols = gpx_erasecols;
+	ri->ri_ops.putchar = gpx_putchar;
+	ri->ri_do_cursor = gpx_do_cursor;
+
+	gpx_stdscreen.ncols = ri->ri_cols;
+	gpx_stdscreen.nrows = ri->ri_rows;
+	gpx_stdscreen.textops = &ri->ri_ops;
+	gpx_stdscreen.fontwidth = ri->ri_font->fontwidth;
+	gpx_stdscreen.fontheight = ri->ri_font->fontheight;
+	gpx_stdscreen.capabilities = ri->ri_caps;
+
+	/*
+	 * Initialize RAMDAC.
+	 */
+	if (ss->ss_depth == 8) {
+		struct ramdac8 *rd = ss->ss_vdac;
+		rd->address = BT_CR;
+		rd->control = BTCR_RAMENA | BTCR_BLINK_1648 | BTCR_MPLX_4;
+	} else {
+		struct ramdac4 *rd = ss->ss_vdac;
+		rd->control = RAMDAC4_INIT;
+	}
+
+	/*
+	 * Put the ADDER and VIPER in a good state.
+	 */
+	gpx_reset_viper(ss);
+
+	/*
+	 * Initialize colormap.
+	 */
+	gpx_resetcmap(ss);
+
+	/*
+	 * Clear display (including non-visible area), in 864 lines chunks.
+	 */
+	gpx_clear_screen(ss);
+
+	/*
+	 * Copy our font to the offscreen area.
+	 */
+	gpx_upload_font(ss);
+
+#if 0
+	ss->ss_cursor->cmdr = ss->ss_curcmd = PCCCMD_HSHI;
+#endif
+
+	return 0;
+}
+
+/*
+ * Copy the selected wsfont to non-visible frame buffer area.
+ * This is necessary since the only way to send data to the frame buffer
+ * is through the ID interface, which is slow and needs 16 bit wide data.
+ * Adapted from qdss.
+ */
+void
+gpx_upload_font(struct gpx_screen *ss)
+{
+	struct rasops_info *ri = &ss->ss_ri;
+	struct wsdisplay_font *font = ri->ri_font;
+	uint8_t *fontbits, *fb;
+	u_int remaining, nchars, row;
+	u_int i, j;
+	uint16_t data;
+
+	/* setup VIPER operand control registers */
+
+	gpx_viper_write(ss, MASK_1, 0xffff);
+	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+
+	gpx_viper_write(ss, SRC1_OCR_B,
+	    EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, SRC2_OCR_B,
+	    EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, DST_OCR_B,
+	    EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+
+	ss->ss_adder->rasterop_mode =
+	    DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
+	gpx_wait(ss, RASTEROP_COMPLETE);
+
+	/*
+	 * Load font data. The font is uploaded in 8 or 16 bit wide cells, on
+	 * as many ``lines'' as necessary at the end of the display.
+	 */
+	ss->ss_gpr = MIN(GPX_WIDTH / (NBBY * font->stride), font->numchars);
+	if (ss->ss_gpr & 1)
+		ss->ss_gpr--;
+	fontbits = font->data;
+	for (row = 1, remaining = font->numchars; remaining != 0;
+	    row++, remaining -= nchars) {
+		nchars = MIN(ss->ss_gpr, remaining);
+
+		ss->ss_adder->destination_x = 0;
+		ss->ss_adder->destination_y =
+		    GPX_HEIGHT - row * font->fontheight;
+		ss->ss_adder->fast_dest_dx = nchars * 16;
+		ss->ss_adder->slow_dest_dy = font->fontheight;
+
+		/* setup for processor to bitmap xfer */
+		gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff);
+		ss->ss_adder->cmd = PBT | OCRB | DTE | LF_R1 | 2; /*XXX why 2?*/
+
+		/* iteratively do the processor to bitmap xfer */
+		for (i = font->fontheight; i != 0; i--) {
+			fb = fontbits;
+			fontbits += font->stride;
+			/* PTOB a scan line */
+			for (j = nchars; j != 0; j--) {
+				/* PTOB one scan of a char cell */
+				if (font->stride == 1) {
+					data = *fb;
+					fb += font->fontheight;
+					/*
+					 * Do not access past font memory if
+					 * it has an odd number of characters
+					 * and this is the last pair.
+					 */
+					if (j != 1 || (nchars & 1) == 0 ||
+					    remaining != nchars) {
+						data |= ((uint16_t)*fb) << 8;
+						fb += font->fontheight;
+					}
+				} else {
+					data =
+					    fb[0] | (((uint16_t)fb[1]) << 8);
+					fb += font->fontheight * font->stride;
+				}
+
+				gpx_wait(ss, TX_READY);
+				ss->ss_adder->id_data = data;
+			}
+		}
+		fontbits += (nchars - 1) * font->stride * font->fontheight;
+	}
+}
+
+void
+gpx_copyrect(struct gpx_screen *ss,
+    int sx, int sy, int dx, int dy, int w, int h)
+{
+
+	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff))
+		continue;
+	gpx_viper_write(ss, MASK_1, 0xffff);
+	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
+	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
+	gpx_viper_write(ss, SRC1_OCR_B,
+	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, DST_OCR_B,
+	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+	ss->ss_adder->fast_dest_dy = 0;
+	ss->ss_adder->slow_dest_dx = 0;
+	ss->ss_adder->error_1 = 0;
+	ss->ss_adder->error_2 = 0;
+	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+	gpx_wait(ss, RASTEROP_COMPLETE);
+	ss->ss_adder->destination_x = dx;
+	ss->ss_adder->fast_dest_dx = w;
+	ss->ss_adder->destination_y = dy;
+	ss->ss_adder->slow_dest_dy = h;
+	ss->ss_adder->source_1_x = sx;
+	ss->ss_adder->source_1_dx = w;
+	ss->ss_adder->source_1_y = sy;
+	ss->ss_adder->source_1_dy = h;
+	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | LF_R1;
+}
+
+/*
+ * Fill a rectangle with the given attribute and function (i.e. rop).
+ */
+void
+gpx_fillrect(struct gpx_screen *ss, int x, int y, int dx, int dy, long attr,
+    u_int function)
+{
+	int fg, bg;
+
+	rasops_unpack_attr(attr, &fg, &bg, NULL);
+
+	while (gpx_viper_write(ss, CS_UPDATE_MASK, 0x00ff));
+	gpx_viper_write(ss, MASK_1, 0xffff);
+	gpx_viper_write(ss, SOURCE, 0xffff);
+	gpx_viper_write(ss, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, fg);
+	gpx_viper_write(ss, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, bg);
+	gpx_viper_write(ss, SRC1_OCR_B,
+	    EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
+	gpx_viper_write(ss, DST_OCR_B,
+	    EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
+	ss->ss_adder->fast_dest_dx = 0;
+	ss->ss_adder->fast_dest_dy = 0;
+	ss->ss_adder->slow_dest_dx = 0;
+	ss->ss_adder->error_1 = 0;
+	ss->ss_adder->error_2 = 0;
+	ss->ss_adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
+	gpx_wait(ss, RASTEROP_COMPLETE);
+	ss->ss_adder->destination_x = x;
+	ss->ss_adder->fast_dest_dx = dx;
+	ss->ss_adder->destination_y = y;
+	ss->ss_adder->slow_dest_dy = dy;
+	ss->ss_adder->source_1_x = x;
+	ss->ss_adder->source_1_dx = dx;
+	ss->ss_adder->source_1_y = y;
+	ss->ss_adder->source_1_dy = dy;
+	ss->ss_adder->cmd = RASTEROP | OCRB | S1E | DTE | function;
+}
+
+/*
+ * Colormap handling routines
+ */
+
+int
+gpx_getcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
+{
+	u_int index = cm->index, count = cm->count, i;
+	u_int colcount = 1 << ss->ss_depth;
+	int error;
+	uint8_t ramp[256], *c, *r;
+
+	if (index >= colcount || count > colcount - index)
+		return EINVAL;
+
+	/* extract reds */
+	c = ss->ss_cmap + 0 + index * 3;
+	for (i = count, r = ramp; i != 0; i--)
+		*r++ = *c << (8 - ss->ss_depth), c += 3;
+	if ((error = copyout(ramp, cm->red, count)) != 0)
+		return error;
+
+	/* extract greens */
+	c = ss->ss_cmap + 1 + index * 3;
+	for (i = count, r = ramp; i != 0; i--)
+		*r++ = *c << (8 - ss->ss_depth), c += 3;
+	if ((error = copyout(ramp, cm->green, count)) != 0)
+		return error;
+
+	/* extract blues */
+	c = ss->ss_cmap + 2 + index * 3;
+	for (i = count, r = ramp; i != 0; i--)
+		*r++ = *c << (8 - ss->ss_depth), c += 3;
+	if ((error = copyout(ramp, cm->blue, count)) != 0)
+		return error;
+
+	return 0;
+}
+
+int
+gpx_putcmap(struct gpx_screen *ss, struct wsdisplay_cmap *cm)
+{
+	u_int index = cm->index, count = cm->count;
+	u_int colcount = 1 << ss->ss_depth;
+	int i, error;
+	uint8_t r[256], g[256], b[256], *nr, *ng, *nb, *c;
+
+	if (index >= colcount || count > colcount - index)
+		return EINVAL;
+
+	if ((error = copyin(cm->red, r, count)) != 0)
+		return error;
+	if ((error = copyin(cm->green, g, count)) != 0)
+		return error;
+	if ((error = copyin(cm->blue, b, count)) != 0)
+		return error;
+
+	nr = r, ng = g, nb = b;
+	c = ss->ss_cmap + index * 3;
+	for (i = count; i != 0; i--) {
+		*c++ = *nr++ >> (8 - ss->ss_depth);
+		*c++ = *ng++ >> (8 - ss->ss_depth);
+		*c++ = *nb++ >> (8 - ss->ss_depth);
+	}
+
+	return 0;
+}
+
+void
+gpx_loadcmap(struct gpx_screen *ss, int from, int count)
+{
+	uint8_t *cmap = ss->ss_cmap;
+	int i, color12;
+
+	gpx_wait(ss, FRAME_SYNC);
+	if (ss->ss_depth == 8) {
+		struct ramdac8 *rd = ss->ss_vdac;
+
+		cmap += from * 3;
+		rd->address = from;
+		for (i = 0; i < count * 3; i++)
+			rd->cmapdata = *cmap++;
+	} else {
+		struct ramdac4 *rd = ss->ss_vdac;
+
+		cmap = ss->ss_cmap + from;
+		for (i = from; i < from + count; i++) {
+			color12  = (*cmap++ >> 4) << 0;
+			color12 |= (*cmap++ >> 4) << 8;
+			color12 |= (*cmap++ >> 4) << 4;
+			rd->colormap[i] = color12;
+		}
+	}
+}
+
+void
+gpx_resetcmap(struct gpx_screen *ss)
+{
+
+	if (ss->ss_depth == 8)
+		memcpy(ss->ss_cmap, rasops_cmap, sizeof(ss->ss_cmap));
+	else {
+		memcpy(ss->ss_cmap, rasops_cmap, 8 * 3);
+		memcpy(ss->ss_cmap + 8 * 3, rasops_cmap + 0xf8 * 3, 8 * 3);
+	}
+	gpx_loadcmap(ss, 0, 1 << ss->ss_depth);
+
+	/*
+	 * On the 4bit RAMDAC, make the hardware cursor black on black
+	 */
+	if (ss->ss_depth != 8) {
+		struct ramdac4 *rd = ss->ss_vdac;
+
+		rd->cursormap[0] = rd->cursormap[1] =
+		    rd->cursormap[2] = rd->cursormap[3] = 0x0000;
+	}
+}
+
+/*
+ * Console support code
+ */
+
+cons_decl(gpx);
+
+/*
+ * Called very early to setup the glass tty as console.
+ * Because it's called before the VM system is initialized, virtual memory
+ * for the framebuffer can be stolen directly without disturbing anything.
+ */
+void
+gpxcnprobe(struct consdev *cndev)
+{
+	extern vaddr_t virtual_avail;
+	extern const struct cdevsw wsdisplay_cdevsw;
+	volatile struct adder *adder;
+	vaddr_t tmp;
+	int depth;
+	u_short status;
+
+	switch (vax_boardtype) {
+	case VAX_BTYP_410:
+	case VAX_BTYP_420:
+	case VAX_BTYP_43:
+		if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0)
+			break; /* doesn't use graphics console */
+
+		if ((vax_confdata & KA420_CFG_VIDOPT) == 0)
+			break; /* no color option */
+
+		/* Check for hardware */
+		tmp = virtual_avail;
+		ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_ADDER_OFFSET), 1);
+		adder = (struct adder *)tmp;
+		adder->status = 0;
+		status = adder->status;
+		iounaccess(tmp, 1);
+		if (status == offsetof(struct adder, status))
+			return;
+
+		/* Check for a recognized color depth */
+		tmp = virtual_avail;
+		ioaccess(tmp, vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
+		depth = *(uint16_t *)
+		    (tmp + (GPX_READBACK_OFFSET & VAX_PGOFSET)) & 0x00f0;
+		iounaccess(tmp, 1);
+		if (depth != 0x00f0 && depth != 0x0080)
+			return;
+
+		cndev->cn_pri = CN_INTERNAL;
+		cndev->cn_dev =
+		    makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
+		break;
+
+	default:
+		break;
+	}
+}
+
+/*
+ * Called very early to setup the glass tty as console.
+ * Because it's called before the VM system is initialized, virtual memory
+ * for the framebuffer can be stolen directly without disturbing anything.
+ */
+void
+gpxcninit(struct consdev *cndev)
+{
+	struct gpx_screen *ss = &gpx_consscr;
+	extern vaddr_t virtual_avail;
+	vaddr_t ova;
+	long defattr;
+	struct rasops_info *ri;
+
+	ova = virtual_avail;
+
+	ioaccess(virtual_avail,
+	    vax_trunc_page(GPXADDR + GPX_READBACK_OFFSET), 1);
+	ss->ss_depth = (0x00f0 & *(uint16_t *)(virtual_avail +
+	    (GPX_READBACK_OFFSET & VAX_PGOFSET))) == 0x00f0 ? 4 : 8;
+
+	ioaccess(virtual_avail, GPXADDR + GPX_ADDER_OFFSET, 1);
+	ss->ss_adder = (struct adder *)virtual_avail;
+	virtual_avail += VAX_NBPG;
+
+	ioaccess(virtual_avail, vax_trunc_page(GPXADDR + GPX_VDAC_OFFSET), 1);
+	ss->ss_vdac = (void *)(virtual_avail + (GPX_VDAC_OFFSET & VAX_PGOFSET));
+	virtual_avail += VAX_NBPG;
+
+#if 0
+	ioaccess(virtual_avail, GPXADDR + GPX_CURSOR_OFFSET, 1);
+	ss->ss_cursor = (struct dc503reg *)virtual_avail;
+	virtual_avail += VAX_NBPG;
+#endif
+
+	virtual_avail = round_page(virtual_avail);
+
+	/* this had better not fail */
+	if (gpx_setup_screen(ss) != 0) {
+#if 0
+		iounaccess((vaddr_t)ss->ss_cursor, 1);
+#endif
+		iounaccess((vaddr_t)ss->ss_vdac, 1);
+		iounaccess((vaddr_t)ss->ss_adder, 1);
+		virtual_avail = ova;
+		return;
+	}
+
+	ri = &ss->ss_ri;
+	ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr);
+	wsdisplay_cnattach(&gpx_stdscreen, ri, 0, 0, defattr);
+	cn_tab->cn_pri = CN_INTERNAL;
+
+#if NDZKBD > 0
+	dzkbd_cnattach(0); /* Connect keyboard and screen together */
+#endif
+}

Reply via email to