Module Name: src
Committed By: tsutsui
Date: Mon Feb 6 13:13:06 UTC 2023
Modified Files:
src/sys/arch/vax/conf: GENERIC INSTALL VAX780 files.vax
src/sys/arch/vax/include: qdreg.h
src/sys/arch/vax/vax: conf.c
src/sys/arch/vax/vsa: smg.c
Added Files:
src/sys/arch/vax/vsa: gpx.c
Log Message:
Add a support for gpx(4) color framebuffer found on VAXstation 3100.
Poted 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
Worth to pullup to netbsd-10.
To generate a diff of this commit:
cvs rdiff -u -r1.216 -r1.217 src/sys/arch/vax/conf/GENERIC
cvs rdiff -u -r1.75 -r1.76 src/sys/arch/vax/conf/INSTALL
cvs rdiff -u -r1.33 -r1.34 src/sys/arch/vax/conf/VAX780
cvs rdiff -u -r1.125 -r1.126 src/sys/arch/vax/conf/files.vax
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/vax/include/qdreg.h
cvs rdiff -u -r1.68 -r1.69 src/sys/arch/vax/vax/conf.c
cvs rdiff -u -r0 -r1.1 src/sys/arch/vax/vsa/gpx.c
cvs rdiff -u -r1.62 -r1.63 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.217
--- src/sys/arch/vax/conf/GENERIC:1.216 Thu Sep 29 10:10:10 2022
+++ src/sys/arch/vax/conf/GENERIC Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.216 2022/09/29 10:10:10 riastradh Exp $
+# $NetBSD: GENERIC,v 1.217 2023/02/06 13:13:05 tsutsui 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.217 $"
# 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.76
--- src/sys/arch/vax/conf/INSTALL:1.75 Mon Jan 20 18:38:21 2020
+++ src/sys/arch/vax/conf/INSTALL Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-# $NetBSD: INSTALL,v 1.75 2020/01/20 18:38:21 thorpej Exp $
+# $NetBSD: INSTALL,v 1.76 2023/02/06 13:13:05 tsutsui 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.34
--- src/sys/arch/vax/conf/VAX780:1.33 Sun Aug 7 02:52:30 2022
+++ src/sys/arch/vax/conf/VAX780 Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-# $NetBSD: VAX780,v 1.33 2022/08/07 02:52:30 simonb Exp $
+# $NetBSD: VAX780,v 1.34 2023/02/06 13:13:05 tsutsui 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.126
--- src/sys/arch/vax/conf/files.vax:1.125 Sat Dec 29 11:30:12 2018
+++ src/sys/arch/vax/conf/files.vax Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-# $NetBSD: files.vax,v 1.125 2018/12/29 11:30:12 maxv Exp $
+# $NetBSD: files.vax,v 1.126 2023/02/06 13:13:05 tsutsui 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.7
--- src/sys/arch/vax/include/qdreg.h:1.6 Tue Aug 17 22:00:31 2021
+++ src/sys/arch/vax/include/qdreg.h Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: qdreg.h,v 1.6 2021/08/17 22:00:31 andvar Exp $ */
+/* $NetBSD: qdreg.h,v 1.7 2023/02/06 13:13:05 tsutsui 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.69
--- src/sys/arch/vax/vax/conf.c:1.68 Sun Jul 5 02:10:53 2015
+++ src/sys/arch/vax/vax/conf.c Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.68 2015/07/05 02:10:53 matt Exp $ */
+/* $NetBSD: conf.c,v 1.69 2023/02/06 13:13:05 tsutsui 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.69 2023/02/06 13:13:05 tsutsui 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.62 src/sys/arch/vax/vsa/smg.c:1.63
--- src/sys/arch/vax/vsa/smg.c:1.62 Fri Jan 13 19:45:45 2023
+++ src/sys/arch/vax/vsa/smg.c Mon Feb 6 13:13:05 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: smg.c,v 1.62 2023/01/13 19:45:45 tsutsui Exp $ */
+/* $NetBSD: smg.c,v 1.63 2023/02/06 13:13:05 tsutsui 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.62 2023/01/13 19:45:45 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.63 2023/02/06 13:13:05 tsutsui 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.62
#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.62
#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
--- /dev/null Mon Feb 6 13:13:06 2023
+++ src/sys/arch/vax/vsa/gpx.c Mon Feb 6 13:13:05 2023
@@ -0,0 +1,1361 @@
+/* $NetBSD: gpx.c,v 1.1 2023/02/06 13:13:05 tsutsui 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
+}