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