Home | History | Annotate | Line # | Download | only in vsa
smg.c revision 1.61.6.4
      1 /*	$NetBSD: smg.c,v 1.61.6.4 2024/02/03 12:56:02 martin Exp $ */
      2 /*	$OpenBSD: smg.c,v 1.28 2014/12/23 21:39:12 miod Exp $	*/
      3 /*
      4  * Copyright (c) 2006, Miodrag Vallat
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25  * POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 /*-
     28  * Copyright (c) 2000 The NetBSD Foundation, Inc.
     29  * All rights reserved.
     30  *
     31  * This code is derived from software contributed to The NetBSD Foundation
     32  * by Tohru Nishimura.
     33  *
     34  * Redistribution and use in source and binary forms, with or without
     35  * modification, are permitted provided that the following conditions
     36  * are met:
     37  * 1. Redistributions of source code must retain the above copyright
     38  *    notice, this list of conditions and the following disclaimer.
     39  * 2. Redistributions in binary form must reproduce the above copyright
     40  *    notice, this list of conditions and the following disclaimer in the
     41  *    documentation and/or other materials provided with the distribution.
     42  *
     43  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     44  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     45  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     46  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     47  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     48  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     49  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     50  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     51  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     52  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     53  * POSSIBILITY OF SUCH DAMAGE.
     54  */
     55 /*
     56  * Copyright (c) 1998 Ludd, University of Lule}, Sweden.
     57  * All rights reserved.
     58  *
     59  * Redistribution and use in source and binary forms, with or without
     60  * modification, are permitted provided that the following conditions
     61  * are met:
     62  * 1. Redistributions of source code must retain the above copyright
     63  *    notice, this list of conditions and the following disclaimer.
     64  * 2. Redistributions in binary form must reproduce the above copyright
     65  *    notice, this list of conditions and the following disclaimer in the
     66  *    documentation and/or other materials provided with the distribution.
     67  *
     68  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     69  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     70  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     71  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     72  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     73  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     74  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     75  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     76  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     77  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     78  */
     79 /*
     80  * Copyright (c) 1996 Jason R. Thorpe.  All rights reserved.
     81  * Copyright (c) 1991 University of Utah.
     82  * Copyright (c) 1990, 1993
     83  *	The Regents of the University of California.  All rights reserved.
     84  *
     85  * This code is derived from software contributed to Berkeley by
     86  * the Systems Programming Group of the University of Utah Computer
     87  * Science Department and Mark Davies of the Department of Computer
     88  * Science, Victoria University of Wellington, New Zealand.
     89  *
     90  * Redistribution and use in source and binary forms, with or without
     91  * modification, are permitted provided that the following conditions
     92  * are met:
     93  * 1. Redistributions of source code must retain the above copyright
     94  *    notice, this list of conditions and the following disclaimer.
     95  * 2. Redistributions in binary form must reproduce the above copyright
     96  *    notice, this list of conditions and the following disclaimer in the
     97  *    documentation and/or other materials provided with the distribution.
     98  * 3. Neither the name of the University nor the names of its contributors
     99  *    may be used to endorse or promote products derived from this software
    100  *    without specific prior written permission.
    101  *
    102  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
    103  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    104  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    105  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
    106  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    107  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    108  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    109  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    110  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    111  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    112  * SUCH DAMAGE.
    113  *
    114  * from: Utah $Hdr: grf_hy.c 1.2 93/08/13$
    115  *
    116  *	@(#)grf_hy.c	8.4 (Berkeley) 1/12/94
    117  */
    118 
    119 #include <sys/cdefs.h>
    120 __KERNEL_RCSID(0, "$NetBSD: smg.c,v 1.61.6.4 2024/02/03 12:56:02 martin Exp $");
    121 
    122 #include "dzkbd.h"
    123 #include "wsdisplay.h"
    124 
    125 #include <sys/param.h>
    126 #include <sys/device.h>
    127 #include <sys/systm.h>
    128 #include <sys/kmem.h>
    129 #include <sys/conf.h>
    130 
    131 #include <machine/vsbus.h>
    132 #include <machine/sid.h>
    133 #include <machine/cpu.h>
    134 #include <machine/ka420.h>
    135 #include <machine/scb.h>
    136 
    137 #include <dev/cons.h>
    138 
    139 #include <dev/ic/dc503reg.h>
    140 
    141 #include <dev/dec/dzreg.h>
    142 #include <dev/dec/dzvar.h>
    143 #include <dev/dec/dzkbdvar.h>
    144 
    145 #include <dev/wscons/wsconsio.h>
    146 #include <dev/wscons/wsdisplayvar.h>
    147 #include <dev/rasops/rasops.h>
    148 
    149 /* Screen hardware defs */
    150 #define SM_XWIDTH	1024
    151 #define SM_YWIDTH	864
    152 
    153 #define CUR_XBIAS	216	/* Add to cursor position */
    154 #define CUR_YBIAS	33
    155 
    156 static int	smg_match(device_t, cfdata_t, void *);
    157 static void	smg_attach(device_t, device_t, void *);
    158 
    159 struct	smg_screen {
    160 	struct rasops_info ss_ri;
    161 	uint8_t		*ss_addr;		/* frame buffer address */
    162 	struct dc503reg	*ss_cursor;		/* cursor registers */
    163 	uint16_t	ss_curcmd;
    164 	struct wsdisplay_curpos ss_curpos, ss_curhot;
    165 	uint16_t	ss_curimg[PCC_CURSOR_SIZE];
    166 	uint16_t	ss_curmask[PCC_CURSOR_SIZE];
    167 };
    168 
    169 /* for console */
    170 static struct smg_screen smg_consscr;
    171 
    172 struct	smg_softc {
    173 	device_t sc_dev;
    174 	struct smg_screen *sc_scr;
    175 	int	sc_nscreens;
    176 };
    177 
    178 CFATTACH_DECL_NEW(smg, sizeof(struct smg_softc),
    179     smg_match, smg_attach, NULL, NULL);
    180 
    181 static struct wsscreen_descr smg_stdscreen = {
    182 	.name = "std",
    183 };
    184 
    185 static const struct wsscreen_descr *_smg_scrlist[] = {
    186 	&smg_stdscreen,
    187 };
    188 
    189 static const struct wsscreen_list smg_screenlist = {
    190 	.nscreens = sizeof(_smg_scrlist) / sizeof(struct wsscreen_descr *),
    191 	.screens = _smg_scrlist,
    192 };
    193 
    194 static int smg_ioctl(void *, void *, u_long, void *, int, struct lwp *);
    195 static paddr_t smg_mmap(void *, void *, off_t, int);
    196 static int smg_alloc_screen(void *, const struct wsscreen_descr *,
    197     void **, int *, int *, long *);
    198 static void smg_free_screen(void *, void *);
    199 static int smg_show_screen(void *, void *, int, void (*) (void *, int, int),
    200     void *);
    201 
    202 static const struct wsdisplay_accessops smg_accessops = {
    203 	.ioctl = smg_ioctl,
    204 	.mmap = smg_mmap,
    205 	.alloc_screen = smg_alloc_screen,
    206 	.free_screen = smg_free_screen,
    207 	.show_screen = smg_show_screen,
    208 	.load_font = NULL
    209 };
    210 
    211 static void smg_putchar(void *, int, int, u_int, long);
    212 static void smg_cursor(void *, int, int, int);
    213 static void smg_blockmove(struct rasops_info *, u_int, u_int, u_int, u_int,
    214     u_int, int);
    215 static void smg_copycols(void *, int, int, int, int);
    216 static void smg_erasecols(void *, int, int, int, long);
    217 
    218 static int smg_getcursor(struct smg_screen *, struct wsdisplay_cursor *);
    219 static int smg_setup_screen(struct smg_screen *);
    220 static int smg_setcursor(struct smg_screen *, struct wsdisplay_cursor *);
    221 static void smg_updatecursor(struct smg_screen *, u_int);
    222 
    223 static int
    224 smg_match(device_t parent, cfdata_t cf, void *aux)
    225 {
    226 	struct vsbus_attach_args *va = aux;
    227 	volatile short *curcmd;
    228 	volatile short *cfgtst;
    229 	short tmp, tmp2;
    230 
    231 	switch (vax_boardtype) {
    232 	default:
    233 		return 0;
    234 
    235 	case VAX_BTYP_410:
    236 	case VAX_BTYP_420:
    237 	case VAX_BTYP_43:
    238 		if (va->va_paddr != KA420_CUR_BASE)
    239 			return 0;
    240 
    241 		/* not present on microvaxes */
    242 		if ((vax_confdata & KA420_CFG_MULTU) != 0)
    243 			return 0;
    244 
    245 		/*
    246 		 * If the color option board is present, do not attach
    247 		 * unless we are explicitely asked to via device flags.
    248 		 */
    249 		if ((vax_confdata & KA420_CFG_VIDOPT) != 0 &&
    250 		    (cf->cf_flags & 1) == 0)
    251 			return 0;
    252 		break;
    253 	}
    254 
    255 	/* when already running as console, always fake things */
    256 	if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0
    257 #if NWSDISPLAY > 0
    258 	    && cn_tab->cn_putc == wsdisplay_cnputc
    259 #endif
    260 	) {
    261 		struct vsbus_softc *sc = device_private(parent);
    262 
    263 		sc->sc_mask = 0x08;
    264 		scb_fake(0x44, 0x15);
    265 		return 20;
    266 	} else {
    267 		/*
    268 		 * Try to find the cursor chip by testing the flip-flop.
    269 		 * If nonexistent, no glass tty.
    270 		 */
    271 		curcmd = (short *)va->va_addr;
    272 		cfgtst = (short *)vax_map_physmem(VS_CFGTST, 1);
    273 		curcmd[0] = PCCCMD_HSHI | PCCCMD_FOPB;
    274 		DELAY(300000);
    275 		tmp = cfgtst[0];
    276 		curcmd[0] = PCCCMD_TEST | PCCCMD_HSHI;
    277 		DELAY(300000);
    278 		tmp2 = cfgtst[0];
    279 		vax_unmap_physmem((vaddr_t)cfgtst, 1);
    280 
    281 		if (tmp2 != tmp)
    282 			return 20; /* Using periodic interrupt */
    283 		else
    284 			return 0;
    285 	}
    286 }
    287 
    288 static void
    289 smg_attach(device_t parent, device_t self, void *aux)
    290 {
    291 	struct smg_softc *sc = device_private(self);
    292 	struct smg_screen *scr;
    293 	struct wsemuldisplaydev_attach_args aa;
    294 	int console;
    295 
    296 	console =
    297 #if NWSDISPLAY > 0
    298 	    (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0 &&
    299 	    cn_tab->cn_putc == wsdisplay_cnputc;
    300 #else
    301 	    (vax_confdata & (KA420_CFG_L3CON | KA420_CFG_VIDOPT)) == 0;
    302 #endif
    303 	if (console) {
    304 		scr = &smg_consscr;
    305 		sc->sc_nscreens = 1;
    306 	} else {
    307 		scr = kmem_zalloc(sizeof(*scr), KM_SLEEP);
    308 
    309 		scr->ss_addr =
    310 		    (void *)vax_map_physmem(SMADDR, SMSIZE / VAX_NBPG);
    311 		if (scr->ss_addr == NULL) {
    312 			aprint_error(": can not map frame buffer\n");
    313 			kmem_free(scr, sizeof(*scr));
    314 			return;
    315 		}
    316 
    317 		scr->ss_cursor =
    318 		    (struct dc503reg *)vax_map_physmem(KA420_CUR_BASE, 1);
    319 		if (scr->ss_cursor == NULL) {
    320 			aprint_error(": can not map cursor chip\n");
    321 			vax_unmap_physmem((vaddr_t)scr->ss_addr,
    322 			    SMSIZE / VAX_NBPG);
    323 			kmem_free(scr, sizeof(*scr));
    324 			return;
    325 		}
    326 
    327 		if (smg_setup_screen(scr) != 0) {
    328 			aprint_error(": initialization failed\n");
    329 			vax_unmap_physmem((vaddr_t)scr->ss_cursor, 1);
    330 			vax_unmap_physmem((vaddr_t)scr->ss_addr,
    331 			    SMSIZE / VAX_NBPG);
    332 			kmem_free(scr, sizeof(*scr));
    333 			return;
    334 		}
    335 	}
    336 	sc->sc_scr = scr;
    337 
    338 	aprint_normal("\n");
    339 	aprint_normal_dev(self, "%dx%d on-board monochrome framebuffer\n",
    340 	    SM_XWIDTH, SM_YWIDTH);
    341 
    342 	aa.console = console;
    343 	aa.scrdata = &smg_screenlist;
    344 	aa.accessops = &smg_accessops;
    345 	aa.accesscookie = sc;
    346 
    347 	config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE);
    348 }
    349 
    350 /*
    351  * Initialize anything necessary for an emulating wsdisplay to work (i.e.
    352  * pick a font, initialize a rasops structure, setup the accessops callbacks.)
    353  */
    354 static int
    355 smg_setup_screen(struct smg_screen *ss)
    356 {
    357 	struct rasops_info *ri = &ss->ss_ri;
    358 	int cookie;
    359 
    360 	memset(ri, 0, sizeof(*ri));
    361 	ri->ri_depth = 1;
    362 	ri->ri_width = SM_XWIDTH;
    363 	ri->ri_height = SM_YWIDTH;
    364 	ri->ri_stride = SM_XWIDTH >> 3;
    365 	ri->ri_flg = RI_CLEAR | RI_CENTER;
    366 	ri->ri_bits = (void *)ss->ss_addr;
    367 	ri->ri_hw = ss;
    368 	if (ss == &smg_consscr)
    369 		ri->ri_flg |= RI_NO_AUTO;
    370 
    371 	wsfont_init();
    372 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_R2L,
    373 	    WSDISPLAY_FONTORDER_R2L, WSFONT_FIND_BITMAP);
    374 	if (cookie < 0)
    375 		cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L,
    376 		    WSDISPLAY_FONTORDER_R2L, WSFONT_FIND_BITMAP);
    377 	if (cookie < 0)
    378 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L,
    379 		    WSDISPLAY_FONTORDER_R2L, WSFONT_FIND_BITMAP);
    380 	if (cookie < 0)
    381 		return -1;
    382 	if (wsfont_lock(cookie, &ri->ri_font) != 0)
    383 		return -1;
    384 	ri->ri_wsfcookie = cookie;
    385 
    386 	/*
    387 	 * Ask for an unholy big display, rasops will trim this to more
    388 	 * reasonable values.
    389 	 */
    390 	if (rasops_init(ri, 160, 160) != 0)
    391 		return -1;
    392 
    393 	ri->ri_ops.cursor = smg_cursor;
    394 	ri->ri_ops.putchar = smg_putchar;
    395 	ri->ri_ops.copycols = smg_copycols;
    396 	ri->ri_ops.erasecols = smg_erasecols;
    397 
    398 	smg_stdscreen.ncols = ri->ri_cols;
    399 	smg_stdscreen.nrows = ri->ri_rows;
    400 	smg_stdscreen.textops = &ri->ri_ops;
    401 	smg_stdscreen.fontwidth = ri->ri_font->fontwidth;
    402 	smg_stdscreen.fontheight = ri->ri_font->fontheight;
    403 	smg_stdscreen.capabilities = ri->ri_caps;
    404 
    405 	ss->ss_curcmd = PCCCMD_HSHI;
    406 	ss->ss_cursor->cmdr = ss->ss_curcmd;
    407 
    408 	return 0;
    409 }
    410 
    411 static int
    412 smg_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
    413 {
    414 	struct smg_softc *sc = v;
    415 	struct smg_screen *ss = sc->sc_scr;
    416 	struct wsdisplay_fbinfo *wdf;
    417 	struct wsdisplay_curpos *pos;
    418 
    419 	switch (cmd) {
    420 	case WSDISPLAYIO_GTYPE:
    421 		*(u_int *)data = WSDISPLAY_TYPE_VAX_MONO;
    422 		break;
    423 
    424 	case WSDISPLAYIO_GINFO:
    425 		wdf = (struct wsdisplay_fbinfo *)data;
    426 		wdf->height = ss->ss_ri.ri_height;
    427 		wdf->width = ss->ss_ri.ri_width;
    428 		wdf->depth = ss->ss_ri.ri_depth;
    429 		wdf->cmsize = 0;
    430 		break;
    431 
    432 	case WSDISPLAYIO_LINEBYTES:
    433 		*(u_int *)data = ss->ss_ri.ri_stride;
    434 		break;
    435 
    436 	case WSDISPLAYIO_GETCMAP:
    437 	case WSDISPLAYIO_PUTCMAP:
    438 	case WSDISPLAYIO_GVIDEO:
    439 	case WSDISPLAYIO_SVIDEO:
    440 		break;
    441 
    442 	case WSDISPLAYIO_GCURPOS:
    443 		pos = (struct wsdisplay_curpos *)data;
    444 		pos->x = ss->ss_curpos.x;
    445 		pos->y = ss->ss_curpos.y;
    446 		break;
    447 
    448 	case WSDISPLAYIO_SCURPOS:
    449 		pos = (struct wsdisplay_curpos *)data;
    450 		ss->ss_curpos.x = pos->x;
    451 		ss->ss_curpos.y = pos->y;
    452 		smg_updatecursor(ss, WSDISPLAY_CURSOR_DOPOS);
    453 		break;
    454 
    455 	case WSDISPLAYIO_GCURMAX:
    456 		pos = (struct wsdisplay_curpos *)data;
    457 		pos->x = pos->y = PCC_CURSOR_SIZE;
    458 
    459 	case WSDISPLAYIO_GCURSOR:
    460 		return smg_getcursor(ss, (struct wsdisplay_cursor *)data);
    461 
    462 	case WSDISPLAYIO_SCURSOR:
    463 		return smg_setcursor(ss, (struct wsdisplay_cursor *)data);
    464 
    465 	default:
    466 		return EPASSTHROUGH;
    467 	}
    468 	return 0;
    469 }
    470 
    471 static paddr_t
    472 smg_mmap(void *v, void *vs, off_t offset, int prot)
    473 {
    474 
    475 	if (offset >= SMSIZE || offset < 0)
    476 		return -1;
    477 
    478 	return (SMADDR + offset) >> PGSHIFT;
    479 }
    480 
    481 static int
    482 smg_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
    483     int *curxp, int *curyp, long *defattrp)
    484 {
    485 	struct smg_softc *sc = v;
    486 	struct smg_screen *ss = sc->sc_scr;
    487 	struct rasops_info *ri = &ss->ss_ri;
    488 
    489 	if (sc->sc_nscreens > 0)
    490 		return ENOMEM;
    491 
    492 	*cookiep = ri;
    493 	*curxp = *curyp = 0;
    494 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, defattrp);
    495 	sc->sc_nscreens++;
    496 
    497 	return 0;
    498 }
    499 
    500 static void
    501 smg_free_screen(void *v, void *cookie)
    502 {
    503 	struct smg_softc *sc = v;
    504 
    505 	sc->sc_nscreens--;
    506 }
    507 
    508 static int
    509 smg_show_screen(void *v, void *cookie, int waitok,
    510     void (*cb)(void *, int, int), void *cbarg)
    511 {
    512 
    513 	return 0;
    514 }
    515 
    516 static int
    517 smg_getcursor(struct smg_screen *ss, struct wsdisplay_cursor *wdc)
    518 {
    519 	int error;
    520 
    521 	if ((wdc->which & WSDISPLAY_CURSOR_DOCUR) != 0)
    522 		wdc->enable = ss->ss_curcmd & PCCCMD_ENPA ? 1 : 0;
    523 	if ((wdc->which & WSDISPLAY_CURSOR_DOPOS) != 0) {
    524 		wdc->pos.x = ss->ss_curpos.x;
    525 		wdc->pos.y = ss->ss_curpos.y;
    526 	}
    527 	if ((wdc->which & WSDISPLAY_CURSOR_DOHOT) != 0) {
    528 		wdc->hot.x = ss->ss_curhot.x;
    529 		wdc->hot.y = ss->ss_curhot.y;
    530 	}
    531 	if ((wdc->which & WSDISPLAY_CURSOR_DOCMAP) != 0) {
    532 		wdc->cmap.index = 0;
    533 		wdc->cmap.count = 0;
    534 	}
    535 	if ((wdc->which & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    536 		wdc->size.x = wdc->size.y = PCC_CURSOR_SIZE;
    537 		error = copyout(ss->ss_curimg, wdc->image,
    538 		    sizeof(ss->ss_curimg));
    539 		if (error != 0)
    540 			return error;
    541 		error = copyout(ss->ss_curmask, wdc->mask,
    542 		    sizeof(ss->ss_curmask));
    543 		if (error != 0)
    544 			return error;
    545 	}
    546 
    547 	return 0;
    548 }
    549 
    550 static int
    551 smg_setcursor(struct smg_screen *ss, struct wsdisplay_cursor *wdc)
    552 {
    553 	uint16_t curfg[PCC_CURSOR_SIZE], curmask[PCC_CURSOR_SIZE];
    554 	int error;
    555 
    556 	if ((wdc->which & WSDISPLAY_CURSOR_DOCMAP) != 0) {
    557 		/* No cursor colormap since we are a B&W device. */
    558 		if (wdc->cmap.count != 0)
    559 			return EINVAL;
    560 	}
    561 
    562 	/*
    563 	 * First, do the userland-kernel data transfers, so that we can fail
    564 	 * if necessary before altering anything.
    565 	 */
    566 	if ((wdc->which & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    567 		if (wdc->size.x != PCC_CURSOR_SIZE ||
    568 		    wdc->size.y != PCC_CURSOR_SIZE)
    569 			return EINVAL;
    570 		error = copyin(wdc->image, curfg, sizeof(curfg));
    571 		if (error != 0)
    572 			return error;
    573 		error = copyin(wdc->mask, curmask, sizeof(curmask));
    574 		if (error != 0)
    575 			return error;
    576 	}
    577 
    578 	/*
    579 	 * Now update our variables...
    580 	 */
    581 	if ((wdc->which & WSDISPLAY_CURSOR_DOCUR) != 0) {
    582 		if (wdc->enable)
    583 			ss->ss_curcmd |= PCCCMD_ENPB | PCCCMD_ENPA;
    584 		else
    585 			ss->ss_curcmd &= ~(PCCCMD_ENPB | PCCCMD_ENPA);
    586 	}
    587 	if ((wdc->which & WSDISPLAY_CURSOR_DOPOS) != 0) {
    588 		ss->ss_curpos.x = wdc->pos.x;
    589 		ss->ss_curpos.y = wdc->pos.y;
    590 	}
    591 	if ((wdc->which & WSDISPLAY_CURSOR_DOHOT) != 0) {
    592 		ss->ss_curhot.x = wdc->hot.x;
    593 		ss->ss_curhot.y = wdc->hot.y;
    594 	}
    595 	if ((wdc->which & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    596 		memcpy(ss->ss_curimg, curfg, sizeof(ss->ss_curimg));
    597 		memcpy(ss->ss_curmask, curmask, sizeof(ss->ss_curmask));
    598 	}
    599 
    600 	/*
    601 	 * ...and update the cursor
    602 	 */
    603 	smg_updatecursor(ss, wdc->which);
    604 
    605 	return 0;
    606 }
    607 
    608 static void
    609 smg_updatecursor(struct smg_screen *ss, u_int which)
    610 {
    611 	u_int i;
    612 
    613 	if ((which & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) {
    614 		ss->ss_cursor->xpos =
    615 		    ss->ss_curpos.x - ss->ss_curhot.x + CUR_XBIAS;
    616 		ss->ss_cursor->ypos =
    617 		    ss->ss_curpos.y - ss->ss_curhot.y + CUR_YBIAS;
    618 	}
    619 	if ((which & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
    620 		ss->ss_cursor->cmdr = ss->ss_curcmd | PCCCMD_LODSA;
    621 		for (i = 0; i < PCC_CURSOR_SIZE; i++)
    622 			ss->ss_cursor->load = ss->ss_curimg[i];
    623 		for (i = 0; i < PCC_CURSOR_SIZE; i++)
    624 			ss->ss_cursor->load = ss->ss_curmask[i];
    625 		ss->ss_cursor->cmdr = ss->ss_curcmd;
    626 	} else
    627 	if ((which & WSDISPLAY_CURSOR_DOCUR) != 0)
    628 		ss->ss_cursor->cmdr = ss->ss_curcmd;
    629 }
    630 
    631 /*
    632  * Faster console operations
    633  */
    634 
    635 #include <vax/vsa/maskbits.h>
    636 
    637 /* putchar() and cursor() ops are taken from luna68k omrasops.c */
    638 
    639 #define	ALL1BITS	(~0U)
    640 #define	ALL0BITS	(0U)
    641 #define	BLITWIDTH	(32)
    642 #define	ALIGNMASK	(0x1f)
    643 #define	BYTESDONE	(4)
    644 
    645 static void
    646 smg_putchar(void *cookie, int row, int startcol, u_int uc, long attr)
    647 {
    648 	struct rasops_info *ri = cookie;
    649 	uint8_t *p;
    650 	int scanspan, startx, height, width, align, y;
    651 	uint32_t lmask, rmask, glyph, inverse;
    652 	int i;
    653 	uint8_t *fb;
    654 
    655 	scanspan = ri->ri_stride;
    656 	y = ri->ri_font->fontheight * row;
    657 	startx = ri->ri_font->fontwidth * startcol;
    658 	height = ri->ri_font->fontheight;
    659 	fb = (uint8_t *)ri->ri_font->data +
    660 	    (uc - ri->ri_font->firstchar) * ri->ri_fontscale;
    661 	inverse = ((attr & WSATTR_REVERSE) != 0) ? ALL1BITS : ALL0BITS;
    662 
    663 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
    664 	align = startx & ALIGNMASK;
    665 	width = ri->ri_font->fontwidth + align;
    666 	/* lmask and rmask are in WSDISPLAY_FONTORDER_R2L bitorder */
    667 	lmask = ALL1BITS << align;
    668 	rmask = ALL1BITS >> (-width & ALIGNMASK);
    669 	if (width <= BLITWIDTH) {
    670 		uint32_t mask = lmask & rmask;
    671 		while (height > 0) {
    672 			uint32_t image;
    673 			/*
    674 			 * The font glyph is stored in byteorder and bitorder
    675 			 * WSDISPLAY_FONTORDER_R2L to use proper shift ops.
    676 			 * On the other hand, VRAM data is stored in
    677 			 * WSDISPLAY_FONTORDER_R2L bitorder and
    678 			 * WSDIPPLAY_FONTORDER_L2R byteorder.
    679 			 */
    680 			glyph = 0;
    681 			for (i = ri->ri_font->stride; i != 0; i--)
    682 				glyph = (glyph << 8) | *fb++;
    683 			glyph = (glyph << align) ^ inverse;
    684 			image = *(uint32_t *)p;
    685 			*(uint32_t *)p = (image & ~mask) | (glyph & mask);
    686 			p += scanspan;
    687 			height--;
    688 		}
    689 	} else {
    690 		uint8_t *q = p;
    691 		uint32_t lhalf, rhalf;
    692 
    693 		while (height > 0) {
    694 			uint32_t image;
    695 			glyph = 0;
    696 			for (i = ri->ri_font->stride; i != 0; i--)
    697 				glyph = (glyph << 8) | *fb++;
    698 			lhalf = (glyph << align) ^ inverse;
    699 			image = *(uint32_t *)p;
    700 			*(uint32_t *)p = (image & ~lmask) | (lhalf & lmask);
    701 			p += BYTESDONE;
    702 			rhalf = (glyph >> (BLITWIDTH - align)) ^ inverse;
    703 			image = *(uint32_t *)p;
    704 			*(uint32_t *)p = (rhalf & rmask) | (image & ~rmask);
    705 
    706 			p = (q += scanspan);
    707 			height--;
    708 		}
    709 	}
    710 }
    711 
    712 static void
    713 smg_cursor(void *cookie, int on, int row, int col)
    714 {
    715 	struct rasops_info *ri = cookie;
    716 	uint8_t *p;
    717 	int scanspan, startx, height, width, align, y;
    718 	uint32_t lmask, rmask, image;
    719 
    720 	if (!on) {
    721 		/* make sure it's on */
    722 		if ((ri->ri_flg & RI_CURSOR) == 0)
    723 			return;
    724 
    725 		row = ri->ri_crow;
    726 		col = ri->ri_ccol;
    727 	} else {
    728 		/* unpaint the old copy. */
    729 		ri->ri_crow = row;
    730 		ri->ri_ccol = col;
    731 	}
    732 
    733 	scanspan = ri->ri_stride;
    734 	y = ri->ri_font->fontheight * row;
    735 	startx = ri->ri_font->fontwidth * col;
    736 	height = ri->ri_font->fontheight;
    737 
    738 	p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4);
    739 	align = startx & ALIGNMASK;
    740 	width = ri->ri_font->fontwidth + align;
    741 	/* lmask and rmask are in WSDISPLAY_FONTORDER_R2L bitorder */
    742 	lmask = ALL1BITS << align;
    743 	rmask = ALL1BITS >> (-width & ALIGNMASK);
    744 	if (width <= BLITWIDTH) {
    745 		uint32_t mask = lmask & rmask;
    746 		while (height > 0) {
    747 			image = *(uint32_t *)p;
    748 			*(uint32_t *)p =
    749 			    (image & ~mask) | ((image ^ ALL1BITS) & mask);
    750 			p += scanspan;
    751 			height--;
    752 		}
    753 	} else {
    754 		uint8_t *q = p;
    755 
    756 		while (height > 0) {
    757 			image = *(uint32_t *)p;
    758 			*(uint32_t *)p =
    759 			    (image & ~lmask) | ((image ^ ALL1BITS) & lmask);
    760 			p += BYTESDONE;
    761 			image = *(uint32_t *)p;
    762 			*(uint32_t *)p =
    763 			    ((image ^ ALL1BITS) & rmask) | (image & ~rmask);
    764 
    765 			p = (q += scanspan);
    766 			height--;
    767 		}
    768 	}
    769 	ri->ri_flg ^= RI_CURSOR;
    770 }
    771 
    772 static void
    773 smg_blockmove(struct rasops_info *ri, u_int sx, u_int y, u_int dx, u_int cx,
    774     u_int cy, int rop)
    775 {
    776 	int width;		/* add to get to same position in next line */
    777 
    778 	unsigned int *psrcLine, *pdstLine;
    779 				/* pointers to line with current src and dst */
    780 	unsigned int *psrc;	/* pointer to current src longword */
    781 	unsigned int *pdst;	/* pointer to current dst longword */
    782 
    783 				/* following used for looping through a line */
    784 	unsigned int startmask, endmask;  /* masks for writing ends of dst */
    785 	int nlMiddle;		/* whole longwords in dst */
    786 	int nl;			/* temp copy of nlMiddle */
    787 	int xoffSrc;		/* offset (>= 0, < 32) from which to
    788 				   fetch whole longwords fetched in src */
    789 	int nstart;		/* number of ragged bits at start of dst */
    790 	int nend;		/* number of ragged bits at end of dst */
    791 	int srcStartOver;	/* pulling nstart bits from src
    792 				   overflows into the next word? */
    793 
    794 	width = SM_XWIDTH >> 5;
    795 
    796 	/* start at first scanline */
    797 	psrcLine = pdstLine = ((u_int *)ri->ri_bits) + (y * width);
    798 
    799 	/* x direction doesn't matter for < 1 longword */
    800 	if (cx <= 32) {
    801 		int srcBit, dstBit;	/* bit offset of src and dst */
    802 
    803 		pdstLine += (dx >> 5);
    804 		psrcLine += (sx >> 5);
    805 		psrc = psrcLine;
    806 		pdst = pdstLine;
    807 
    808 		srcBit = sx & ALIGNMASK;
    809 		dstBit = dx & ALIGNMASK;
    810 
    811 		while (cy--) {
    812 			getandputrop(psrc, srcBit, dstBit, cx, pdst, rop);
    813 			pdst += width;
    814 			psrc += width;
    815 		}
    816 	} else {
    817 		startmask = ALL1BITS << (dx & ALIGNMASK);
    818 		endmask   = ALL1BITS >> (~cx & ALIGNMASK);
    819 		if (startmask)
    820 			nlMiddle = (cx - (32 - (dx & ALIGNMASK))) >> 5;
    821 		else
    822 			nlMiddle = cx >> 5;
    823 
    824 		if (startmask)
    825 			nstart = 32 - (dx & ALIGNMASK);
    826 		else
    827 			nstart = 0;
    828 		if (endmask)
    829 			nend = (dx + cx) & ALIGNMASK;
    830 		else
    831 			nend = 0;
    832 
    833 		xoffSrc = ((sx & ALIGNMASK) + nstart) & ALIGNMASK;
    834 		srcStartOver = ((sx & ALIGNMASK) + nstart) > 31;
    835 
    836 		if (sx >= dx) {	/* move left to right */
    837 			pdstLine += (dx >> 5);
    838 			psrcLine += (sx >> 5);
    839 
    840 			while (cy--) {
    841 				psrc = psrcLine;
    842 				pdst = pdstLine;
    843 
    844 				if (startmask) {
    845 					getandputrop(psrc, (sx & ALIGNMASK),
    846 					    (dx & ALIGNMASK), nstart, pdst, rop);
    847 					pdst++;
    848 					if (srcStartOver)
    849 						psrc++;
    850 				}
    851 
    852 				/* special case for aligned operations */
    853 				if (xoffSrc == 0) {
    854 					nl = nlMiddle;
    855 					while (nl--) {
    856 						switch (rop) {
    857 						case RR_CLEAR:
    858 							*pdst = 0;
    859 							break;
    860 						case RR_SET:
    861 							*pdst = ~0;
    862 							break;
    863 						default:
    864 							*pdst = *psrc;
    865 							break;
    866 						}
    867 						psrc++;
    868 						pdst++;
    869 					}
    870 				} else {
    871 					nl = nlMiddle + 1;
    872 					while (--nl) {
    873 						switch (rop) {
    874 						case RR_CLEAR:
    875 							*pdst = 0;
    876 							break;
    877 						case RR_SET:
    878 							*pdst = ~0;
    879 							break;
    880 						default:
    881 							getunalignedword(psrc,
    882 							    xoffSrc, *pdst);
    883 							break;
    884 						}
    885 						pdst++;
    886 						psrc++;
    887 					}
    888 				}
    889 
    890 				if (endmask) {
    891 					getandputrop(psrc, xoffSrc, 0, nend,
    892 					    pdst, rop);
    893 				}
    894 
    895 				pdstLine += width;
    896 				psrcLine += width;
    897 			}
    898 		} else {	/* move right to left */
    899 			pdstLine += ((dx + cx) >> 5);
    900 			psrcLine += ((sx + cx) >> 5);
    901 			/*
    902 			 * If fetch of last partial bits from source crosses
    903 			 * a longword boundary, start at the previous longword
    904 			 */
    905 			if (xoffSrc + nend >= 32)
    906 				--psrcLine;
    907 
    908 			while (cy--) {
    909 				psrc = psrcLine;
    910 				pdst = pdstLine;
    911 
    912 				if (endmask) {
    913 					getandputrop(psrc, xoffSrc, 0, nend,
    914 					    pdst, rop);
    915 				}
    916 
    917 				nl = nlMiddle + 1;
    918 				while (--nl) {
    919 					--psrc;
    920 					--pdst;
    921 					switch (rop) {
    922 					case RR_CLEAR:
    923 						*pdst = 0;
    924 						break;
    925 					case RR_SET:
    926 						*pdst = ~0;
    927 						break;
    928 					default:
    929 						getunalignedword(psrc, xoffSrc,
    930 						    *pdst);
    931 						break;
    932 					}
    933 				}
    934 
    935 				if (startmask) {
    936 					if (srcStartOver)
    937 						--psrc;
    938 					--pdst;
    939 					getandputrop(psrc, (sx & ALIGNMASK),
    940 					    (dx & ALIGNMASK), nstart, pdst,
    941 					    rop);
    942 				}
    943 
    944 				pdstLine += width;
    945 				psrcLine += width;
    946 			}
    947 		}
    948 	}
    949 }
    950 
    951 static void
    952 smg_copycols(void *cookie, int row, int src, int dst, int n)
    953 {
    954 	struct rasops_info *ri = cookie;
    955 
    956 	n *= ri->ri_font->fontwidth;
    957 	src *= ri->ri_font->fontwidth;
    958 	dst *= ri->ri_font->fontwidth;
    959 	row *= ri->ri_font->fontheight;
    960 
    961 	smg_blockmove(ri, src, row, dst, n, ri->ri_font->fontheight,
    962 	    RR_COPY);
    963 }
    964 
    965 static void
    966 smg_erasecols(void *cookie, int row, int col, int num, long attr)
    967 {
    968 	struct rasops_info *ri = cookie;
    969 	int fg, bg;
    970 
    971 	rasops_unpack_attr(attr, &fg, &bg, NULL);
    972 
    973 	num *= ri->ri_font->fontwidth;
    974 	col *= ri->ri_font->fontwidth;
    975 	row *= ri->ri_font->fontheight;
    976 
    977 	smg_blockmove(ri, col, row, col, num, ri->ri_font->fontheight,
    978 	    bg == 0 ? RR_CLEAR : RR_SET);
    979 }
    980 
    981 /*
    982  * Console support code
    983  */
    984 
    985 cons_decl(smg);
    986 
    987 void
    988 smgcnprobe(struct consdev *cndev)
    989 {
    990 	extern const struct cdevsw wsdisplay_cdevsw;
    991 
    992 	switch (vax_boardtype) {
    993 	case VAX_BTYP_410:
    994 	case VAX_BTYP_420:
    995 	case VAX_BTYP_43:
    996 		if ((vax_confdata & (KA420_CFG_L3CON | KA420_CFG_MULTU)) != 0)
    997 			break;	/* doesn't use graphics console */
    998 
    999 		if ((vax_confdata & KA420_CFG_VIDOPT) != 0)
   1000 			break;	/* there is a color option */
   1001 
   1002 		cndev->cn_pri = CN_INTERNAL;
   1003 		cndev->cn_dev =
   1004 		    makedev(cdevsw_lookup_major(&wsdisplay_cdevsw), 0);
   1005 		break;
   1006 
   1007 	default:
   1008 		break;
   1009 	}
   1010 }
   1011 
   1012 /*
   1013  * Called very early to setup the glass tty as console.
   1014  * Because it's called before the VM system is initialized, virtual memory
   1015  * for the framebuffer can be stolen directly without disturbing anything.
   1016  */
   1017 void
   1018 smgcninit(struct consdev *cndev)
   1019 {
   1020 	struct smg_screen *ss = &smg_consscr;
   1021 	vaddr_t ova;
   1022 	long defattr;
   1023 	struct rasops_info *ri;
   1024 	extern vaddr_t virtual_avail;
   1025 
   1026 	ova = virtual_avail;
   1027 
   1028 	ss->ss_addr = (uint8_t *)virtual_avail;
   1029 	ioaccess(virtual_avail, SMADDR, SMSIZE / VAX_NBPG);
   1030 	virtual_avail += SMSIZE;
   1031 
   1032 	ss->ss_cursor = (struct dc503reg *)virtual_avail;
   1033 	ioaccess(virtual_avail, KA420_CUR_BASE, 1);
   1034 	virtual_avail += VAX_NBPG;
   1035 
   1036 	virtual_avail = round_page(virtual_avail);
   1037 
   1038 	/* this had better not fail */
   1039 	if (smg_setup_screen(ss) != 0) {
   1040 		iounaccess((vaddr_t)ss->ss_addr, SMSIZE / VAX_NBPG);
   1041 		iounaccess((vaddr_t)ss->ss_cursor, 1);
   1042 		virtual_avail = ova;
   1043 		return;
   1044 	}
   1045 
   1046 	ri = &ss->ss_ri;
   1047 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
   1048 	wsdisplay_cnattach(&smg_stdscreen, ri, 0, 0, defattr);
   1049 	cn_tab->cn_pri = CN_INTERNAL;
   1050 
   1051 #if NDZKBD > 0
   1052 	dzkbd_cnattach(0); /* Connect keyboard and screen together */
   1053 #endif
   1054 }
   1055