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