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