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