xref: /netbsd-src/sys/arch/vax/vsa/smg.c (revision 8733f5a6645975d0b589c28c3c3eb614dc83627a)
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
smg_match(device_t parent,cfdata_t cf,void * aux)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
smg_attach(device_t parent,device_t self,void * aux)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
smg_setup_screen(struct smg_screen * ss)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
smg_ioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)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
smg_mmap(void * v,void * vs,off_t offset,int prot)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
smg_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * defattrp)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
smg_free_screen(void * v,void * cookie)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
smg_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)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
smg_getcursor(struct smg_screen * ss,struct wsdisplay_cursor * wdc)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
smg_setcursor(struct smg_screen * ss,struct wsdisplay_cursor * wdc)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
smg_updatecursor(struct smg_screen * ss,u_int which)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
smg_putchar(void * cookie,int row,int startcol,u_int uc,long attr)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
smg_cursor(void * cookie,int on,int row,int col)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
smg_blockmove(struct rasops_info * ri,u_int sx,u_int y,u_int dx,u_int cx,u_int cy,int rop)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
smg_copycols(void * cookie,int row,int src,int dst,int n)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
smg_erasecols(void * cookie,int row,int col,int num,long attr)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
smgcnprobe(struct consdev * cndev)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
smgcninit(struct consdev * cndev)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