1 /* $NetBSD: amidisplaycc.c,v 1.40 2022/07/06 14:34:13 jandberg Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Jukka Andberg. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: amidisplaycc.c,v 1.40 2022/07/06 14:34:13 jandberg Exp $"); 32 33 /* 34 * wscons interface to amiga custom chips. Contains the necessary functions 35 * to render text on bitmapped screens. Uses the functions defined in 36 * grfabs_reg.h for display creation/destruction and low level setup. 37 * 38 * For each virtual terminal a new screen (a grfabs view) is allocated. 39 * Also one more view is allocated for the mapped screen on demand. 40 */ 41 42 #include "amidisplaycc.h" 43 #include "grfcc.h" 44 #include "view.h" 45 #include "opt_amigaccgrf.h" 46 #include "kbd.h" 47 48 #if NAMIDISPLAYCC>0 49 50 #include <sys/param.h> 51 #include <sys/types.h> 52 #include <sys/device.h> 53 #include <sys/malloc.h> 54 #include <sys/systm.h> 55 56 #include <sys/conf.h> 57 58 #include <amiga/dev/grfabs_reg.h> 59 #include <amiga/dev/kbdvar.h> 60 #include <amiga/dev/viewioctl.h> 61 #include <amiga/amiga/device.h> 62 #include <dev/wscons/wsconsio.h> 63 #include <dev/wscons/wscons_raster.h> 64 #include <dev/wscons/wsdisplayvar.h> 65 #include <dev/cons.h> 66 #include <dev/wsfont/wsfont.h> 67 68 /* These can be lowered if you are sure you don't need that much colors. */ 69 #define MAXDEPTH 8 70 #define MAXROWS 128 71 72 #define ADJUSTCOLORS 73 74 #define MAXCOLORS (1<<MAXDEPTH) 75 76 struct amidisplaycc_screen; 77 struct amidisplaycc_softc 78 { 79 struct amidisplaycc_screen * currentscreen; 80 81 /* display turned on? */ 82 int ison; 83 84 /* stuff relating to the mapped screen */ 85 view_t * gfxview; 86 int gfxwidth; 87 int gfxheight; 88 int gfxdepth; 89 int gfxon; 90 }; 91 92 93 /* 94 * Configuration stuff. 95 */ 96 97 static int amidisplaycc_match(device_t, cfdata_t, void *); 98 static void amidisplaycc_attach(device_t, device_t, void *); 99 100 CFATTACH_DECL_NEW(amidisplaycc, sizeof(struct amidisplaycc_softc), 101 amidisplaycc_match, amidisplaycc_attach, NULL, NULL); 102 103 static int amidisplaycc_attached; 104 105 cons_decl(amidisplaycc_); 106 107 /* end of configuration stuff */ 108 109 /* private utility functions */ 110 111 static int amidisplaycc_setvideo(struct amidisplaycc_softc *, int); 112 113 static int amidisplaycc_setemulcmap(struct amidisplaycc_screen *, 114 struct wsdisplay_cmap *); 115 116 static int amidisplaycc_cmapioctl(view_t *, u_long, struct wsdisplay_cmap *); 117 static int amidisplaycc_setcmap(view_t *, struct wsdisplay_cmap *); 118 static int amidisplaycc_getcmap(view_t *, struct wsdisplay_cmap *); 119 static int amidisplaycc_setgfxview(struct amidisplaycc_softc *, int); 120 static void amidisplaycc_initgfxview(struct amidisplaycc_softc *); 121 static int amidisplaycc_getfbinfo(struct amidisplaycc_softc *, struct wsdisplayio_fbinfo *); 122 123 static int amidisplaycc_setfont(struct amidisplaycc_screen *, const char *); 124 static const struct wsdisplay_font * amidisplaycc_getbuiltinfont(void); 125 static void amidisplaycc_cursor_undraw(struct amidisplaycc_screen *); 126 static void amidisplaycc_cursor_draw(struct amidisplaycc_screen *); 127 static void amidisplaycc_cursor_xor(struct amidisplaycc_screen *, int, int); 128 129 static void dprintf(const char *fmt, ...); 130 131 /* end of private utility functions */ 132 133 /* emulops for wscons */ 134 void amidisplaycc_cursor(void *, int, int, int); 135 int amidisplaycc_mapchar(void *, int, unsigned int *); 136 void amidisplaycc_putchar(void *, int, int, u_int, long); 137 void amidisplaycc_copycols(void *, int, int, int, int); 138 void amidisplaycc_erasecols(void *, int, int, int, long); 139 void amidisplaycc_copyrows(void *, int, int, int); 140 void amidisplaycc_eraserows(void *, int, int, long); 141 int amidisplaycc_allocattr(void *, int, int, int, long *); 142 /* end of emulops for wscons */ 143 144 145 /* accessops for wscons */ 146 int amidisplaycc_ioctl(void *, void *, u_long, void *, int, struct lwp *); 147 paddr_t amidisplaycc_mmap(void *, void *, off_t, int); 148 int amidisplaycc_alloc_screen(void *, const struct wsscreen_descr *, void **, 149 int *, int *, long *); 150 void amidisplaycc_free_screen( void *, void *); 151 int amidisplaycc_show_screen(void *, void *, int, void (*)(void *, int, int), 152 void *); 153 int amidisplaycc_load_font(void *, void *, struct wsdisplay_font *); 154 void amidisplaycc_pollc(void *, int); 155 /* end of accessops for wscons */ 156 157 /* 158 * These structures are passed to wscons, and they contain the 159 * display-specific callback functions. 160 */ 161 162 const struct wsdisplay_accessops amidisplaycc_accessops = { 163 amidisplaycc_ioctl, 164 amidisplaycc_mmap, 165 amidisplaycc_alloc_screen, 166 amidisplaycc_free_screen, 167 amidisplaycc_show_screen, 168 amidisplaycc_load_font, 169 amidisplaycc_pollc 170 }; 171 172 const struct wsdisplay_emulops amidisplaycc_emulops = { 173 amidisplaycc_cursor, 174 amidisplaycc_mapchar, 175 amidisplaycc_putchar, 176 amidisplaycc_copycols, 177 amidisplaycc_erasecols, 178 amidisplaycc_copyrows, 179 amidisplaycc_eraserows, 180 amidisplaycc_allocattr 181 }; 182 183 /* Add some of our own data to the wsscreen_descr */ 184 struct amidisplaycc_screen_descr { 185 struct wsscreen_descr wsdescr; 186 int depth; 187 }; 188 189 #define ADCC_SCREEN(name, width, height, depth, fontwidth, fontheight) \ 190 /* CONSTCOND */ \ 191 {{ \ 192 name, \ 193 width / fontwidth, \ 194 height / fontheight, \ 195 &amidisplaycc_emulops, fontwidth, fontheight, \ 196 (depth > 1 ? WSSCREEN_WSCOLORS : 0) | WSSCREEN_REVERSE | \ 197 WSSCREEN_HILIT | WSSCREEN_UNDERLINE }, \ 198 depth } 199 200 /* 201 * List of supported screen types. 202 * 203 * The first item in list is used for the console screen. 204 * A suitable screen size is guessed for it by looking 205 * at the GRF_* options. 206 */ 207 struct amidisplaycc_screen_descr amidisplaycc_screentab[] = { 208 /* name, width, height, depth, fontwidth==8, fontheight */ 209 210 #if defined(GRF_PAL) && !defined(GRF_NTSC) 211 ADCC_SCREEN("default", 640, 512, 3, 8, 8), 212 #else 213 ADCC_SCREEN("default", 640, 400, 3, 8, 8), 214 #endif 215 ADCC_SCREEN("80x50", 640, 400, 3, 8, 8), 216 ADCC_SCREEN("80x40", 640, 400, 3, 8, 10), 217 ADCC_SCREEN("80x25", 640, 400, 3, 8, 16), 218 ADCC_SCREEN("80x24", 640, 192, 3, 8, 8), 219 220 ADCC_SCREEN("80x64", 640, 512, 3, 8, 8), 221 ADCC_SCREEN("80x51", 640, 510, 3, 8, 10), 222 ADCC_SCREEN("80x32", 640, 512, 3, 8, 16), 223 ADCC_SCREEN("80x31", 640, 248, 3, 8, 8), 224 225 ADCC_SCREEN("640x400x1", 640, 400, 1, 8, 8), 226 ADCC_SCREEN("640x400x2", 640, 400, 2, 8, 8), 227 ADCC_SCREEN("640x400x3", 640, 400, 3, 8, 8), 228 229 ADCC_SCREEN("640x200x1", 640, 200, 1, 8, 8), 230 ADCC_SCREEN("640x200x2", 640, 200, 2, 8, 8), 231 ADCC_SCREEN("640x200x3", 640, 200, 3, 8, 8), 232 }; 233 234 #define ADCC_SCREENPTR(index) &amidisplaycc_screentab[index].wsdescr 235 const struct wsscreen_descr *amidisplaycc_screens[] = { 236 ADCC_SCREENPTR(0), 237 ADCC_SCREENPTR(1), 238 ADCC_SCREENPTR(2), 239 ADCC_SCREENPTR(3), 240 ADCC_SCREENPTR(4), 241 ADCC_SCREENPTR(5), 242 ADCC_SCREENPTR(6), 243 ADCC_SCREENPTR(7), 244 ADCC_SCREENPTR(8), 245 ADCC_SCREENPTR(9), 246 ADCC_SCREENPTR(10), 247 ADCC_SCREENPTR(11), 248 ADCC_SCREENPTR(12), 249 ADCC_SCREENPTR(13), 250 ADCC_SCREENPTR(14), 251 }; 252 253 #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0])) 254 255 /* 256 * This structure is passed to wscons. It contains pointers 257 * to the available display modes. 258 */ 259 260 const struct wsscreen_list amidisplaycc_screenlist = { 261 sizeof(amidisplaycc_screens)/sizeof(amidisplaycc_screens[0]), 262 amidisplaycc_screens 263 }; 264 265 /* 266 * Our own screen structure. One will be created for each screen. 267 */ 268 269 struct amidisplaycc_screen 270 { 271 struct amidisplaycc_softc *device; 272 273 int isconsole; 274 int isvisible; 275 view_t * view; 276 277 int ncols; 278 int nrows; 279 280 int cursorrow; 281 int cursorcol; 282 int cursordrawn; 283 284 /* Active bitplanes for each character row. */ 285 int rowmasks[MAXROWS]; 286 287 /* Mapping of colors to screen colors. */ 288 int colormap[MAXCOLORS]; 289 290 /* Copies of display parameters for convenience */ 291 int width; 292 int height; 293 int depth; 294 295 int widthbytes; /* bytes_per_row */ 296 int linebytes; /* widthbytes + row_mod */ 297 int rowbytes; /* linebytes * fontheight */ 298 299 u_char * planes[MAXDEPTH]; 300 301 const struct wsdisplay_font * wsfont; 302 int wsfontcookie; /* if -1, builtin font */ 303 int fontwidth; 304 int fontheight; 305 }; 306 307 typedef struct amidisplaycc_screen adccscr_t; 308 309 /* 310 * Need one statically allocated screen for early init. 311 * The rest are mallocated when needed. 312 */ 313 adccscr_t amidisplaycc_consolescreen; 314 315 /* 316 * Default palettes for 2, 4 and 8 color emulation displays. 317 */ 318 319 /* black, grey */ 320 static u_char pal2red[] = { 0x00, 0xaa }; 321 static u_char pal2grn[] = { 0x00, 0xaa }; 322 static u_char pal2blu[] = { 0x00, 0xaa }; 323 324 /* black, red, green, grey */ 325 static u_char pal4red[] = { 0x00, 0xaa, 0x00, 0xaa }; 326 static u_char pal4grn[] = { 0x00, 0x00, 0xaa, 0xaa }; 327 static u_char pal4blu[] = { 0x00, 0x00, 0x00, 0xaa }; 328 329 /* black, red, green, brown, blue, magenta, cyan, grey */ 330 static u_char pal8red[] = { 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa}; 331 static u_char pal8grn[] = { 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa}; 332 static u_char pal8blu[] = { 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa}; 333 334 static struct wsdisplay_cmap pal2 = { 0, 2, pal2red, pal2grn, pal2blu }; 335 static struct wsdisplay_cmap pal4 = { 0, 4, pal4red, pal4grn, pal4blu }; 336 static struct wsdisplay_cmap pal8 = { 0, 8, pal8red, pal8grn, pal8blu }; 337 338 #ifdef GRF_AGA 339 extern int aga_enable; 340 #else 341 static int aga_enable = 0; 342 #endif 343 344 /* 345 * This gets called at console init to determine the priority of 346 * this console device. 347 * 348 * Pointers to this and other functions must present 349 * in constab[] in conf.c for this to work. 350 */ 351 void 352 amidisplaycc_cnprobe(struct consdev *cd) 353 { 354 cd->cn_pri = CN_INTERNAL; 355 356 /* 357 * Yeah, real nice. But if we win the console then the wscons system 358 * does the proper initialization. 359 */ 360 cd->cn_dev = NODEV; 361 } 362 363 /* 364 * This gets called if this device is used as the console. 365 */ 366 void 367 amidisplaycc_cninit(struct consdev * cd) 368 { 369 void * cookie; 370 long attr; 371 int x; 372 int y; 373 374 /* 375 * This will do the basic stuff we also need. 376 */ 377 grfcc_probe(); 378 379 #if NVIEW>0 380 viewprobe(); 381 #endif 382 383 /* 384 * Set up wscons to handle the details. 385 * It will then call us back when it needs something 386 * display-specific. It will also set up cn_tab properly, 387 * something which we failed to do at amidisplaycc_cnprobe(). 388 */ 389 390 /* 391 * The alloc_screen knows to allocate the first screen statically. 392 */ 393 amidisplaycc_alloc_screen(NULL, &amidisplaycc_screentab[0].wsdescr, 394 &cookie, &x, &y, &attr); 395 wsdisplay_cnattach(&amidisplaycc_screentab[0].wsdescr, 396 cookie, x, y, attr); 397 398 #if NKBD>0 399 /* tell kbd device it is used as console keyboard */ 400 kbd_cnattach(); 401 #endif 402 } 403 404 static int 405 amidisplaycc_match(device_t parent, cfdata_t cf, void *aux) 406 { 407 char *name = aux; 408 409 if (matchname("amidisplaycc", name) == 0) 410 return 0; 411 412 /* Allow only one of us. */ 413 if (amidisplaycc_attached) 414 return 0; 415 416 return 1; 417 } 418 419 /* ARGSUSED */ 420 static void 421 amidisplaycc_attach(device_t parent, device_t self, void *aux) 422 { 423 struct wsemuldisplaydev_attach_args waa; 424 struct amidisplaycc_softc * adp; 425 426 amidisplaycc_attached = 1; 427 428 adp = device_private(self); 429 430 grfcc_probe(); 431 432 #if NVIEW>0 433 viewprobe(); 434 #endif 435 436 /* 437 * Attach only at real configuration time. Console init is done at 438 * the amidisplaycc_cninit function above. 439 */ 440 if (adp) { 441 printf(": Amiga custom chip graphics %s", 442 aga_enable ? "(AGA)" : ""); 443 444 if (amidisplaycc_consolescreen.isconsole) { 445 amidisplaycc_consolescreen.device = adp; 446 adp->currentscreen = &amidisplaycc_consolescreen; 447 printf(" (console)"); 448 } else 449 adp->currentscreen = NULL; 450 451 printf("\n"); 452 453 adp->ison = 1; 454 455 /* 456 * Mapped screen properties. 457 * Would need a way to configure. 458 */ 459 adp->gfxview = NULL; 460 adp->gfxon = 0; 461 adp->gfxwidth = amidisplaycc_screentab[0].wsdescr.ncols * 462 amidisplaycc_screentab[0].wsdescr.fontwidth; 463 adp->gfxheight = amidisplaycc_screentab[0].wsdescr.nrows * 464 amidisplaycc_screentab[0].wsdescr.fontheight; 465 466 if (aga_enable) 467 adp->gfxdepth = 8; 468 else 469 adp->gfxdepth = 4; 470 471 if (NELEMS(amidisplaycc_screentab) != 472 NELEMS(amidisplaycc_screens)) 473 panic("invalid screen definitions"); 474 475 waa.scrdata = &amidisplaycc_screenlist; 476 waa.console = amidisplaycc_consolescreen.isconsole; 477 waa.accessops = &amidisplaycc_accessops; 478 waa.accesscookie = adp; 479 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 480 481 wsfont_init(); 482 } 483 } 484 485 /* 486 * Foreground color, background color, and style are packed into one 487 * long attribute. These macros are used to create/split the attribute. 488 */ 489 490 #define MAKEATTR(fg, bg, mode) (((fg)<<16) | ((bg)<<8) | (mode)) 491 #define ATTRFG(attr) (((attr)>>16) & 255) 492 #define ATTRBG(attr) (((attr)>>8) & 255) 493 #define ATTRMO(attr) ((attr) & 255) 494 495 /* 496 * Called by wscons to draw/clear the cursor. 497 * We do this by xorring the block to the screen. 498 * 499 * This simple implementation will break if the screen is modified 500 * under the cursor before clearing it. 501 */ 502 void 503 amidisplaycc_cursor(void *screen, int on, int row, int col) 504 { 505 adccscr_t * scr; 506 507 scr = screen; 508 509 if (row < 0 || col < 0 || row >= scr->nrows || col >= scr->ncols) 510 return; 511 512 amidisplaycc_cursor_undraw(scr); 513 514 if (on) { 515 scr->cursorrow = row; 516 scr->cursorcol = col; 517 amidisplaycc_cursor_draw(scr); 518 } else { 519 scr->cursorrow = -1; 520 scr->cursorcol = -1; 521 } 522 } 523 524 void 525 amidisplaycc_cursor_undraw(struct amidisplaycc_screen * scr) 526 { 527 if (scr->cursordrawn) { 528 amidisplaycc_cursor_xor(scr, scr->cursorrow, scr->cursorcol); 529 scr->cursordrawn = 0; 530 } 531 } 532 533 void 534 amidisplaycc_cursor_draw(struct amidisplaycc_screen * scr) 535 { 536 if (!scr->cursordrawn && scr->cursorrow >= 0 && scr->cursorcol >= 0) { 537 amidisplaycc_cursor_xor(scr, scr->cursorrow, scr->cursorcol); 538 scr->cursordrawn = 1; 539 } 540 } 541 542 void 543 amidisplaycc_cursor_xor(struct amidisplaycc_screen * scr, int row, int col) 544 { 545 u_char * dst; 546 int i; 547 548 KASSERT(scr); 549 KASSERT(row >= 0); 550 KASSERT(col >= 0); 551 552 dst = scr->planes[0]; 553 dst += row * scr->rowbytes; 554 dst += col; 555 556 for (i = scr->fontheight ; i > 0 ; i--) { 557 *dst ^= 255; 558 dst += scr->linebytes; 559 } 560 } 561 562 int 563 amidisplaycc_mapchar(void *screen, int ch, unsigned int *chp) 564 { 565 if (ch > 0 && ch < 256) { 566 *chp = ch; 567 return 5; 568 } 569 *chp = ' '; 570 return 0; 571 } 572 573 /* 574 * Write a character to screen with color / bgcolor / hilite(bold) / 575 * underline / reverse. 576 * Surely could be made faster but I'm not sure if its worth the 577 * effort as scrolling is at least a magnitude slower. 578 */ 579 void 580 amidisplaycc_putchar(void *screen, int row, int col, u_int ch, long attr) 581 { 582 adccscr_t * scr; 583 u_char * dst; 584 u_char * font; 585 586 int fontheight; 587 u_int8_t * fontreal; 588 int fontlow; 589 int fonthigh; 590 591 int bmapoffset; 592 int linebytes; 593 int underline; 594 int fgcolor; 595 int bgcolor; 596 int plane; 597 int depth; 598 int mode; 599 int bold; 600 u_char f; 601 int j; 602 603 scr = screen; 604 605 if (row < 0 || col < 0 || row >= scr->nrows || col >= scr->ncols) 606 return; 607 608 /* Extract the colors from the attribute */ 609 fgcolor = ATTRFG(attr); 610 bgcolor = ATTRBG(attr); 611 mode = ATTRMO(attr); 612 613 /* Translate to screen colors */ 614 fgcolor = scr->colormap[fgcolor]; 615 bgcolor = scr->colormap[bgcolor]; 616 617 if (mode & WSATTR_REVERSE) { 618 j = fgcolor; 619 fgcolor = bgcolor; 620 bgcolor = j; 621 } 622 623 bold = (mode & WSATTR_HILIT) > 0; 624 underline = (mode & WSATTR_UNDERLINE) > 0; 625 626 fontreal = scr->wsfont->data; 627 fontlow = scr->wsfont->firstchar; 628 fonthigh = fontlow + scr->wsfont->numchars - 1; 629 630 fontheight = uimin(scr->fontheight, scr->wsfont->fontheight); 631 depth = scr->depth; 632 linebytes = scr->linebytes; 633 634 if (ch < fontlow || ch > fonthigh) 635 ch = fontlow; 636 637 /* Find the location where the wanted char is in the font data */ 638 fontreal += scr->wsfont->fontheight * (ch - fontlow); 639 640 bmapoffset = row * scr->rowbytes + col; 641 642 scr->rowmasks[row] |= fgcolor | bgcolor; 643 644 for (plane = 0 ; plane < depth ; plane++) { 645 dst = scr->planes[plane] + bmapoffset; 646 647 if (fgcolor & 1) { 648 if (bgcolor & 1) { 649 /* fg=on bg=on (fill) */ 650 651 for (j = 0 ; j < fontheight ; j++) { 652 *dst = 255; 653 dst += linebytes; 654 } 655 } else { 656 /* fg=on bg=off (normal) */ 657 658 font = fontreal; 659 for (j = 0 ; j < fontheight ; j++) { 660 f = *(font++); 661 f |= f >> bold; 662 *dst = f; 663 dst += linebytes; 664 } 665 666 if (underline) 667 *(dst - linebytes) = 255; 668 } 669 } else { 670 if (bgcolor & 1) { 671 /* fg=off bg=on (inverted) */ 672 673 font = fontreal; 674 for (j = 0 ; j < fontheight ; j++) { 675 f = *(font++); 676 f |= f >> bold; 677 *dst = ~f; 678 dst += linebytes; 679 } 680 681 if (underline) 682 *(dst - linebytes) = 0; 683 } else { 684 /* fg=off bg=off (clear) */ 685 686 for (j = 0 ; j < fontheight ; j++) { 687 *dst = 0; 688 dst += linebytes; 689 } 690 } 691 } 692 fgcolor >>= 1; 693 bgcolor >>= 1; 694 } 695 } 696 697 /* 698 * Copy characters on a row to another position on the same row. 699 */ 700 701 void 702 amidisplaycc_copycols(void *screen, int row, int srccol, int dstcol, int ncols) 703 { 704 adccscr_t * scr; 705 u_char * src; 706 u_char * dst; 707 708 int bmapoffset; 709 int linebytes; 710 int depth; 711 int plane; 712 int i; 713 int j; 714 715 scr = screen; 716 717 if (srccol < 0 || srccol + ncols > scr->ncols || 718 dstcol < 0 || dstcol + ncols > scr->ncols || 719 row < 0 || row >= scr->nrows) 720 return; 721 722 depth = scr->depth; 723 linebytes = scr->linebytes; 724 bmapoffset = row * scr->rowbytes; 725 726 for (plane = 0 ; plane < depth ; plane++) { 727 src = scr->planes[plane] + bmapoffset; 728 729 for (j = 0 ; j < scr->fontheight ; j++) { 730 dst = src; 731 732 if (srccol < dstcol) { 733 734 for (i = ncols - 1 ; i >= 0 ; i--) 735 dst[dstcol + i] = src[srccol + i]; 736 737 } else { 738 739 for (i = 0 ; i < ncols ; i++) 740 dst[dstcol + i] = src[srccol + i]; 741 742 } 743 src += linebytes; 744 } 745 } 746 } 747 748 /* 749 * Erase part of a row. 750 */ 751 752 void 753 amidisplaycc_erasecols(void *screen, int row, int startcol, int ncols, 754 long attr) 755 { 756 adccscr_t * scr; 757 u_char * dst; 758 759 int bmapoffset; 760 int linebytes; 761 int bgcolor; 762 int depth; 763 int plane; 764 int fill; 765 int j; 766 767 scr = screen; 768 769 if (row < 0 || row >= scr->nrows || 770 startcol < 0 || startcol + ncols > scr->ncols) 771 return; 772 773 depth = scr->depth; 774 linebytes = scr->linebytes; 775 bmapoffset = row * scr->rowbytes + startcol; 776 777 /* Erase will be done using the set background color. */ 778 bgcolor = ATTRBG(attr); 779 bgcolor = scr->colormap[bgcolor]; 780 781 for(plane = 0 ; plane < depth ; plane++) { 782 783 fill = (bgcolor & 1) ? 255 : 0; 784 785 dst = scr->planes[plane] + bmapoffset; 786 787 for (j = 0 ; j < scr->fontheight ; j++) { 788 memset(dst, fill, ncols); 789 dst += linebytes; 790 } 791 } 792 } 793 794 /* 795 * Copy a number of rows to another location on the screen. 796 */ 797 798 void 799 amidisplaycc_copyrows(void *screen, int srcrow, int dstrow, int nrows) 800 { 801 adccscr_t * scr; 802 u_char * src; 803 u_char * dst; 804 805 int srcbmapoffset; 806 int dstbmapoffset; 807 int widthbytes; 808 int fontheight; 809 int linebytes; 810 u_int copysize; 811 int rowdelta; 812 int rowbytes; 813 int srcmask; 814 int dstmask; 815 int bmdelta; 816 int depth; 817 int plane; 818 int i; 819 int j; 820 821 scr = screen; 822 823 if (srcrow < 0 || srcrow + nrows > scr->nrows || 824 dstrow < 0 || dstrow + nrows > scr->nrows) 825 return; 826 827 depth = scr->depth; 828 829 widthbytes = scr->widthbytes; 830 rowbytes = scr->rowbytes; 831 linebytes = scr->linebytes; 832 fontheight = scr->fontheight; 833 834 srcbmapoffset = rowbytes * srcrow; 835 dstbmapoffset = rowbytes * dstrow; 836 837 if (srcrow < dstrow) { 838 /* Move data downwards, need to copy from down to up */ 839 bmdelta = -rowbytes; 840 rowdelta = -1; 841 842 srcbmapoffset += rowbytes * (nrows - 1); 843 srcrow += nrows - 1; 844 845 dstbmapoffset += rowbytes * (nrows - 1); 846 dstrow += nrows - 1; 847 } else { 848 /* Move data upwards, copy up to down */ 849 bmdelta = rowbytes; 850 rowdelta = 1; 851 } 852 853 if (widthbytes == linebytes) 854 copysize = rowbytes; 855 else 856 copysize = 0; 857 858 for (j = 0 ; j < nrows ; j++) { 859 /* Need to copy only planes that have data on src or dst */ 860 srcmask = scr->rowmasks[srcrow]; 861 dstmask = scr->rowmasks[dstrow]; 862 scr->rowmasks[dstrow] = srcmask; 863 864 for (plane = 0 ; plane < depth ; plane++) { 865 866 if (srcmask & 1) { 867 /* 868 * Source row has data on this 869 * plane, copy it. 870 */ 871 872 src = scr->planes[plane] + srcbmapoffset; 873 dst = scr->planes[plane] + dstbmapoffset; 874 875 if (copysize > 0) { 876 877 memcpy(dst, src, copysize); 878 879 } else { 880 881 /* 882 * Data not continuous, 883 * must do in pieces 884 */ 885 for (i=0 ; i < fontheight ; i++) { 886 memcpy(dst, src, widthbytes); 887 888 src += linebytes; 889 dst += linebytes; 890 } 891 } 892 } else if (dstmask & 1) { 893 /* 894 * Source plane is empty, but dest is not. 895 * so all we need to is clear it. 896 */ 897 898 dst = scr->planes[plane] + dstbmapoffset; 899 900 if (copysize > 0) { 901 /* Do it all */ 902 memset(dst, 0, copysize); 903 } else { 904 for (i = 0 ; i < fontheight ; i++) { 905 memset(dst, 0, widthbytes); 906 dst += linebytes; 907 } 908 } 909 } 910 911 srcmask >>= 1; 912 dstmask >>= 1; 913 } 914 srcbmapoffset += bmdelta; 915 dstbmapoffset += bmdelta; 916 917 srcrow += rowdelta; 918 dstrow += rowdelta; 919 } 920 } 921 922 /* 923 * Erase some rows. 924 */ 925 926 void 927 amidisplaycc_eraserows(void *screen, int row, int nrows, long attr) 928 { 929 adccscr_t * scr; 930 u_char * dst; 931 932 int bmapoffset; 933 int fillsize; 934 int bgcolor; 935 int depth; 936 int plane; 937 int fill; 938 int j; 939 940 int widthbytes; 941 int linebytes; 942 int rowbytes; 943 944 945 scr = screen; 946 947 if (row < 0 || row + nrows > scr->nrows) 948 return; 949 amidisplaycc_cursor_undraw(scr); 950 951 depth = scr->depth; 952 widthbytes = scr->widthbytes; 953 linebytes = scr->linebytes; 954 rowbytes = scr->rowbytes; 955 956 bmapoffset = row * rowbytes; 957 958 if (widthbytes == linebytes) 959 fillsize = rowbytes * nrows; 960 else 961 fillsize = 0; 962 963 bgcolor = ATTRBG(attr); 964 bgcolor = scr->colormap[bgcolor]; 965 966 for (j = 0 ; j < nrows ; j++) 967 scr->rowmasks[row+j] = bgcolor; 968 969 for (plane = 0 ; plane < depth ; plane++) { 970 dst = scr->planes[plane] + bmapoffset; 971 fill = (bgcolor & 1) ? 255 : 0; 972 973 if (fillsize > 0) { 974 /* If the rows are continuous, write them all. */ 975 memset(dst, fill, fillsize); 976 } else { 977 for (j = 0 ; j < scr->fontheight * nrows ; j++) { 978 memset(dst, fill, widthbytes); 979 dst += linebytes; 980 } 981 } 982 bgcolor >>= 1; 983 } 984 amidisplaycc_cursor_draw(scr); 985 } 986 987 988 /* 989 * Compose an attribute value from foreground color, 990 * background color, and flags. 991 */ 992 int 993 amidisplaycc_allocattr(void *screen, int fg, int bg, int flags, long *attrp) 994 { 995 adccscr_t * scr; 996 int maxcolor; 997 int newfg; 998 int newbg; 999 1000 scr = screen; 1001 maxcolor = (1 << scr->view->bitmap->depth) - 1; 1002 1003 /* Ensure the colors are displayable. */ 1004 newfg = fg & maxcolor; 1005 newbg = bg & maxcolor; 1006 1007 #ifdef ADJUSTCOLORS 1008 /* 1009 * Hack for low-color screens, if background color is nonzero 1010 * but would be displayed as one, adjust it. 1011 */ 1012 if (bg > 0 && newbg == 0) 1013 newbg = maxcolor; 1014 1015 /* 1016 * If foreground and background colors are different but would 1017 * display the same fix them by modifying the foreground. 1018 */ 1019 if (fg != bg && newfg == newbg) { 1020 if (newbg > 0) 1021 newfg = 0; 1022 else 1023 newfg = maxcolor; 1024 } 1025 #endif 1026 *attrp = MAKEATTR(newfg, newbg, flags); 1027 1028 return 0; 1029 } 1030 1031 int 1032 amidisplaycc_ioctl(void *dp, void *vs, u_long cmd, void *data, int flag, 1033 struct lwp *l) 1034 { 1035 struct amidisplaycc_softc *adp; 1036 1037 adp = dp; 1038 1039 if (adp == NULL) { 1040 printf("amidisplaycc_ioctl: adp==NULL\n"); 1041 return EINVAL; 1042 } 1043 1044 #define UINTDATA (*(u_int*)data) 1045 #define INTDATA (*(int*)data) 1046 #define FBINFO (*(struct wsdisplay_fbinfo*)data) 1047 1048 switch (cmd) 1049 { 1050 case WSDISPLAYIO_GTYPE: 1051 UINTDATA = WSDISPLAY_TYPE_AMIGACC; 1052 return 0; 1053 1054 case WSDISPLAYIO_SVIDEO: 1055 dprintf("amidisplaycc: WSDISPLAYIO_SVIDEO %s\n", 1056 UINTDATA ? "On" : "Off"); 1057 1058 return amidisplaycc_setvideo(adp, UINTDATA); 1059 1060 case WSDISPLAYIO_GVIDEO: 1061 dprintf("amidisplaycc: WSDISPLAYIO_GVIDEO\n"); 1062 UINTDATA = adp->ison ? 1063 WSDISPLAYIO_VIDEO_ON : WSDISPLAYIO_VIDEO_OFF; 1064 1065 return 0; 1066 1067 case WSDISPLAYIO_SMODE: 1068 switch (INTDATA) { 1069 case WSDISPLAYIO_MODE_EMUL: 1070 return amidisplaycc_setgfxview(adp, 0); 1071 case WSDISPLAYIO_MODE_MAPPED: 1072 case WSDISPLAYIO_MODE_DUMBFB: 1073 return amidisplaycc_setgfxview(adp, 1); 1074 default: 1075 return EINVAL; 1076 } 1077 1078 case WSDISPLAYIO_GINFO: 1079 FBINFO.width = adp->gfxwidth; 1080 FBINFO.height = adp->gfxheight; 1081 FBINFO.depth = adp->gfxdepth; 1082 FBINFO.cmsize = 1 << FBINFO.depth; 1083 return 0; 1084 1085 case WSDISPLAYIO_PUTCMAP: 1086 case WSDISPLAYIO_GETCMAP: 1087 return amidisplaycc_cmapioctl(adp->gfxview, cmd, 1088 (struct wsdisplay_cmap*)data); 1089 case WSDISPLAYIO_GET_FBINFO: 1090 amidisplaycc_initgfxview(adp); 1091 return amidisplaycc_getfbinfo(adp, data); 1092 } 1093 1094 return EPASSTHROUGH; 1095 1096 #undef UINTDATA 1097 #undef INTDATA 1098 #undef FBINFO 1099 } 1100 1101 static int 1102 amidisplaycc_getfbinfo(struct amidisplaycc_softc *adp, struct wsdisplayio_fbinfo *fbinfo) 1103 { 1104 bmap_t *bm; 1105 1106 KASSERT(adp); 1107 1108 if (adp->gfxview == NULL) { 1109 return ENOMEM; 1110 } 1111 1112 bm = adp->gfxview->bitmap; 1113 KASSERT(bm); 1114 1115 memset(fbinfo, 0, sizeof(*fbinfo)); 1116 fbinfo->fbi_fbsize = bm->bytes_per_row * bm->rows * adp->gfxdepth; 1117 fbinfo->fbi_fboffset = 0; 1118 fbinfo->fbi_width = bm->bytes_per_row * 8; 1119 fbinfo->fbi_height = bm->rows; 1120 fbinfo->fbi_stride = bm->bytes_per_row; 1121 fbinfo->fbi_bitsperpixel = adp->gfxdepth; 1122 fbinfo->fbi_pixeltype = WSFB_CI; 1123 fbinfo->fbi_flags = 0; 1124 fbinfo->fbi_subtype.fbi_cmapinfo.cmap_entries = 1 << adp->gfxdepth; 1125 1126 return 0; 1127 } 1128 1129 /* 1130 * Initialize (but not display) the view used for graphics. 1131 */ 1132 static void 1133 amidisplaycc_initgfxview(struct amidisplaycc_softc *adp) 1134 { 1135 dimen_t dimension; 1136 1137 if (adp->gfxview == NULL) { 1138 /* First time here, create the screen */ 1139 dimension.width = adp->gfxwidth; 1140 dimension.height = adp->gfxheight; 1141 adp->gfxview = grf_alloc_view(NULL, 1142 &dimension, 1143 adp->gfxdepth); 1144 } 1145 } 1146 1147 /* 1148 * Switch to either emulation (text) or mapped (graphics) mode 1149 * We keep an extra screen for mapped mode so it does not 1150 * interfere with emulation screens. 1151 * 1152 * Once the extra screen is created, it never goes away. 1153 */ 1154 static int 1155 amidisplaycc_setgfxview(struct amidisplaycc_softc *adp, int on) 1156 { 1157 dprintf("amidisplaycc: switching to %s mode.\n", 1158 on ? "mapped" : "emul"); 1159 1160 /* Current mode same as requested mode? */ 1161 if ( (on > 0) == (adp->gfxon > 0) ) 1162 return 0; 1163 1164 if (!on) { 1165 /* 1166 * Switch away from mapped mode. If there is 1167 * a emulation screen, switch to it, otherwise 1168 * just try to hide the mapped screen. 1169 */ 1170 adp->gfxon = 0; 1171 if (adp->currentscreen) 1172 grf_display_view(adp->currentscreen->view); 1173 else if (adp->gfxview) 1174 grf_remove_view(adp->gfxview); 1175 1176 return 0; 1177 } 1178 1179 /* switch to mapped mode then */ 1180 amidisplaycc_initgfxview(adp); 1181 1182 if (adp->gfxview) { 1183 adp->gfxon = 1; 1184 1185 grf_display_view(adp->gfxview); 1186 } else { 1187 printf("amidisplaycc: failed to make mapped screen\n"); 1188 return ENOMEM; 1189 } 1190 return 0; 1191 } 1192 1193 /* 1194 * Map the graphics screen. It must have been created before 1195 * by switching to mapped mode by using an ioctl. 1196 */ 1197 paddr_t 1198 amidisplaycc_mmap(void *dp, void *vs, off_t off, int prot) 1199 { 1200 struct amidisplaycc_softc * adp; 1201 bmap_t * bm; 1202 paddr_t rv; 1203 1204 adp = (struct amidisplaycc_softc*)dp; 1205 1206 /* Check we are in mapped mode */ 1207 if (adp->gfxon == 0 || adp->gfxview == NULL) { 1208 dprintf("amidisplaycc_mmap: Not in mapped mode\n"); 1209 return (paddr_t)(-1); 1210 } 1211 1212 /* 1213 * Screen reserved for graphics is used to avoid writing 1214 * over the text screens. 1215 */ 1216 1217 bm = adp->gfxview->bitmap; 1218 1219 /* Check that the offset is valid */ 1220 if (off < 0 || off >= bm->depth * bm->bytes_per_row * bm->rows) { 1221 dprintf("amidisplaycc_mmap: Offset out of range\n"); 1222 return (paddr_t)(-1); 1223 } 1224 1225 rv = (paddr_t)bm->hardware_address; 1226 rv += off; 1227 1228 return MD_BTOP(rv); 1229 } 1230 1231 1232 /* 1233 * Create a new screen. 1234 * 1235 * NULL dp signifies console and then memory is allocated statically 1236 * and the screen is automatically displayed. 1237 * 1238 * A font with suitable size is searched and if not found 1239 * the builtin 8x8 font is used. 1240 * 1241 * There are separate default palettes for 2, 4 and 8+ color 1242 * screens. 1243 */ 1244 1245 int 1246 amidisplaycc_alloc_screen(void *dp, const struct wsscreen_descr *screenp, 1247 void **cookiep, int *curxp, int *curyp, 1248 long *defattrp) 1249 { 1250 const struct amidisplaycc_screen_descr * adccscreenp; 1251 struct amidisplaycc_screen * scr; 1252 struct amidisplaycc_softc * adp; 1253 view_t * view; 1254 1255 dimen_t dimension; 1256 int fontheight; 1257 int fontwidth; 1258 int maxcolor; 1259 int depth; 1260 int i; 1261 int j; 1262 1263 adccscreenp = (const struct amidisplaycc_screen_descr *)screenp; 1264 depth = adccscreenp->depth; 1265 1266 adp = dp; 1267 1268 maxcolor = (1 << depth) - 1; 1269 1270 /* Sanity checks because of fixed buffers */ 1271 if (depth > MAXDEPTH || maxcolor >= MAXCOLORS) 1272 return ENOMEM; 1273 if (screenp->nrows > MAXROWS) 1274 return ENOMEM; 1275 1276 fontwidth = screenp->fontwidth; 1277 fontheight = screenp->fontheight; 1278 1279 /* 1280 * The screen size is defined in characters. 1281 * Calculate the pixel size using the font size. 1282 */ 1283 1284 dimension.width = screenp->ncols * fontwidth; 1285 dimension.height = screenp->nrows * fontheight; 1286 1287 view = grf_alloc_view(NULL, &dimension, depth); 1288 if (view == NULL) 1289 return ENOMEM; 1290 1291 /* 1292 * First screen gets the statically allocated console screen. 1293 * Others are allocated dynamically. 1294 */ 1295 if (adp == NULL) { 1296 scr = &amidisplaycc_consolescreen; 1297 if (scr->isconsole) 1298 panic("more than one console?"); 1299 1300 scr->isconsole = 1; 1301 } else { 1302 scr = malloc(sizeof(adccscr_t), M_DEVBUF, M_WAITOK|M_ZERO); 1303 } 1304 1305 scr->view = view; 1306 1307 scr->ncols = screenp->ncols; 1308 scr->nrows = screenp->nrows; 1309 1310 /* Copies of most used values */ 1311 scr->width = dimension.width; 1312 scr->height = dimension.height; 1313 scr->depth = depth; 1314 scr->widthbytes = view->bitmap->bytes_per_row; 1315 scr->linebytes = scr->widthbytes + view->bitmap->row_mod; 1316 scr->rowbytes = scr->linebytes * fontheight; 1317 1318 scr->device = adp; 1319 1320 1321 /* 1322 * Try to find a suitable font. 1323 * Avoid everything but the builtin font for console screen. 1324 * Builtin font is used if no other is found, even if it 1325 * has the wrong size. 1326 */ 1327 1328 KASSERT(fontwidth == 8); 1329 1330 scr->wsfont = NULL; 1331 scr->wsfontcookie = -1; 1332 scr->fontwidth = fontwidth; 1333 scr->fontheight = fontheight; 1334 1335 if (adp) 1336 amidisplaycc_setfont(scr, NULL); 1337 1338 if (scr->wsfont == NULL) 1339 { 1340 scr->wsfont = amidisplaycc_getbuiltinfont(); 1341 scr->wsfontcookie = -1; 1342 } 1343 1344 KASSERT(scr->wsfont); 1345 KASSERT(scr->wsfont->stride == 1); 1346 1347 for (i = 0 ; i < depth ; i++) { 1348 scr->planes[i] = view->bitmap->plane[i]; 1349 } 1350 1351 for (i = 0 ; i < MAXROWS ; i++) 1352 scr->rowmasks[i] = 0; 1353 1354 /* Simple one-to-one mapping for most colors */ 1355 for (i = 0 ; i < MAXCOLORS ; i++) 1356 scr->colormap[i] = i; 1357 1358 /* 1359 * Arrange the most used pens to quickest colors. 1360 * The default color for given depth is (1<<depth)-1. 1361 * It is assumed it is used most and it is mapped to 1362 * color that can be drawn by writing data to one bitplane 1363 * only. 1364 * So map colors 3->2, 7->4, 15->8 and so on. 1365 */ 1366 for (i = 2 ; i < MAXCOLORS ; i *= 2) { 1367 j = i * 2 - 1; 1368 1369 if (j < MAXCOLORS) { 1370 scr->colormap[i] = j; 1371 scr->colormap[j] = i; 1372 } 1373 } 1374 1375 /* 1376 * Set the default colormap. 1377 */ 1378 if (depth == 1) 1379 amidisplaycc_setemulcmap(scr, &pal2); 1380 else if (depth == 2) 1381 amidisplaycc_setemulcmap(scr, &pal4); 1382 else 1383 amidisplaycc_setemulcmap(scr, &pal8); 1384 1385 *cookiep = scr; 1386 1387 /* cursor initially at top left */ 1388 scr->cursorrow = -1; 1389 scr->cursorcol = -1; 1390 *curxp = 0; 1391 *curyp = 0; 1392 amidisplaycc_cursor(scr, 1, *curxp, *curyp); 1393 1394 *defattrp = MAKEATTR(maxcolor, 0, 0); 1395 1396 /* Show the console automatically */ 1397 if (adp == NULL) 1398 grf_display_view(scr->view); 1399 1400 if (adp) { 1401 dprintf("amidisplaycc: allocated screen; %dx%dx%d; font=%s\n", 1402 dimension.width, 1403 dimension.height, 1404 depth, 1405 scr->wsfont->name); 1406 } 1407 1408 return 0; 1409 } 1410 1411 1412 /* 1413 * Destroy a screen. 1414 */ 1415 1416 void 1417 amidisplaycc_free_screen(void *dp, void *screen) 1418 { 1419 struct amidisplaycc_screen * scr; 1420 struct amidisplaycc_softc * adp; 1421 1422 scr = screen; 1423 adp = (struct amidisplaycc_softc*)dp; 1424 1425 if (scr == NULL) 1426 return; 1427 1428 /* Free the used font */ 1429 if (scr->wsfont && scr->wsfontcookie != -1) 1430 wsfont_unlock(scr->wsfontcookie); 1431 scr->wsfont = NULL; 1432 scr->wsfontcookie = -1; 1433 1434 if (adp->currentscreen == scr) 1435 adp->currentscreen = NULL; 1436 1437 if (scr->view) 1438 grf_free_view(scr->view); 1439 scr->view = NULL; 1440 1441 /* Take care not to free the statically allocated console screen */ 1442 if (scr != &amidisplaycc_consolescreen) { 1443 free(scr, M_DEVBUF); 1444 } 1445 } 1446 1447 /* 1448 * Switch to another vt. Switch is always made immediately. 1449 */ 1450 1451 /* ARGSUSED2 */ 1452 int 1453 amidisplaycc_show_screen(void *dp, void *screen, int waitok, 1454 void (*cb) (void *, int, int), void *cbarg) 1455 { 1456 adccscr_t *scr; 1457 struct amidisplaycc_softc *adp; 1458 1459 adp = (struct amidisplaycc_softc*)dp; 1460 scr = screen; 1461 1462 if (adp == NULL) { 1463 dprintf("amidisplaycc_show_screen: adp==NULL\n"); 1464 return EINVAL; 1465 } 1466 if (scr == NULL) { 1467 dprintf("amidisplaycc_show_screen: scr==NULL\n"); 1468 return EINVAL; 1469 } 1470 1471 if (adp->gfxon) { 1472 dprintf("amidisplaycc: Screen shift while in gfx mode?"); 1473 adp->gfxon = 0; 1474 } 1475 1476 adp->currentscreen = scr; 1477 adp->ison = 1; 1478 1479 grf_display_view(scr->view); 1480 1481 return 0; 1482 } 1483 1484 /* 1485 * Load/set a font. 1486 * 1487 * Only setting is supported, as the wsfont pseudo-device can 1488 * handle the loading of fonts for us. 1489 */ 1490 int 1491 amidisplaycc_load_font(void *dp, void *cookie, struct wsdisplay_font *font) 1492 { 1493 struct amidisplaycc_softc * adp __diagused; 1494 struct amidisplaycc_screen * scr __diagused; 1495 1496 adp = dp; 1497 scr = cookie; 1498 1499 KASSERT(adp); 1500 KASSERT(scr); 1501 KASSERT(font); 1502 KASSERT(font->name); 1503 1504 if (font->data) 1505 { 1506 /* request to load the font, not supported */ 1507 return EINVAL; 1508 } 1509 else 1510 { 1511 /* request to use the given font on this screen */ 1512 return amidisplaycc_setfont(scr, font->name); 1513 } 1514 } 1515 1516 /* 1517 * Set display on/off. 1518 */ 1519 static int 1520 amidisplaycc_setvideo(struct amidisplaycc_softc *adp, int mode) 1521 { 1522 view_t * view; 1523 1524 if (adp == NULL) { 1525 dprintf("amidisplaycc_setvideo: adp==NULL\n"); 1526 return EINVAL; 1527 } 1528 if (adp->currentscreen == NULL) { 1529 dprintf("amidisplaycc_setvideo: adp->currentscreen==NULL\n"); 1530 return EINVAL; 1531 } 1532 1533 /* select graphics or emulation screen */ 1534 if (adp->gfxon && adp->gfxview) 1535 view = adp->gfxview; 1536 else 1537 view = adp->currentscreen->view; 1538 1539 if (mode) { 1540 /* on */ 1541 1542 grf_display_view(view); 1543 dprintf("amidisplaycc: video is now on\n"); 1544 adp->ison = 1; 1545 1546 } else { 1547 /* off */ 1548 1549 grf_remove_view(view); 1550 dprintf("amidisplaycc: video is now off\n"); 1551 adp->ison = 0; 1552 } 1553 1554 return 0; 1555 } 1556 1557 /* 1558 * Handle the WSDISPLAY_[PUT/GET]CMAP ioctls. 1559 * Just handle the copying of data to/from userspace and 1560 * let the functions amidisplaycc_setcmap and amidisplaycc_putcmap 1561 * do the real work. 1562 */ 1563 1564 static int 1565 amidisplaycc_cmapioctl(view_t *view, u_long cmd, struct wsdisplay_cmap *cmap) 1566 { 1567 struct wsdisplay_cmap tmpcmap; 1568 u_char cmred[MAXCOLORS]; 1569 u_char cmgrn[MAXCOLORS]; 1570 u_char cmblu[MAXCOLORS]; 1571 1572 int err; 1573 1574 if (cmap->index >= MAXCOLORS || 1575 cmap->count > MAXCOLORS || 1576 cmap->index + cmap->count > MAXCOLORS) 1577 return EINVAL; 1578 1579 if (cmap->count == 0) 1580 return 0; 1581 1582 tmpcmap.index = cmap->index; 1583 tmpcmap.count = cmap->count; 1584 tmpcmap.red = cmred; 1585 tmpcmap.green = cmgrn; 1586 tmpcmap.blue = cmblu; 1587 1588 if (cmd == WSDISPLAYIO_PUTCMAP) { 1589 /* copy the color data to kernel space */ 1590 1591 err = copyin(cmap->red, cmred, cmap->count); 1592 if (err) 1593 return err; 1594 1595 err = copyin(cmap->green, cmgrn, cmap->count); 1596 if (err) 1597 return err; 1598 1599 err = copyin(cmap->blue, cmblu, cmap->count); 1600 if (err) 1601 return err; 1602 1603 return amidisplaycc_setcmap(view, &tmpcmap); 1604 1605 } else if (cmd == WSDISPLAYIO_GETCMAP) { 1606 1607 err = amidisplaycc_getcmap(view, &tmpcmap); 1608 if (err) 1609 return err; 1610 1611 /* copy data to user space */ 1612 1613 err = copyout(cmred, cmap->red, cmap->count); 1614 if (err) 1615 return err; 1616 1617 err = copyout(cmgrn, cmap->green, cmap->count); 1618 if (err) 1619 return err; 1620 1621 err = copyout(cmblu, cmap->blue, cmap->count); 1622 if (err) 1623 return err; 1624 1625 return 0; 1626 1627 } else 1628 return EPASSTHROUGH; 1629 } 1630 1631 /* 1632 * Set the palette of a emulation screen. 1633 * Here we do only color remapping and then call 1634 * amidisplaycc_setcmap to do the work. 1635 */ 1636 1637 static int 1638 amidisplaycc_setemulcmap(struct amidisplaycc_screen *scr, 1639 struct wsdisplay_cmap *cmap) 1640 { 1641 struct wsdisplay_cmap tmpcmap; 1642 1643 u_char red [MAXCOLORS]; 1644 u_char grn [MAXCOLORS]; 1645 u_char blu [MAXCOLORS]; 1646 1647 int rc; 1648 int i; 1649 1650 /* 1651 * Get old palette first. 1652 * Because of the color mapping going on in the emulation 1653 * screen the color range may not be contiguous in the real 1654 * palette. 1655 * So get the whole palette, insert the new colors 1656 * at the appropriate places and then set the whole 1657 * palette back. 1658 */ 1659 1660 tmpcmap.index = 0; 1661 tmpcmap.count = 1 << scr->depth; 1662 tmpcmap.red = red; 1663 tmpcmap.green = grn; 1664 tmpcmap.blue = blu; 1665 1666 rc = amidisplaycc_getcmap(scr->view, &tmpcmap); 1667 if (rc) 1668 return rc; 1669 1670 for (i = cmap->index ; i < cmap->index + cmap->count ; i++) { 1671 1672 tmpcmap.red [ scr->colormap[ i ] ] = cmap->red [ i ]; 1673 tmpcmap.green [ scr->colormap[ i ] ] = cmap->green [ i ]; 1674 tmpcmap.blue [ scr->colormap[ i ] ] = cmap->blue [ i ]; 1675 } 1676 1677 rc = amidisplaycc_setcmap(scr->view, &tmpcmap); 1678 if (rc) 1679 return rc; 1680 1681 return 0; 1682 } 1683 1684 1685 /* 1686 * Set the colormap for the given screen. 1687 */ 1688 1689 static int 1690 amidisplaycc_setcmap(view_t *view, struct wsdisplay_cmap *cmap) 1691 { 1692 u_long cmentries [MAXCOLORS]; 1693 1694 u_int colors; 1695 int index; 1696 int count; 1697 int err; 1698 colormap_t cm; 1699 1700 if (view == NULL) 1701 return EINVAL; 1702 1703 if (!cmap || !cmap->red || !cmap->green || !cmap->blue) { 1704 dprintf("amidisplaycc_setcmap: other==NULL\n"); 1705 return EINVAL; 1706 } 1707 1708 index = cmap->index; 1709 count = cmap->count; 1710 colors = (1 << view->bitmap->depth); 1711 1712 if (count > colors || index >= colors || index + count > colors) 1713 return EINVAL; 1714 1715 if (count == 0) 1716 return 0; 1717 1718 cm.entry = cmentries; 1719 cm.first = index; 1720 cm.size = count; 1721 1722 /* 1723 * Get the old colormap. We need to do this at least to know 1724 * how many bits to use with the color values. 1725 */ 1726 1727 err = grf_get_colormap(view, &cm); 1728 if (err) 1729 return err; 1730 1731 /* 1732 * The palette entries from wscons contain 8 bits per gun. 1733 * We need to convert them to the number of bits the view 1734 * expects. That is typically 4 or 8. Here we calculate the 1735 * conversion constants with which we divide the color values. 1736 */ 1737 1738 if (cm.type == CM_COLOR) { 1739 int c, green_div, blue_div, red_div; 1740 1741 red_div = 256 / (cm.red_mask + 1); 1742 green_div = 256 / (cm.green_mask + 1); 1743 blue_div = 256 / (cm.blue_mask + 1); 1744 1745 for (c = 0 ; c < count ; c++) 1746 cm.entry[c + index] = MAKE_COLOR_ENTRY( 1747 cmap->red[c] / red_div, 1748 cmap->green[c] / green_div, 1749 cmap->blue[c] / blue_div); 1750 1751 } else if (cm.type == CM_GREYSCALE) { 1752 int c, grey_div; 1753 1754 grey_div = 256 / (cm.grey_mask + 1); 1755 1756 /* Generate grey from average of r-g-b (?) */ 1757 for (c = 0 ; c < count ; c++) 1758 cm.entry[c + index] = MAKE_COLOR_ENTRY( 1759 0, 1760 0, 1761 (cmap->red[c] + 1762 cmap->green[c] + 1763 cmap->blue[c]) / 3 / grey_div); 1764 } else 1765 return EINVAL; /* Hmhh */ 1766 1767 /* 1768 * Now we have a new colormap that contains all the entries. Set 1769 * it to the view. 1770 */ 1771 1772 err = grf_use_colormap(view, &cm); 1773 if (err) 1774 return err; 1775 1776 return 0; 1777 } 1778 1779 /* 1780 * Return the colormap of the given screen. 1781 */ 1782 1783 static int 1784 amidisplaycc_getcmap(view_t *view, struct wsdisplay_cmap *cmap) 1785 { 1786 u_long cmentries [MAXCOLORS]; 1787 1788 u_int colors; 1789 int index; 1790 int count; 1791 int err; 1792 colormap_t cm; 1793 1794 if (view == NULL) 1795 return EINVAL; 1796 1797 if (!cmap || !cmap->red || !cmap->green || !cmap->blue) 1798 return EINVAL; 1799 1800 index = cmap->index; 1801 count = cmap->count; 1802 colors = (1 << view->bitmap->depth); 1803 1804 if (count > colors || index >= colors || index + count > colors) 1805 return EINVAL; 1806 1807 if (count == 0) 1808 return 0; 1809 1810 cm.entry = cmentries; 1811 cm.first = index; 1812 cm.size = count; 1813 1814 err = grf_get_colormap(view, &cm); 1815 if (err) 1816 return err; 1817 1818 /* 1819 * Copy color data to wscons-style structure. Translate to 1820 * 8 bits/gun from whatever resolution the color natively is. 1821 */ 1822 if (cm.type == CM_COLOR) { 1823 int c, red_mul, green_mul, blue_mul; 1824 1825 red_mul = 256 / (cm.red_mask + 1); 1826 green_mul = 256 / (cm.green_mask + 1); 1827 blue_mul = 256 / (cm.blue_mask + 1); 1828 1829 for (c = 0 ; c < count ; c++) { 1830 cmap->red[c] = red_mul * 1831 CM_GET_RED(cm.entry[index+c]); 1832 cmap->green[c] = green_mul * 1833 CM_GET_GREEN(cm.entry[index+c]); 1834 cmap->blue[c] = blue_mul * 1835 CM_GET_BLUE(cm.entry[index+c]); 1836 } 1837 } else if (cm.type == CM_GREYSCALE) { 1838 int c, grey_mul; 1839 1840 grey_mul = 256 / (cm.grey_mask + 1); 1841 1842 for (c = 0 ; c < count ; c++) { 1843 cmap->red[c] = grey_mul * 1844 CM_GET_GREY(cm.entry[index+c]); 1845 cmap->green[c] = grey_mul * 1846 CM_GET_GREY(cm.entry[index+c]); 1847 cmap->blue[c] = grey_mul * 1848 CM_GET_GREY(cm.entry[index+c]); 1849 } 1850 } else 1851 return EINVAL; 1852 1853 return 0; 1854 } 1855 1856 /* 1857 * Find and set a font for the given screen. 1858 * 1859 * If fontname is given, a font with that name and suitable 1860 * size (determined by the screen) is searched for. 1861 * If fontname is NULL, a font with suitable size is searched. 1862 * 1863 * On success, the found font is assigned to the screen and possible 1864 * old font is freed. 1865 */ 1866 static int 1867 amidisplaycc_setfont(struct amidisplaycc_screen *scr, const char *fontname) 1868 { 1869 struct wsdisplay_font *wsfont; 1870 int wsfontcookie; 1871 1872 KASSERT(scr); 1873 1874 wsfontcookie = wsfont_find(fontname, 1875 scr->fontwidth, 1876 scr->fontheight, 1877 1, 1878 WSDISPLAY_FONTORDER_L2R, 1879 WSDISPLAY_FONTORDER_L2R, 1880 WSFONT_FIND_BITMAP); 1881 1882 if (wsfontcookie == -1) 1883 return EINVAL; 1884 1885 /* Suitable font found. Now lock it. */ 1886 if (wsfont_lock(wsfontcookie, &wsfont)) 1887 return EINVAL; 1888 1889 KASSERT(wsfont); 1890 1891 if (scr->wsfont && scr->wsfontcookie != -1) 1892 wsfont_unlock(scr->wsfontcookie); 1893 1894 scr->wsfont = wsfont; 1895 scr->wsfontcookie = wsfontcookie; 1896 1897 return 0; 1898 } 1899 1900 /* 1901 * Return a font that is guaranteed to exist. 1902 */ 1903 static const struct wsdisplay_font * 1904 amidisplaycc_getbuiltinfont(void) 1905 { 1906 static struct wsdisplay_font font; 1907 1908 extern unsigned char kernel_font_width_8x8; 1909 extern unsigned char kernel_font_height_8x8; 1910 extern unsigned char kernel_font_lo_8x8; 1911 extern unsigned char kernel_font_hi_8x8; 1912 extern unsigned char kernel_font_8x8[]; 1913 1914 font.name = "kf8x8"; 1915 font.firstchar = kernel_font_lo_8x8; 1916 font.numchars = kernel_font_hi_8x8 - kernel_font_lo_8x8 + 1; 1917 font.fontwidth = kernel_font_width_8x8; 1918 font.stride = 1; 1919 font.fontheight = kernel_font_height_8x8; 1920 font.data = kernel_font_8x8; 1921 1922 /* these values aren't really used for anything */ 1923 font.encoding = WSDISPLAY_FONTENC_ISO; 1924 font.bitorder = WSDISPLAY_FONTORDER_KNOWN; 1925 font.byteorder = WSDISPLAY_FONTORDER_KNOWN; 1926 1927 return &font; 1928 } 1929 1930 /* ARGSUSED */ 1931 void 1932 amidisplaycc_pollc(void *cookie, int on) 1933 { 1934 if (amidisplaycc_consolescreen.isconsole) 1935 { 1936 if (on) 1937 { 1938 /* About to use console, so make it visible */ 1939 grf_display_view(amidisplaycc_consolescreen.view); 1940 } 1941 if (!on && 1942 amidisplaycc_consolescreen.isconsole && 1943 amidisplaycc_consolescreen.device != NULL && 1944 amidisplaycc_consolescreen.device->currentscreen != NULL) 1945 { 1946 /* Restore the correct view after done with console use */ 1947 grf_display_view(amidisplaycc_consolescreen.device->currentscreen->view); 1948 } 1949 } 1950 } 1951 1952 /* 1953 * These dummy functions are here just so that we can compete of 1954 * the console at init. 1955 * If we win the console then the wscons system will provide the 1956 * real ones which in turn will call the appropriate wskbd device. 1957 * These should never be called. 1958 */ 1959 1960 /* ARGSUSED */ 1961 void 1962 amidisplaycc_cnputc(dev_t cd, int ch) 1963 { 1964 } 1965 1966 /* ARGSUSED */ 1967 int 1968 amidisplaycc_cngetc(dev_t cd) 1969 { 1970 return 0; 1971 } 1972 1973 /* ARGSUSED */ 1974 void 1975 amidisplaycc_cnpollc(dev_t cd, int on) 1976 { 1977 } 1978 1979 1980 /* 1981 * Prints stuff if DEBUG is turned on. 1982 */ 1983 1984 /* ARGSUSED */ 1985 static void 1986 dprintf(const char *fmt, ...) 1987 { 1988 #ifdef DEBUG 1989 va_list ap; 1990 1991 va_start(ap, fmt); 1992 vprintf(fmt, ap); 1993 va_end(ap); 1994 #endif 1995 } 1996 1997 #endif /* AMIDISPLAYCC */ 1998