Porting LCG framebuffer driver

Gabucino <[email protected]> Sun, 13 Jun 2004 23:55:44 +0200
Newsgroups gmane.os.openbsd.vax
Message-ID <[email protected]>
I've been trying to add Blaz Antonic's excellent NetBSD driver (patch attached,
with configfile) for the LCG colour framebuffer found in the VAXstation 4000
series, but I'm getting undefined symbols during linking, and it seems that not
all of them are LCG related (though I'd need some hint on the wsfont messages
too).

Hints are greatly appreciated.

-- 
Gabucino
diff ../sys/arch/vax/conf/files.vax sys/arch/vax/conf/files.vax
--- ../sys/arch/vax/conf/files.vax	Thu May 16 09:37:41 2002
+++ sys/arch/vax/conf/files.vax	Wed Jun  9 15:45:01 2004
@@ -160,6 +160,11 @@
 attach	smg at vsbus
 file	arch/vax/vsa/smg.c		smg needs-flag
 
+# Colour framebuffer on VS4000.
+device	lcg: wsemuldisplaydev
+attach	lcg at vsbus
+file	arch/vax/vsa/lcg.c		lcg needs-flag
+
 device	lkkbd: wskbddev 
 attach	lkkbd at dz with dzkbd
 file	arch/vax/dec/dzkbd.c		dzkbd needs-flag
diff ../sys/arch/vax/conf/zsebivax sys/arch/vax/conf/zsebivax
--- ../sys/arch/vax/conf/zsebivax	Thu Jan  1 01:00:00 1970
+++ sys/arch/vax/conf/zsebivax	Wed Jun  9 15:59:01 2004
@@ -0,0 +1,150 @@
+#	$OpenBSD: GENERIC,v 1.34 2003/03/08 04:43:45 hugh Exp $
+#	$NetBSD: GENERIC,v 1.61 2000/04/19 06:50:36 itojun Exp $
+
+machine 	vax			# machine type; required
+
+include "../../../conf/GENERIC"
+
+# Here are all different supported CPU types listed.
+# One of these is required.
+#option		VAX8600
+#option		VAX8200
+#option		VAX780		# 11/780
+#option		VAX750		# 11/750
+#option		VAX630		# MV II
+#option		VAX650		# MV III, 3300, 3600, 3800, 3900
+#option		VAX660		# VAX 4000 200
+#option		VAX670		# VAX 4000 300
+#option		VAX680		# VAX 4000 {4,5,6,7}0{0,5}{,A}
+#option		VAX410		# VS 2000, 3100/{30,}
+#option		VAX43		# VS 3100/76
+#option		VAX46		# VS 4000/60
+option		VAX48		# VS 4000 VLC
+#option		VAX49		# VS 4000/90
+#option		VAX53		# VAX 4000 10X, MicroVAX 3100m9X
+
+# Max users on system; this is just a hint
+maxusers	8	
+
+option		SCSIVERBOSE	# Verbose SCSI errors
+
+# Old compat stuff; needed to run 4.3BSD Reno programs.
+# Note that if COMPAT_ULTRIX is set, you lose compatibility with
+# 4.3BSD Reno programs and get Ultrix compatibility instead.
+# (They cannot coexist).
+option		COMPAT_VAX1K	# Must be present to run old binaries.
+#option		COMPAT_ULTRIX
+
+option		INSN_EMULATE	# CPU lacks some hardware instructions.
+
+# Kernel(s) to compile
+config		bsd		swap generic
+#config		nfsbsd	root on nfs swap on nfs
+
+mainbus0	at root
+
+# All buses; from the beginning attached to mainbus.
+#abus0		at mainbus0		# Master bus on VAX 8600
+#sbi0		at mainbus0		# SBI, master bus on 11/780.
+#cmi0		at mainbus0		# 11/750 internal bus.
+#bi0		at mainbus0		# VAX 8200 
+vsbus0		at mainbus0		# All VAXstations
+#ibus0		at mainbus0		# All Microvax
+#nbi0		at mainbus0		# VAX 8800
+#xmi0		at mainbus0		# VAX 6000
+
+# Vsbus, the virtual VAXstation bus, and possible devices.
+le0		at vsbus0 csr 0x200e0000 # LANCE ethernet
+#ze0		at vsbus0 csr 0x20008000 # SGEC ethernet
+dz0		at vsbus0 csr 0x200a0000 # DC-367 DZ-11 lookalike ctlr
+dz0		at vsbus0 csr 0x25000000 # VS4000/90 4000/10X MV3100/9X serial
+#hdc0		at vsbus0 csr 0x200c0000 # HDC9224 MFM/floppy ctlr
+#ncr0		at vsbus0 csr 0x200c0080 # VS2000/3100 SCSI-ctlr
+#ncr1		at vsbus0 csr 0x200c0180 # VS2000/3100 SCSI-ctlr
+asc0		at vsbus0 csr 0x200c0080 # VS4000/60 (or VLC) SCSI-ctlr
+asc0		at vsbus0 csr 0x26000080 # VS4000/90 4000/10X MV3100/9X SCSI
+#smg0		at vsbus0 csr 0x200f0000 # Small monochrome display ctlr.
+lcg0		at vsbus0 csr 0x21801000 # Colour display ctlr. for VS4000
+#clr0		at vsbus0 csr 0x30000000 # 4- or 8-bitplans color graphics
+
+#hd*		at hdc0 drive?		# RD5x disks
+#ry*		at hdc0 drive?		# RX floppies
+
+# Ibus, the internal bus on most Microvaxen
+#uba0		at ibus0 		# Qbus adapter
+#ze0		at ibus0 		# SGEC on-board ethernet
+#le0		at ibus0		# LANCE ethernet (MV3400)
+#shac0		at ibus0 		# DSSI controller
+
+# Devices connected at VAXBI
+#cpu*		at bi? node?		# KA820/KA825 cpu
+#mem*		at bi? node?		# Memory subsystems
+#uba*		at bi? node?		# DWBUA BI-Unibus adapter
+#ni*		at bi? node?		# DEBNA/DEBNT ethernet adapter
+#kdb*		at bi? node?		# KDB50 MSCP disk ctlr
+#mscpbus*	at kdb?
+
+# CMI (VAX 11/750)
+#mem*		at cmi? tr?		# Memory subsystems
+#uba*		at cmi? tr?		# Unibus adapters
+#mba*		at cmi? tr?		# Massbus adapters
+
+# SBI (VAX 11/780, VAX 8600)
+#sbi*		at abus0		# VAX 8600 can have up to 4 SBI's.
+
+#mem*		at sbi? tr?		# Memory subsystems
+#uba*		at sbi? tr?		# Unibus adapters
+#mba*		at sbi? tr?		# Massbus adapters
+
+# Devices on Massbus adapters
+#hp*		at mba? drive?		# RM/RP disk drives
+
+# Devices on Unibus/Qbus adapters
+#uda0		at uba?	csr 0172150	# UDA50/RQDX?
+#uda1		at uba?	csr 0160334
+#mtc0		at uba? csr 0174500	# Tape MSCP ctlr
+#ts0		at uba? csr 0172520	# TS11/TSV05 tape.
+#qd0		at uba? csr 0177400	# 4- or 8-bitplans color graphics
+#qv0		at uba? csr 0177400	# Monochrome graphics
+#de0		at uba? csr 0174510	# DELUA/DEUNA
+#qe0		at uba? csr 0174440	# DEQNA/DELQA
+#dhu0		at uba? csr 0160440	# DHU-11
+#dz0		at uba? csr 0160100	# DZ-11
+#dl0		at uba? csr 0176500	# DL-11
+
+# MSCP devices
+#mscpbus*	at uda?
+#mscpbus*	at mtc?
+#mscpbus*	at kdb?
+
+#ra*		at mscpbus? drive?	# MSCP disk
+#rx*		at mscpbus? drive?	# MSCP floppy
+#mt*		at mscpbus? drive?	# MSCP tape
+
+# VS2000 builtin MFM controller (HDC9224)
+#hdc0		at vsbus0		# The strange builtin MFM controller
+
+# SCSI devices
+scsibus*	at asc?
+#scsibus*	at ncr?
+
+sd*		at scsibus? target? lun?
+st*		at scsibus? target? lun?
+cd*		at scsibus? target? lun?
+ch*		at scsibus? target? lun?
+ss*		at scsibus? target? lun?
+uk*		at scsibus? target? lun?
+
+# Workstation console
+#wsdisplay0	at smg?
+wsdisplay0	at lcg?
+
+#wsdisplay0	at clr0
+#wsdisplay0	at qd0
+#wsdisplay0	at qv0
+
+lkkbd0		at dz0 line 0
+wskbd*		at lkkbd? console ?
+lkms0		at dz0 line 1
+wsmouse*	at lkms?
+pseudo-device	wsmux
diff ../sys/arch/vax/include/lcgreg.h sys/arch/vax/include/lcgreg.h
--- ../sys/arch/vax/include/lcgreg.h	Thu Jan  1 01:00:00 1970
+++ sys/arch/vax/include/lcgreg.h	Thu Jun 10 09:00:48 2004
@@ -0,0 +1,194 @@
+/* $NetBSD: lcgreg.h,v 1.1 2000/04/24 17:09:03 matt Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef	_VAX_LCGREG_H
+#define	_VAX_LCGREG_H
+
+/* The registers of the LCG used in the VS4000/60 and VS4000/VLC.
+ * All relative to 0x20100000
+ */
+
+/* Memory Control, Flow Control, Configration Registers
+ */
+#define	LCG_REG_MEM_CONFIG		0x001800
+#define	LCG_REG_MEM_STATUS		0x001804
+#define	LCG_REG_MEM_CURRENT_STATE	0x001808
+#define	LCG_REG_MEM_ERROR		0x00180c
+#define	LCG_REG_SLOW_CONTROL_STATUS	0x001810
+
+/* Video Control Registers
+ */
+#define	LCG_REG_VIDEO_CONFIG		0x001e00
+#define	LCG_REG_VIDEO_HTIMING		0x001e10
+#define	LCG_REG_VIDEO_VTIMING		0x001e14
+#define	LCG_REG_VIDEO_TIMING		0x001e18
+#define	LCG_REG_VIDEO_X			0x000e30
+#define	LCG_REG_VIDEO_Y			0x000e30
+#define	LCG_REG_VIDEO_REFRESH_BASE	0x000e34
+#define	LCG_REG_VIDEO_REFRESH_SHIFT	0x000e40
+#define	LCG_REG_VIDEO_LUT_LOAD_COUNT	0x000e40
+#define	LCG_REG_CURSOR_SCANLINE_LW0	0x000e50
+#define	LCG_REG_CURSOR_SCANLINE_LW1	0x000e54
+#define	LCG_REG_CURSOR_SCANLINE_LW2	0x000e58
+#define	LCG_REG_CURSOR_SCANLINE_LW3	0x000e5c
+#define	LCG_REG_CURSOR_BASE		0x000e80
+#define	LCG_REG_CURSOR_XY		0x000e84
+#define	LCG_REG_CURSOR_X		0x000e84
+#define	LCG_REG_CURSOR_Y		0x000e84
+#define	LCG_REG_LUT_CONSOLE_SEL		0x000ee0
+#define	LCG_REG_LUT_COLOR_BASE_W	0x0006e4
+#define	LCG_REG_LUT_COLOR_BASE_R	0x0006e4
+#define	LCG_REG_LUT_CONTROL_BASE	0x000ee8
+#define	LCG_REG_VIDEO_COUNTER_TEST	0x000f00
+#define	LCG_REG_MEM_REFRESH_BASE	0x000f04
+
+/* Graphics Control and VM Registers
+ */
+#define	LCG_REG_LCG_GO			0x000c80
+#define	LCG_REG_NEXT_ADDRESS		0x001334
+#define	LCG_REG_PA_SPTE_PTE		0x001338
+#define	LCG_REG_TB_INVALIDATE_SINGLE	0x001a00
+#define	LCG_REG_TB_INVALIDATE_ALL	0x001a08
+#define	LCG_REG_TB_INVALIDATE_STATUS	0x001a10
+#define	LCG_REG_TB_STATUS		0x001c00
+#define	LCG_REG_TB_VPN_COUNT		0x001c04
+#define	LCG_REG_TB_DEST_VPN		0x001c14
+#define	LCG_REG_TB_SOURCE_VPN		0x001c18
+#define	LCG_REG_TB_STENCIL_VPN		0x001c1c
+#define	LCG_REG_TB_DEST_DATA_PFN_R	0x001c24
+#define	LCG_REG_TB_DEST_DATA_PFN_W	0x001c24
+#define	LCG_REG_TB_SOURCE_DATA_PFN_R	0x001c28
+#define	LCG_REG_TB_SOURCE_DATA_PFN_W	0x001c28
+#define	LCG_REG_TB_STENCIL_DATA_PFN_R	0x001c2c
+#define	LCG_REG_TB_STENCIL_DATA_PFN_W	0x001c2c
+#define	LCG_REG_TB_DEST_PRE_PFN_R	0x001c34
+#define	LCG_REG_TB_DEST_PRE_PFN_W	0x001c34
+#define	LCG_REG_TB_SOURCE_PTE_PFN_R	0x001c38
+#define	LCG_REG_TB_SOURCE_PTE_PFN_W	0x001c38
+#define	LCG_REG_TB_STENCIL_PTE_PFN_R	0x001c3c
+#define	LCG_REG_TB_STENCIL_PTE_PFN_W	0x001c3c
+#define	LCG_REG_GRAPHICS_CONFIG		0x001c90
+#define	LCG_REG_GRAPHICS_INT_STATUS	0x001c94
+#define	LCG_REG_GRAPHICS_INT_SET_ENABLE	0x001c98
+#define	LCG_REG_GRAPHICS_INT_CLR_ENABLE	0x001c9c
+#define	LCG_REG_GRAPHICS_SUB_STATUS	0x001ca0
+#define	LCG_REG_GRAPHICS_CONTROL	0x001ca4
+#define	LCG_REG_BREAKPT_ADDRESS		0x001cb0
+#define	LCG_REG_BREAKPT_VIRTUAL		0x001cb0
+#define	LCG_REG_WRITE_PROTECT_LOW_HIGH	0x001cc0
+#define	LCG_REG_WRITE_PROTECT_LOW	0x001cc0
+#define	LCG_REG_WRITE_PROTECT_HIGH	0x001cc0
+#define	LCG_REG_MAX_VIRTUAL_ADDRESS	0x002350
+#define	LCG_REG_PA_SPTE_POBR		0x002354
+
+/* Clip List / Command FIFO Registers
+ */
+#define	LCG_REG_CLIP_LIST_OFFSET	0x0004e4
+#define	LCG_REG_CLIP_LIST_BASE		0x0004e4
+#define	LCG_REG_CLIP_LIST		0x0004e4
+#define	LCG_REG_FIFO_MASKS		0x000570
+#define	LCG_REG_FIFO_HEAD_OFFSET	0x000574
+#define	LCG_REG_FIFO_BASE		0x000574
+#define	LCG_REG_FIFO_HEAD		0x000574
+#define	LCG_REG_FIFO_TAIL_OFFSET	0x000578
+#define	LCG_REG_FIFO_BASE2		0x000578
+#define	LCG_REG_FIFO_TAIL		0x000578
+#define	LCG_REG_CLIP_LIST_SAVE_OFFSET	0x000ce4
+#define	LCG_REG_FIFO_RESIDUE_LW0	0x000d00
+#define	LCG_REG_FIFO_RESIDUE_LW1	0x000d04
+#define	LCG_REG_FIFO_RESIDUE_LW2	0x000d0c
+#define	LCG_REG_FIFO_LENGTH		0x000d70
+#define	LCG_REG_FIFO_SAVE_HEAD_OFFSET	0x000d74
+#define	LCG_REG_FIFO_WINDOW_BASE	0x080000
+#define	LCG_REG_FIFO_WINDOW_END		0x100000
+
+/* Graphics Data Buffer and Pixel SLU Registers
+ */
+#define	LCG_REG_LOGICAL_FUNCTION	0x000220
+#define	LCG_REG_PLANE_MASK		0x000234
+#define	LCG_REG_SOURCE_PLANE_INDEX	0x00026c
+#define	LCG_REG_FOREGROUND_PIXEL	0x0002c0
+#define	LCG_REG_BACKGROUND_PIXEL	0x0004c0
+#define	LCG_REG_GDB_LW0			0x000d80
+#define	LCG_REG_GDB_LW1			0x000d84
+#define	LCG_REG_GDB_LW2			0x000d88
+#define	LCG_REG_GDB_LW3			0x000d8c
+#define	LCG_REG_GDB_LW4			0x000d90
+#define	LCG_REG_GDB_LW5			0x000d94
+#define	LCG_REG_GDB_LW6			0x000d98
+#define	LCG_REG_GDB_LW7			0x000d9c
+#define	LCG_REG_SLU_STATE		0x000da0
+
+/* Address Generator Registers
+ */
+#define	LCG_REG_CLIP_MIN_Y		0x000244
+#define	LCG_REG_CLIP_MIN_MAX_X		0x000248
+#define	LCG_REG_CLIP_MIN_X		0x000248
+#define	LCG_REG_CLIP_MAX_X		0x000248
+#define	LCG_REG_CLIP_MAX_Y		0x00024c
+#define	LCG_REG_DEST_X_BIAS		0x000250
+#define	LCG_REG_DEST_Y_ORIGIN		0x000254
+#define	LCG_REG_DEST_Y_STEP		0x000258
+#define	LCG_REG_SOURCE_X_BIAS		0x000260
+#define	LCG_REG_SOURCE_Y_BASE		0x000264
+#define	LCG_REG_SOURCE_Y_STEP_WIDTH	0x000268
+#define	LCG_REG_SOURCE_Y_STEP		0x000268
+#define	LCG_REG_SOURCE_WIDTH		0x000268
+#define	LCG_REG_STENCIL_X_BIAS		0x000270
+#define	LCG_REG_STENCIL_Y_BASE		0x000274
+#define	LCG_REG_STENCIL_Y_STEP		0x000278
+#define	LCG_REG_DEST_Y_BASE		0x000284
+#define	LCG_REG_DEST_X			0x000290
+#define	LCG_REG_DEST_WIDTH_HEIGHT	0x000294
+#define	LCG_REG_DEST_WIDTH		0x000294
+#define	LCG_REG_DEST_HEIGHT		0x000294
+#define	LCG_REG_AG_STATUS2		0x000320
+#define	LCG_REG_AG_CURRENT_STATE	0x000320
+#define	LCG_REG_CURRENT_OPCODE		0x000320
+#define	LCG_REG_OP_ACTION_CODE		0x000320
+#define	LCG_REG_AG_STATUS		0x000324
+#define	LCG_REG_NEXT_X			0x000330
+#define	LCG_REG_CLIP_X_DIFF		0x000330
+#define	LCG_REG_SOURCE_X_BIAS0		0x000460
+#define	LCG_REG_SOURCE_WIDTH0		0x000468
+#define	LCG_REG_DEST_X0			0x000490
+#define	LCG_REG_DEST_WIDTH0		0x000494
+#define	LCG_REG_TILE_ROTATION		0x000660
+#define	LCG_REG_TILE_WIDTH		0x000668
+ 
+#endif	/* _VAX_LCGREG_H */
diff ../sys/arch/vax/vax/conf.c sys/arch/vax/vax/conf.c
--- ../sys/arch/vax/vax/conf.c	Sat Feb 21 05:10:41 2004
+++ sys/arch/vax/vax/conf.c	Wed Jun  9 15:57:07 2004
@@ -144,6 +144,7 @@
 
 #include "wskbd.h"
 #include "smg.h"
+#include "lcg.h"
 #if NSMG > 0
 #if NWSKBD > 0
 #define smgcngetc wskbd_cngetc
@@ -159,10 +160,26 @@
 #define smgcnputc wsdisplay_cnputc
 #define	smgcnpollc nullcnpollc
 
+#if NLCG > 0
+#if NWSKBD > 0
+#define lcgcngetc wskbd_cngetc
+#else
+static int
+lcgcngetc(dev_t dev)
+{
+	return 0;
+}
+#endif	/* NWSKBD > 0 */
+#endif	/* NSMG > 0 */
+
+#define lcgcnputc wsdisplay_cnputc
+#define	lcgcnpollc nullcnpollc
+
 cons_decl(gen);
 cons_decl(dz);
 cons_decl(qd);
 cons_decl(smg);
+cons_decl(lcg);
 #include "qv.h"
 #include "qd.h"
 
@@ -187,6 +204,9 @@
 #endif
 #if NSMG
 	cons_init(smg),
+#endif
+#if NLCG
+	cons_init(lcg),
 #endif
 
 #ifdef notyet
diff ../sys/arch/vax/vsa/lcg.c sys/arch/vax/vsa/lcg.c
--- ../sys/arch/vax/vsa/lcg.c	Thu Jan  1 01:00:00 1970
+++ sys/arch/vax/vsa/lcg.c	Thu Jun 10 09:45:02 2004
@@ -0,0 +1,953 @@
+/*	$NetBSD: lcg.c,v 1.1 2004/02/12 18:24:00 Blaz Antonic Exp $ */
+/*
+ * Copyright (c) 2003, 2004 Blaz Antonic
+ *
+ * Based on bits of ragge's lcspx code (interrupt faking)
+ * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
+ * 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. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed at Ludd, University of 
+ *	Lule}, Sweden and its contributors.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/cdefs.h>
+// __KERNEL_RCSID(0, "$NetBSD: lcg.c,v 1.1 2004/02/12 18:24:00 Blaz Antonic Exp $");
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/time.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+
+#include <machine/vsbus.h>
+#include <machine/sid.h>
+#include <machine/cpu.h>
+#include <machine/lcgreg.h>
+
+#include <dev/cons.h>
+
+#include <../../qbus/dzreg.h>
+#include <../../qbus/dzvar.h>
+#include <../../dec/dzkbdvar.h>
+
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wscons_callbacks.h>
+#include <dev/wsfont/wsfont.h>
+
+#include "machine/scb.h"
+
+#include "dzkbd.h"
+
+/* Screen hardware defs */
+
+#define	LCG_FB_ADDR		0x21801000	/* Frame buffer */
+
+/* register space defines */
+#define LCG_REG_ADDR	0x20100000	/* LCG registers */
+#define LCG_REG_SIZE	0x4000		/* 16384 bytes */
+#define LCG_REG(reg) regaddr[(reg / 4)]
+
+/* LUT defines */
+#define LCG_LUT_ADDR	0x21800800	/* LUT right before onscreen FB */
+#define LCG_LUT_OFFSET	0x00000800
+#define LCG_LUT_SIZE	0x800		/* 2048 bytes */
+
+#define	LCG_BG_COLOR	WSCOL_BLACK
+#define	LCG_FG_COLOR	WSCOL_WHITE
+
+#define	LCG_CONFIG	0x200f0010	/* LCG model information */
+
+static	int lcg_match(struct device *, struct cfdata *, void *);
+static	void lcg_attach(struct device *, struct device *, void *);
+
+struct	lcg_softc {
+	struct	device ss_dev;
+};
+
+struct cfattach lcg_ca = {
+	sizeof(struct lcg_softc), (cfmatch_t)lcg_match, lcg_attach,
+};
+
+struct cfdriver lcg_cd = {
+	NULL, "lcg", DV_DULL
+};
+
+static void	lcg_cursor(void *, int, int, int);
+static int	lcg_mapchar(void *, int, unsigned int *);
+static void	lcg_putchar(void *, int, int, u_int, long);
+static void	lcg_copycols(void *, int, int, int,int);
+static void	lcg_erasecols(void *, int, int, int, long);
+static void	lcg_copyrows(void *, int, int, int);
+static void	lcg_eraserows(void *, int, int, long);
+static int	lcg_alloc_attr(void *, int, int, int, long *);
+static int	lcg_get_cmap(struct wsdisplay_cmap *);
+static int	lcg_set_cmap(struct wsdisplay_cmap *);
+static void	lcg_init_common(struct device *, struct vsbus_attach_args *);
+
+const struct wsdisplay_emulops lcg_emulops = {
+	lcg_cursor,
+	lcg_mapchar,
+	lcg_putchar,
+	lcg_copycols,
+	lcg_erasecols,
+	lcg_copyrows,
+	lcg_eraserows,
+	lcg_alloc_attr
+};
+
+const struct wsscreen_descr lcg_stdscreen = {
+	"160x68", 160, 68,		/* dynamically set */
+	&lcg_emulops,
+	8, 15,					/* dynamically set */
+	WSSCREEN_UNDERLINE|WSSCREEN_REVERSE|WSSCREEN_WSCOLORS,
+};
+
+const struct wsscreen_descr *_lcg_scrlist[] = {
+	&lcg_stdscreen,
+};
+
+const struct wsscreen_list lcg_screenlist = {
+	sizeof(_lcg_scrlist) / sizeof(struct wsscreen_descr *),
+	_lcg_scrlist,
+};
+
+static	char *lcgaddr;
+static	char *lutaddr;
+static	volatile long *regaddr;
+
+static int	lcg_xsize;
+static int	lcg_ysize;
+static int	lcg_depth;
+static int	lcg_cols;
+static int	lcg_rows;
+static int	lcg_onerow;
+static int	lcg_fb_size;
+
+/* Our current hardware colormap */
+static struct hwcmap256 {
+#define	CMAP_SIZE	256	/* 256 R/G/B entries */
+	u_int8_t r[CMAP_SIZE];
+	u_int8_t g[CMAP_SIZE];
+	u_int8_t b[CMAP_SIZE];
+} lcg_cmap;
+
+/* The default colormap */
+static struct {
+	u_int8_t r[8];
+	u_int8_t g[8];
+	u_int8_t b[8];
+} lcg_default_cmap = {
+	{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+	{ 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff },
+	{ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }
+};
+
+struct wsdisplay_font lcg_font;
+static u_char *qf;
+static u_short *qf2;
+
+#define QCHAR(c) (c < lcg_font.firstchar ? 0 : \
+	(c >= (lcg_font.firstchar + lcg_font.numchars) ? 0 : c - lcg_font.firstchar))
+#define QFONT(c,line)	((lcg_font.stride == 2 ? \
+	qf2[QCHAR(c) * lcg_font.fontheight + line] : \
+	qf[QCHAR(c) * lcg_font.fontheight + line]))
+#define	LCG_ADDR(row, col, line, dot) \
+	lcgaddr[((col) * lcg_font.fontwidth) + ((row) * lcg_font.fontheight * lcg_xsize) + \
+	    (line) * lcg_xsize + dot]
+
+
+static int	lcg_ioctl(void *, u_long, caddr_t, int, struct proc *);
+static paddr_t	lcg_mmap(void *, off_t, int);
+static int	lcg_alloc_screen(void *, const struct wsscreen_descr *,
+				      void **, int *, int *, long *);
+static void	lcg_free_screen(void *, void *);
+static int	lcg_show_screen(void *, void *, int,
+				     void (*) (void *, int, int), void *);
+static void	lcg_crsr_blink(void *);
+
+const struct wsdisplay_accessops lcg_accessops = {
+	lcg_ioctl,
+	lcg_mmap,
+	lcg_alloc_screen,
+	lcg_free_screen,
+	lcg_show_screen,
+	0 /* load_font */
+};
+
+/* XXX What to do about the size of ss_image? */
+struct	lcg_screen {
+	int	ss_curx;
+	int	ss_cury;
+	int	ss_cur_fg;
+	int	ss_cur_bg;
+	struct {
+		u_char	data;			/* Image character */
+		u_char	attr;			/* Attribute: 80/70/08/07 */
+	} ss_image[160 * 128];			/* XXXX Sized for 8x8 font FIXME? XXXX */
+};
+#define	LCG_ATTR_UNDERLINE	0x80
+#define	LCG_BG_MASK		0x70
+#define	LCG_ATTR_REVERSE	0x08
+#define	LCG_FG_MASK		0x07
+
+static	struct lcg_screen lcg_conscreen;
+static	struct lcg_screen *curscr;
+static	struct lcg_screen *savescr;
+
+static  struct timeout lcg_blink_timeout;
+
+extern int getmajor(void *);
+
+int
+lcg_match(struct device *parent, struct cfdata *match, void *aux)
+{
+	struct vsbus_softc *sc = (void *)parent;
+	struct vsbus_attach_args *va = aux;
+	char *ch = (char *)va->va_addr;
+
+	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
+		return 0;
+
+	*ch = 1;
+	if ((*ch & 1) == 0)
+		return 0;
+	*ch = 0;
+	if ((*ch & 1) != 0)
+		return 0;
+
+	/* XXX use vertical interrupt? */
+	sc->sc_mask = 0x04; /* XXX - should be generated */
+	scb_fake(0x120, 0x15);
+	return 20;
+}
+
+void
+lcg_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct vsbus_attach_args *va = aux;
+	struct wsemuldisplaydev_attach_args aa;
+
+	printf("\n");
+	aa.console = lcgaddr != NULL;
+
+	lcg_init_common(self, va);
+
+	curscr = &lcg_conscreen;
+
+	aa.scrdata = &lcg_screenlist;
+	aa.accessops = &lcg_accessops;
+
+	/* enable software cursor */
+	timeout_set(&lcg_blink_timeout, lcg_crsr_blink, NULL);
+	timeout_add(&lcg_blink_timeout, hz / 2);
+
+	config_found(self, &aa, wsemuldisplaydevprint);
+}
+
+static	char *cursor;
+
+static	int cur_on;
+
+static	int cur_fg, cur_bg;
+
+static void
+lcg_crsr_blink(void *arg)
+{
+	int dot;
+
+	if (cur_on && curscr != NULL)
+		for (dot = 0; dot < lcg_font.fontwidth; dot++)
+			cursor[dot] = ((cursor[dot] & 0x0f) == cur_fg) ? cur_bg : cur_fg;
+
+	timeout_add(&lcg_blink_timeout, hz / 2);
+}
+
+void
+lcg_cursor(void *id, int on, int row, int col)
+{
+	struct lcg_screen *ss = id;
+	int dot, attr;
+
+	attr = ss->ss_image[row * lcg_cols + col].attr;
+	if (ss == curscr) {
+		if (cursor != NULL) {
+			int ch = QFONT(ss->ss_image[ss->ss_cury * lcg_cols +
+			    ss->ss_curx].data, lcg_font.fontheight - 1);
+			int attr = ss->ss_image[ss->ss_cury * lcg_cols +
+			    ss->ss_curx].attr;
+
+			if (attr & LCG_ATTR_REVERSE) {
+				cur_bg = attr & LCG_FG_MASK;
+				cur_fg = (attr & LCG_BG_MASK) >> 4;
+			} else {
+				cur_fg = attr & LCG_FG_MASK;
+				cur_bg = (attr & LCG_BG_MASK) >> 4;
+			}
+			for (dot = 0; dot < lcg_font.fontwidth; dot++)
+				cursor[dot] =  (ch & (1 << dot)) ?
+				    cur_fg : cur_bg;
+		}
+
+		cursor = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
+		cur_on = on;
+		if (attr & LCG_ATTR_REVERSE) {
+			cur_bg = attr & LCG_FG_MASK;
+			cur_fg = (attr & LCG_BG_MASK) >> 4;
+		} else {
+			cur_fg = attr & LCG_FG_MASK;
+			cur_bg = (attr & LCG_BG_MASK) >> 4;
+		}
+	}
+	ss->ss_curx = col;
+	ss->ss_cury = row;
+	if (attr & LCG_ATTR_REVERSE) {
+		ss->ss_cur_bg = attr & LCG_FG_MASK;
+		ss->ss_cur_fg = (attr & LCG_BG_MASK) >> 4;
+	} else {
+		ss->ss_cur_fg = attr & LCG_FG_MASK;
+		ss->ss_cur_bg = (attr & LCG_BG_MASK) >> 4;
+	}
+}
+
+int
+lcg_mapchar(void *id, int uni, unsigned int *index)
+{
+	if (uni < 256) {
+		*index = uni;
+		return (5);
+	}
+	*index = ' ';
+	return (0);
+}
+
+static void
+lcg_putchar(void *id, int row, int col, u_int c, long attr)
+{
+	struct lcg_screen *ss = id;
+	int i, j;
+	char dot_fg, dot_bg;
+
+	c &= 0xff;
+
+	ss->ss_image[row * lcg_cols + col].data = c;
+	ss->ss_image[row * lcg_cols + col].attr = attr;
+	if (ss != curscr)
+		return;
+
+	dot_fg = attr & LCG_FG_MASK;
+	dot_bg = (attr & LCG_BG_MASK) >> 4;
+	if (attr & LCG_ATTR_REVERSE) {
+		dot_fg = (attr & LCG_BG_MASK) >> 4;
+		dot_bg = attr & LCG_FG_MASK;
+	}
+
+	for (i = 0; i < lcg_font.fontheight; i++) {
+		int ch = QFONT(c, i);
+		char *p = &LCG_ADDR(row, col, i, 0);
+
+		for (j = 0; j < lcg_font.fontwidth; ++j) {
+			*p++ = ch & (1 << j) ? dot_fg : dot_bg;
+		}
+	}
+	if (attr & LCG_ATTR_UNDERLINE) {
+		char *p = &LCG_ADDR(row, col, lcg_font.fontheight - 1, 0);
+		for (i = 0; i < lcg_font.fontwidth; i++)
+			p[i] = ~p[i];
+	}
+}
+
+/*
+ * copies columns inside a row.
+ */
+static void
+lcg_copycols(void *id, int row, int srccol, int dstcol, int ncols)
+{
+	struct lcg_screen *ss = id;
+	int i;
+
+	bcopy(&ss->ss_image[row * lcg_cols + srccol], &ss->ss_image[row *
+	    lcg_cols + dstcol], ncols * sizeof(ss->ss_image[0]));
+	if (ss != curscr)
+		return;
+	for (i = 0; i < lcg_font.fontheight; i++)
+		memcpy(&LCG_ADDR(row, dstcol, i, 0),
+		    &LCG_ADDR(row,srccol, i, 0), ncols * lcg_font.fontwidth);
+}
+
+/*
+ * Erases a bunch of chars inside one row.
+ */
+static void
+lcg_erasecols(void *id, int row, int startcol, int ncols, long fillattr)
+{
+	struct lcg_screen *ss = id;
+	int i;
+
+	bzero(&ss->ss_image[row * lcg_cols + startcol], ncols * sizeof(ss->ss_image[0]));
+	for (i = row * lcg_cols + startcol; i < row * lcg_cols + startcol + ncols; ++i)
+		ss->ss_image[i].attr = fillattr;
+	if (ss != curscr)
+		return;
+	for (i = 0; i < lcg_font.fontheight; i++)
+		memset(&LCG_ADDR(row, startcol, i, 0),
+		    (fillattr & LCG_BG_MASK) >> 4, ncols * lcg_font.fontwidth);
+}
+
+static void
+lcg_copyrows(void *id, int srcrow, int dstrow, int nrows)
+{
+	struct lcg_screen *ss = id;
+
+	bcopy(&ss->ss_image[srcrow * lcg_cols], &ss->ss_image[dstrow * lcg_cols],
+	    nrows * lcg_cols * sizeof(ss->ss_image[0]));
+	if (ss != curscr)
+		return;
+	memcpy(&lcgaddr[dstrow * lcg_onerow], &lcgaddr[srcrow * lcg_onerow],
+	    nrows * lcg_onerow);
+}
+
+static void
+lcg_eraserows(void *id, int startrow, int nrows, long fillattr)
+{
+	struct lcg_screen *ss = id;
+	int i;
+
+	bzero(&ss->ss_image[startrow * lcg_cols], nrows * lcg_cols *
+	    sizeof(ss->ss_image[0]));
+	for (i = startrow * lcg_cols; i < (startrow + nrows) * lcg_cols; ++i)
+		ss->ss_image[i].attr = fillattr;
+	if (ss != curscr)
+		return;
+	memset(&lcgaddr[startrow * lcg_onerow], (fillattr & LCG_BG_MASK) >> 4,
+	    nrows * lcg_onerow);
+}
+
+static int
+lcg_alloc_attr(void *id, int fg, int bg, int flags, long *attrp)
+{
+	long myattr;
+
+	if (flags & WSATTR_WSCOLORS)
+		myattr = (fg & LCG_FG_MASK) | ((bg << 4) & LCG_BG_MASK);
+	else
+		myattr = WSCOL_WHITE << 4;	/* XXXX */
+	if (flags & WSATTR_REVERSE)
+		myattr |= LCG_ATTR_REVERSE;
+	if (flags & WSATTR_UNDERLINE)
+		myattr |= LCG_ATTR_UNDERLINE;
+	*attrp = myattr;
+	return 0;
+}
+
+int
+lcg_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+	struct wsdisplay_fbinfo *fb = (void *)data;
+	int i;
+
+	switch (cmd) {
+	case WSDISPLAYIO_GTYPE:
+		*(u_int *)data = WSDISPLAY_TYPE_LCG;
+		break;
+
+	case WSDISPLAYIO_GINFO:
+		fb->height = lcg_ysize;
+		fb->width = lcg_xsize;
+		fb->depth = lcg_depth;
+		fb->cmsize = 1 << lcg_depth;
+		break;
+
+	case WSDISPLAYIO_GETCMAP:
+		return lcg_get_cmap((struct wsdisplay_cmap *)data);
+
+	case WSDISPLAYIO_PUTCMAP:
+		return lcg_set_cmap((struct wsdisplay_cmap *)data);
+
+	case WSDISPLAYIO_GMODE:
+		return ENOTTY;
+
+	case WSDISPLAYIO_SMODE:
+		/* if setting WSDISPLAYIO_MODE_EMUL, restore console cmap, current screen */
+		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) {
+			bzero(lutaddr, LCG_LUT_SIZE);
+			for (i = 0; i < 8; ++i) {
+				lcg_cmap.r[i] = lcg_default_cmap.r[i];
+				lcg_cmap.g[i] = lcg_default_cmap.g[i];
+				lcg_cmap.b[i] = lcg_default_cmap.b[i];
+				lutaddr[i * 8 + 1] = i;
+				lutaddr[i * 8 + 2] = 1;
+				lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
+				lutaddr[i * 8 + 4] = 1;
+				lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
+				lutaddr[i * 8 + 6] = 1;
+				lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
+			}
+			if (savescr != NULL)
+				lcg_show_screen(NULL, savescr, 0, NULL, NULL);
+			savescr = NULL;
+		} else {		/* WSDISPLAYIO_MODE_MAPPED */
+			savescr = curscr;
+			curscr = NULL;
+			/* clear screen? */
+		}
+
+		return ENOTTY;
+#if 0
+	case WSDISPLAYIO_SVIDEO:
+		if (*(u_int *)data == WSDISPLAYIO_VIDEO_ON) {
+			curcmd = curc;
+		} else {
+			curc = curcmd;
+			curcmd &= ~(CUR_CMD_FOPA|CUR_CMD_ENPA);
+			curcmd |= CUR_CMD_FOPB;
+		}
+		WRITECUR(CUR_CMD, curcmd);
+		break;
+
+	case WSDISPLAYIO_GVIDEO:
+		*(u_int *)data = (curcmd & CUR_CMD_FOPB ?
+		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
+		break;
+
+#endif
+	default:
+		return ENOTTY;
+	}
+	return 0;
+}
+
+static paddr_t
+lcg_mmap(void *v, off_t offset, int prot)
+{
+	if (offset >= lcg_fb_size || offset < 0)
+		return -1;
+	return (LCG_FB_ADDR + offset) >> PGSHIFT;
+}
+
+int
+lcg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+    int *curxp, int *curyp, long *defattrp)
+{
+	int i;
+	struct lcg_screen *ss;
+
+	*cookiep = malloc(sizeof(struct lcg_screen), M_DEVBUF, M_WAITOK);
+	bzero(*cookiep, sizeof(struct lcg_screen));
+	*curxp = *curyp = 0;
+	*defattrp = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
+	ss = *cookiep;
+	for (i = 0; i < lcg_cols * lcg_rows; ++i)
+		ss->ss_image[i].attr = (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
+	return 0;
+}
+
+void
+lcg_free_screen(void *v, void *cookie)
+{
+}
+
+int
+lcg_show_screen(void *v, void *cookie, int waitok,
+    void (*cb)(void *, int, int), void *cbarg)
+{
+	struct lcg_screen *ss = cookie;
+	int row, col, line, dot_fg, dot_bg, j, attr;
+	char *p;
+
+	if (ss == curscr)
+		return (0);
+
+	for (row = 0; row < lcg_rows; row++)
+		for (col = 0; col < lcg_cols; col++) {
+			attr = ss->ss_image[row * lcg_cols + col].attr;
+			if (attr & LCG_ATTR_REVERSE) {
+				dot_fg = (attr & LCG_BG_MASK) >> 4;
+				dot_bg = attr & LCG_FG_MASK;
+			} else {
+				dot_fg = attr & LCG_FG_MASK;
+				dot_bg = (attr & LCG_BG_MASK) >> 4;
+			}
+			for (line = 0; line < lcg_font.fontheight; line++) {
+				u_char c = ss->ss_image[row * lcg_cols + col].data;
+				int s;
+
+				if (c < 32)
+					c = 32;
+				s = QFONT(c, line);
+
+				p = &LCG_ADDR(row, col, line, 0);
+				for (j = 0; j < lcg_font.fontwidth; ++j)
+					*p++ = s & (1 << j) ? dot_fg : dot_bg;
+			}
+			if (attr & LCG_ATTR_UNDERLINE)
+				for (j = 0; j < lcg_font.fontwidth; j++)
+					LCG_ADDR(row, col,
+					    lcg_font.fontheight - 1, j) = dot_fg;
+		}
+
+	cursor = &lcgaddr[(ss->ss_cury * lcg_onerow) + 
+		((lcg_font.fontheight - 1) * lcg_xsize) +
+			(ss->ss_curx * lcg_font.fontwidth)];
+	cur_fg = ss->ss_cur_fg;
+	cur_bg = ss->ss_cur_bg;
+
+	curscr = ss;
+	return (0);
+}
+
+static int
+lcg_get_cmap(p)
+	struct wsdisplay_cmap *p;
+{
+	u_int index = p->index, count = p->count;
+	int error;
+
+	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
+		return (EINVAL);
+
+	error = copyout(&lcg_cmap.r[index], p->red, count);
+	if (error)
+		return error;
+	error = copyout(&lcg_cmap.g[index], p->green, count);
+	if (error)
+		return error;
+	error = copyout(&lcg_cmap.b[index], p->blue, count);
+	return error;
+}
+
+static int
+lcg_set_cmap(p)
+	struct wsdisplay_cmap *p;
+{
+	u_int index = p->index, count = p->count;
+	int error, s;
+
+	if (index >= (1 << lcg_depth) || count > (1 << lcg_depth) - index)
+		return (EINVAL);
+
+	error = copyin(p->red, &lcg_cmap.r[index], count);
+	if (error)
+		return error;
+	error = copyin(p->green, &lcg_cmap.g[index], count);
+	if (error)
+		return error;
+	error = copyin(p->blue, &lcg_cmap.b[index], count);
+	if (error)
+		return error;
+
+	s = spltty();
+	while (count-- > 0) {
+		lutaddr[index * 8 + 0] = 0;
+		lutaddr[index * 8 + 1] = index;
+		lutaddr[index * 8 + 2] = 1;
+		lutaddr[index * 8 + 3] = lcg_cmap.r[index] >> (lcg_depth & 7);
+		lutaddr[index * 8 + 4] = 1;
+		lutaddr[index * 8 + 5] = lcg_cmap.g[index] >> (lcg_depth & 7);
+		lutaddr[index * 8 + 6] = 1;
+		lutaddr[index * 8 + 7] = lcg_cmap.b[index] >> (lcg_depth & 7);
+		++index;
+	}
+	splx(s);
+	return (0);
+}
+
+cons_decl(lcg);
+
+void
+lcgcninit(struct consdev *cndev)
+{
+	int i;
+	/* Clear screen */
+	memset(lcgaddr, LCG_BG_COLOR, lcg_xsize * lcg_ysize);
+
+	curscr = &lcg_conscreen;
+	for (i = 0; i < lcg_cols * lcg_rows; ++i)
+		lcg_conscreen.ss_image[i].attr =
+		    (LCG_BG_COLOR << 4) | LCG_FG_COLOR;
+	wsdisplay_cnattach(&lcg_stdscreen, &lcg_conscreen, 0, 0,
+	    (LCG_BG_COLOR << 4) | LCG_FG_COLOR);
+	cn_tab->cn_pri = CN_INTERNAL;
+
+#if NDZKBD > 0
+	dzkbd_cnattach(0); /* Connect keyboard and screen together */
+#endif
+}
+
+/*
+ * Called very early to setup the glass tty as console.
+ * Because it's called before the VM system is inited, virtual memory
+ * for the framebuffer can be stolen directly without disturbing anything.
+ */
+void
+lcgcnprobe(struct consdev *cndev)
+{
+	if ((vax_boardtype != VAX_BTYP_46) && (vax_boardtype != VAX_BTYP_48))
+		return; /* Only for VS 4000/60 and VLC */
+
+	if (vax_confdata & 0x100)
+		return; /* Diagnostic console */
+
+	lcg_init_common(NULL, NULL);
+
+	/* Set up default LUT */
+
+	cndev->cn_pri = CN_INTERNAL;
+	cndev->cn_dev = makedev(getmajor(wsdisplayopen), 0);
+}
+
+void
+lcg_init_common(struct device *self, struct vsbus_attach_args *va)
+{
+	u_int magic, *lcg_config;
+	int i;
+	extern vaddr_t virtual_avail;
+	long video_conf;
+	int cookie;
+	struct wsdisplay_font *wf;
+
+	if (regaddr != NULL)
+		return;
+
+	/* map LCG registers first */
+	if (self != NULL) {
+		regaddr = (long*)vax_map_physmem(LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
+		if (regaddr == 0) {
+			printf("%s: Couldn't allocate register memory.\n", self->dv_xname);
+			return;
+		}
+	} else {
+		regaddr = (long*)virtual_avail;
+		virtual_avail += LCG_REG_SIZE;
+		ioaccess((vaddr_t)regaddr, LCG_REG_ADDR, (LCG_REG_SIZE/VAX_NBPG));
+	}
+
+	/*
+	 * v = *0x200f0010 & VLC ? 0x07 : 0xf0;
+	 * switch(v) {
+	 * 0x05: 1280x1024
+	 * 0x06: conf & 0x80 ? 1024x768 : 640x480
+	 * 0x07: conf & 0x80 ? 1024x768 ? 1024x864
+	 * 0x20: 1024x864
+	 * 0x40: 1024x768
+	 * 0x60: 1024x864
+	 * 0x80: 1280x1024 4BPN
+	 * 0x90: 1280x1024 8BPN
+	 * 0xb0: 1280x1024 8BPN 2HD
+	 */
+	if (self != NULL) {
+		lcg_config = (u_int *)vax_map_physmem(LCG_CONFIG, 1);
+	} else {
+		lcg_config = (u_int *)virtual_avail;
+		ioaccess((vaddr_t)lcg_config, LCG_CONFIG, 1);
+	}
+	magic = *lcg_config & (vax_boardtype == VAX_BTYP_46 ? 0xf0 : 0x07);
+	if (self != NULL) {
+		vax_unmap_physmem((vaddr_t)lcg_config, 1);
+	} else {
+		iounaccess((vaddr_t)lcg_config, 1);
+	}
+	lcg_depth = 8;
+	switch(magic) {
+	case 0x80:		/* KA46 HR 1280x1024 4BPLN */
+		lcg_depth = 4;
+	case 0x05:		/* KA48 HR 1280x1024 8BPLN */
+	case 0x90:		/* KA46 HR 1280x1024 8BPLN */
+	case 0xb0:		/* KA46 HR 1280x1024 8BPLN 2HD */
+		lcg_xsize = 1280;
+		lcg_ysize = 1024;
+		break;
+	case 0x06:		/* KA48 1024x768 or 640x480 */
+		if (vax_confdata & 0x80) {
+			lcg_xsize = 1024;
+			lcg_ysize = 768;
+		} else {
+			lcg_xsize = 640;
+			lcg_ysize = 480;
+		}
+		break;
+	case 0x07:		/* KA48 1024x768 or 1024x864 */
+		lcg_xsize = 1024;
+		lcg_ysize = (vax_confdata & 0x80) ? 768 : 864;
+		break;
+	case 0x20:		/* KA46 1024x864 */
+	case 0x60:		/* KA46 1024x864 */
+		lcg_xsize = 1024;
+		lcg_ysize = 864;
+		break;
+	case 0x40:		/* KA46 1024x768 */
+		lcg_xsize = 1024;
+		lcg_ysize = 768;
+		break;
+	default:
+		panic("LCG model not supported");
+	}
+
+	wsfont_init();
+	cookie = wsfont_find(NULL, 12, 22, 0);
+	if (cookie == -1)
+		cookie = wsfont_find(NULL, 8, 0, 0);
+	if (cookie == -1)
+		cookie = wsfont_find(NULL, 0, 0, 0);
+	if (cookie == -1 || wsfont_lock(cookie, &wf, WSDISPLAY_FONTORDER_L2R,
+			WSDISPLAY_FONTORDER_R2L))
+		panic("lcg_common_init: can't load console font");
+	lcg_font = *wf;
+	if (self != NULL) {
+		printf("lcg0: Using font %s\n", wf->name);
+	}
+	lcg_cols = lcg_xsize / lcg_font.fontwidth;
+	lcg_rows = lcg_ysize / lcg_font.fontheight;
+	lcg_onerow = lcg_xsize * lcg_font.fontheight;
+	lcg_fb_size = lcg_xsize * lcg_ysize;
+/*	lcg_stdscreen.ncols = lcg_cols;
+	lcg_stdscreen.nrows = lcg_rows;
+	lcg_stdscreen.fontwidth = lcg_font.fontwidth;
+	lcg_stdscreen.fontheight = lcg_font.fontheight; */
+	sprintf("160x68", "%dx%d", lcg_cols, lcg_rows);
+	qf = lcg_font.data;
+	qf2 = (u_short *)lcg_font.data;
+
+	if (self != NULL) {
+		lcgaddr = (caddr_t)vax_map_physmem(va->va_paddr, (lcg_fb_size/VAX_NBPG));
+		if (lcgaddr == 0) {
+			printf("%s: Couldn't allocate graphics memory.\n", self->dv_xname);
+			return;
+		}
+		lutaddr = (caddr_t)vax_map_physmem(LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
+		if (lutaddr == 0) {
+			printf("%s: Couldn't allocate LUT memory.\n", self->dv_xname);
+			return;
+		}
+	} else {
+		lcgaddr = (caddr_t)virtual_avail;
+		virtual_avail += lcg_fb_size;
+		ioaccess((vaddr_t)lcgaddr, LCG_FB_ADDR, (lcg_fb_size/VAX_NBPG));
+
+		lutaddr = (caddr_t)virtual_avail;
+		virtual_avail += LCG_LUT_SIZE;
+		ioaccess((vaddr_t)lutaddr, LCG_LUT_ADDR, (LCG_LUT_SIZE/VAX_NBPG));
+	}
+
+	bzero(lutaddr, LCG_LUT_SIZE);
+	for (i = 0; i < 8; ++i) {
+		lcg_cmap.r[i] = lcg_default_cmap.r[i];
+		lcg_cmap.g[i] = lcg_default_cmap.g[i];
+		lcg_cmap.b[i] = lcg_default_cmap.b[i];
+		lutaddr[i * 8 + 1] = i;
+		lutaddr[i * 8 + 2] = 1;
+		lutaddr[i * 8 + 3] = lcg_cmap.r[i] >> (lcg_depth & 7);
+		lutaddr[i * 8 + 4] = 1;
+		lutaddr[i * 8 + 5] = lcg_cmap.g[i] >> (lcg_depth & 7);
+		lutaddr[i * 8 + 6] = 1;
+		lutaddr[i * 8 + 7] = lcg_cmap.b[i] >> (lcg_depth & 7);
+	}
+
+	/* XXX Use existing video_config register setting? */
+	/*
+	 * 0xf100165b 4000/60
+	 * 1111 0001 0000 0000 0001 0110 0101 1011
+	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
+	 * 3322 2222 2222 1111 1111 11
+	 * 1098 7654 3210 9876 5432 1098 7654 3210
+	 *
+ 	 * 0xf1001d7b 4000/VLC
+	 * 1111 0001 0000 0000 0001 1101 0111 1011
+	 * vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
+	 * 3322 2222 2222 1111 1111 11
+	 * 1098 7654 3210 9876 5432 1098 7654 3210
+	 *
+	 * 31-30     11 Vertical state
+	 * 29-38     11 Horizontal state
+	 * 27-26     00
+	 * 25         0 console LUT select
+	 * 24         1 control LUT select
+	 * 23         0
+	 * 22         0 cursor active
+	 * 21-16 000000
+	 * 15         0 video subsystem reset
+	 * 14         0
+	 * 13         0 LUT load size 2KB
+	 * 12         1 enable H sync
+	 * 11         0 Full LUT load		 1
+	 * 10         1 video clock select
+	 *  9- 8     10 memory refresh rate	01
+	 *  7- 6     01 video refresh rate
+	 *  5         0 load select		 1
+	 *  4         1 read cursor output
+	 *  3         1 LUT load enable
+	 *  2         0 cursor enable
+	 *  1         1 video enable
+	 *  0         1 refresh clock enable
+	 */
+	/* prepare video_config reg for LUT relaod */
+	video_conf
+		 = (3 << 30) /* vertical state */
+		 | (3 << 28) /* horizontal state */
+		 | (0 << 26) /* unused */
+		 | (0 << 25) /* console LUT select */
+		 | (0 << 24) /* control LUT select */
+		 | (0 << 23) /* unused */
+		 | (0 << 22) /* cursor active */
+		 | (0 << 16) /* current cursor scanline showing */
+		 | (0 << 15) /* video subsystem reset */
+		 | (0 << 14) /* unused */
+		 | (1 << 13) /* LUT load size 2 KB */
+		 | (1 << 12) /* enable horizontal sync */
+		 | (1 << 10) /* video clock select */
+		 | (1 << 6) /* video refresh select */
+		 | (1 << 4) /* read curosr output */
+		 | (1 << 3) /* LUT load enable */
+		 | (0 << 2) /* cursor enable */
+		 | (1 << 1) /* video enable */
+		 | (1 << 0); /* refresh clock enable */
+	if (lcg_xsize == 1280) {		/* 4000/60 HR 4PLN */
+		video_conf |= (0 << 11); /* split LUT load */
+		video_conf |= (2 << 8); /* memory refresh select */
+		video_conf |= (0 << 5); /* split shift register load */
+	} else {				/* 4000/VLC LR 8PLN */
+		video_conf |= (1 << 11); /* Full LUT load */
+		video_conf |= (1 << 8); /* memory refresh select */
+		video_conf |= (1 << 5); /* split shift register load */
+	}
+
+	LCG_REG(LCG_REG_VIDEO_CONFIG) = video_conf;
+
+	/* vital !!! */
+	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 1;
+
+	LCG_REG(LCG_REG_LUT_COLOR_BASE_W) = LCG_LUT_OFFSET;
+
+	delay(1000);
+
+	LCG_REG(LCG_REG_LUT_CONSOLE_SEL) = 0;
+
+	if (self != NULL)
+		printf("lcg: video config register set 0x%08lx\n", video_conf);
+}
making sure the compat library is up to date...
`libcompat.a' is up to date.
mkdir -p /usr/src/sys/arch/vax/compile/zsebivax/lib/kern
making sure the kern library is up to date...
`libkern.o' is up to date.
sh /usr/src/sys/arch/vax/compile/zsebivax/../../../../conf/newvers.sh
cc  -O2 -Werror -Wall -Wmissing-prototypes -Wstrict-prototypes  -Wno-main -Wno-format -Wno-uninitialized -fno-builtin-printf -fno-builtin-log  -I. -I/usr/src/sys/arch/vax/compile/zsebivax/../../../../arch -I/usr/src/sys/arch/vax/compile/zsebivax/../../../.. -nostdinc -DDDB -DDIAGNOSTIC -DKTRACE -DKMEMSTATS -DPTRACE -DCRYPTO -DSYSVMSG -DSYSVSEM -DSYSVSHM -DUVM_SWAP_ENCRYPT -DCOMPAT_43 -DLKM -DFFS -DFFS_SOFTUPDATES -DUFS_DIRHASH -DQUOTA -DEXT2FS -DMFS -DXFS -DTCP_SACK -DTCP_ECN -DTCP_SIGNATURE -DNFSCLIENT -DNFSSERVER -DCD9660 -DMSDOSFS -DFDESC -DFIFO -DKERNFS -DPORTAL -DPROCFS -DNULLFS -DUMAPFS -DUNION -DINET -DALTQ -DINET6 -DIPSEC -DPPP_BSDCOMP -DPPP_DEFLATE -DBOOT_CONFIG -DVAX48 -DSCSIVERBOSE -DCOMPAT_VAX1K -DINSN_EMULATE -DMAXUSERS=8 -D_KERNEL  -D_VAX_INLINE_  -c vers.c
ld -N -Ttext 80000000 -e start -S -o bsd ${SYSTEM_OBJ} vers.o
lcg.o: Undefined symbol `_wsfont_init' referenced from text segment
lcg.o: Undefined symbol `_wsfont_find' referenced from text segment
lcg.o: Undefined symbol `_wsfont_lock' referenced from text segment
lcg.o: Undefined symbol `_sprintf' referenced from text segment
ka48.o: Undefined symbol `_clk_adrshift' referenced from text segment
ka48.o: Undefined symbol `_clk_tweak' referenced from text segment
ka48.o: Undefined symbol `_clk_page' referenced from text segment
ka48.o: Undefined symbol `_clk_page' referenced from text segment
ka48.o: Undefined symbol `_clk_page' referenced from text segment
ka48.o: Undefined symbol `_chip_clkread' referenced from data segment
ka48.o: Undefined symbol `_chip_clkwrite' referenced from data segment
*** Error code 1

Stop in /usr/src/sys/arch/vax/compile/zsebivax (line 377 of Makefile).