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