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