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