1 /* $NetBSD: rasops.c,v 1.52 2006/02/27 12:19:29 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: rasops.c,v 1.52 2006/02/27 12:19:29 jmcneill Exp $"); 41 42 #include "opt_rasops.h" 43 #include "rasops_glue.h" 44 #include "opt_wsmsgattrs.h" 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/time.h> 49 50 #include <sys/bswap.h> 51 #include <machine/endian.h> 52 53 #include <dev/wscons/wsdisplayvar.h> 54 #include <dev/wscons/wsconsio.h> 55 #include <dev/wsfont/wsfont.h> 56 #include <dev/rasops/rasops.h> 57 58 #ifndef _KERNEL 59 #include <errno.h> 60 #endif 61 62 /* ANSI colormap (R,G,B). Upper 8 are high-intensity */ 63 const u_char rasops_cmap[256*3] = { 64 0x00, 0x00, 0x00, /* black */ 65 0x7f, 0x00, 0x00, /* red */ 66 0x00, 0x7f, 0x00, /* green */ 67 0x7f, 0x7f, 0x00, /* brown */ 68 0x00, 0x00, 0x7f, /* blue */ 69 0x7f, 0x00, 0x7f, /* magenta */ 70 0x00, 0x7f, 0x7f, /* cyan */ 71 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 72 73 0x7f, 0x7f, 0x7f, /* black */ 74 0xff, 0x00, 0x00, /* red */ 75 0x00, 0xff, 0x00, /* green */ 76 0xff, 0xff, 0x00, /* brown */ 77 0x00, 0x00, 0xff, /* blue */ 78 0xff, 0x00, 0xff, /* magenta */ 79 0x00, 0xff, 0xff, /* cyan */ 80 0xff, 0xff, 0xff, /* white */ 81 82 /* 83 * For the cursor, we need at least the last (255th) 84 * color to be white. Fill up white completely for 85 * simplicity. 86 */ 87 #define _CMWHITE 0xff, 0xff, 0xff, 88 #define _CMWHITE16 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 89 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 90 _CMWHITE _CMWHITE _CMWHITE _CMWHITE \ 91 _CMWHITE _CMWHITE _CMWHITE _CMWHITE 92 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 93 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 94 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 /* but not the last one */ 95 #undef _CMWHITE16 96 #undef _CMWHITE 97 98 /* 99 * For the cursor the fg/bg indices are bit inverted, so 100 * provide complimentary colors in the upper 16 entries. 101 */ 102 0x7f, 0x7f, 0x7f, /* black */ 103 0xff, 0x00, 0x00, /* red */ 104 0x00, 0xff, 0x00, /* green */ 105 0xff, 0xff, 0x00, /* brown */ 106 0x00, 0x00, 0xff, /* blue */ 107 0xff, 0x00, 0xff, /* magenta */ 108 0x00, 0xff, 0xff, /* cyan */ 109 0xff, 0xff, 0xff, /* white */ 110 111 0x00, 0x00, 0x00, /* black */ 112 0x7f, 0x00, 0x00, /* red */ 113 0x00, 0x7f, 0x00, /* green */ 114 0x7f, 0x7f, 0x00, /* brown */ 115 0x00, 0x00, 0x7f, /* blue */ 116 0x7f, 0x00, 0x7f, /* magenta */ 117 0x00, 0x7f, 0x7f, /* cyan */ 118 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */ 119 }; 120 121 /* True if color is gray */ 122 const u_char rasops_isgray[16] = { 123 1, 0, 0, 0, 124 0, 0, 0, 1, 125 1, 0, 0, 0, 126 0, 0, 0, 1 127 }; 128 129 /* Generic functions */ 130 static void rasops_copyrows(void *, int, int, int); 131 static int rasops_mapchar(void *, int, u_int *); 132 static void rasops_cursor(void *, int, int, int); 133 static int rasops_allocattr_color(void *, int, int, int, long *); 134 static int rasops_allocattr_mono(void *, int, int, int, long *); 135 static void rasops_do_cursor(struct rasops_info *); 136 static void rasops_init_devcmap(struct rasops_info *); 137 138 /* 139 * Initialize a 'rasops_info' descriptor. 140 */ 141 int 142 rasops_init(ri, wantrows, wantcols) 143 struct rasops_info *ri; 144 int wantrows, wantcols; 145 { 146 147 #ifdef _KERNEL 148 /* Select a font if the caller doesn't care */ 149 if (ri->ri_font == NULL) { 150 int cookie; 151 152 wsfont_init(); 153 154 /* Want 8 pixel wide, don't care about aestethics */ 155 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_L2R, 156 WSDISPLAY_FONTORDER_L2R); 157 if (cookie <= 0) 158 cookie = wsfont_find(NULL, 0, 0, 0, 159 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R); 160 161 if (cookie <= 0) { 162 printf("rasops_init: font table is empty\n"); 163 return (-1); 164 } 165 166 if (wsfont_lock(cookie, &ri->ri_font)) { 167 printf("rasops_init: couldn't lock font\n"); 168 return (-1); 169 } 170 171 ri->ri_wsfcookie = cookie; 172 } 173 #endif 174 175 /* This should never happen in reality... */ 176 #ifdef DEBUG 177 if ((long)ri->ri_bits & 3) { 178 printf("rasops_init: bits not aligned on 32-bit boundary\n"); 179 return (-1); 180 } 181 182 if ((int)ri->ri_stride & 3) { 183 printf("rasops_init: stride not aligned on 32-bit boundary\n"); 184 return (-1); 185 } 186 #endif 187 188 if (rasops_reconfig(ri, wantrows, wantcols)) 189 return (-1); 190 191 rasops_init_devcmap(ri); 192 return (0); 193 } 194 195 /* 196 * Reconfigure (because parameters have changed in some way). 197 */ 198 int 199 rasops_reconfig(ri, wantrows, wantcols) 200 struct rasops_info *ri; 201 int wantrows, wantcols; 202 { 203 int bpp, s; 204 205 s = splhigh(); 206 207 if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4) 208 panic("rasops_init: fontwidth assumptions botched!"); 209 210 /* Need this to frob the setup below */ 211 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth); 212 213 if ((ri->ri_flg & RI_CFGDONE) != 0) 214 ri->ri_bits = ri->ri_origbits; 215 216 /* Don't care if the caller wants a hideously small console */ 217 if (wantrows < 10) 218 wantrows = 10; 219 220 if (wantcols < 20) 221 wantcols = 20; 222 223 /* Now constrain what they get */ 224 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 225 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 226 227 if (ri->ri_emuwidth > ri->ri_width) 228 ri->ri_emuwidth = ri->ri_width; 229 230 if (ri->ri_emuheight > ri->ri_height) 231 ri->ri_emuheight = ri->ri_height; 232 233 /* Reduce width until aligned on a 32-bit boundary */ 234 while ((ri->ri_emuwidth * bpp & 31) != 0) 235 ri->ri_emuwidth--; 236 237 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 238 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 239 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 240 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 241 ri->ri_ccol = 0; 242 ri->ri_crow = 0; 243 ri->ri_pelbytes = bpp >> 3; 244 245 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 246 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 247 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 248 249 #ifdef DEBUG 250 if ((ri->ri_delta & 3) != 0) 251 panic("rasops_init: ri_delta not aligned on 32-bit boundary"); 252 #endif 253 /* Clear the entire display */ 254 if ((ri->ri_flg & RI_CLEAR) != 0) 255 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 256 257 /* Now centre our window if needs be */ 258 ri->ri_origbits = ri->ri_bits; 259 260 if ((ri->ri_flg & RI_CENTER) != 0) { 261 ri->ri_bits += (((ri->ri_width * bpp >> 3) - 262 ri->ri_emustride) >> 1) & ~3; 263 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 264 ri->ri_stride; 265 266 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) 267 / ri->ri_stride; 268 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) 269 % ri->ri_stride) * 8 / bpp); 270 } else 271 ri->ri_xorigin = ri->ri_yorigin = 0; 272 273 /* 274 * Fill in defaults for operations set. XXX this nukes private 275 * routines used by accelerated fb drivers. 276 */ 277 ri->ri_ops.mapchar = rasops_mapchar; 278 ri->ri_ops.copyrows = rasops_copyrows; 279 ri->ri_ops.copycols = rasops_copycols; 280 ri->ri_ops.erasecols = rasops_erasecols; 281 ri->ri_ops.eraserows = rasops_eraserows; 282 ri->ri_ops.cursor = rasops_cursor; 283 ri->ri_do_cursor = rasops_do_cursor; 284 285 if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) { 286 ri->ri_ops.allocattr = rasops_allocattr_mono; 287 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE; 288 } else { 289 ri->ri_ops.allocattr = rasops_allocattr_color; 290 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 291 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 292 } 293 294 switch (ri->ri_depth) { 295 #if NRASOPS1 > 0 296 case 1: 297 rasops1_init(ri); 298 break; 299 #endif 300 #if NRASOPS2 > 0 301 case 2: 302 rasops2_init(ri); 303 break; 304 #endif 305 #if NRASOPS4 > 0 306 case 4: 307 rasops4_init(ri); 308 break; 309 #endif 310 #if NRASOPS8 > 0 311 case 8: 312 rasops8_init(ri); 313 break; 314 #endif 315 #if NRASOPS15 > 0 || NRASOPS16 > 0 316 case 15: 317 case 16: 318 rasops15_init(ri); 319 break; 320 #endif 321 #if NRASOPS24 > 0 322 case 24: 323 rasops24_init(ri); 324 break; 325 #endif 326 #if NRASOPS32 > 0 327 case 32: 328 rasops32_init(ri); 329 break; 330 #endif 331 default: 332 ri->ri_flg &= ~RI_CFGDONE; 333 splx(s); 334 return (-1); 335 } 336 337 ri->ri_flg |= RI_CFGDONE; 338 splx(s); 339 return (0); 340 } 341 342 /* 343 * Map a character. 344 */ 345 static int 346 rasops_mapchar(cookie, c, cp) 347 void *cookie; 348 int c; 349 u_int *cp; 350 { 351 struct rasops_info *ri; 352 353 ri = (struct rasops_info *)cookie; 354 355 #ifdef DIAGNOSTIC 356 if (ri->ri_font == NULL) 357 panic("rasops_mapchar: no font selected"); 358 #endif 359 360 if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) { 361 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 362 *cp = ' '; 363 return (0); 364 365 } 366 } 367 368 if (c < ri->ri_font->firstchar) { 369 *cp = ' '; 370 return (0); 371 } 372 373 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 374 *cp = ' '; 375 return (0); 376 } 377 378 *cp = c; 379 return (5); 380 } 381 382 /* 383 * Allocate a color attribute. 384 */ 385 static int 386 rasops_allocattr_color(cookie, fg, bg, flg, attr) 387 void *cookie; 388 int fg, bg, flg; 389 long *attr; 390 { 391 int swap; 392 393 #ifdef RASOPS_CLIPPING 394 fg &= 7; 395 bg &= 7; 396 #endif 397 if ((flg & WSATTR_BLINK) != 0) 398 return (EINVAL); 399 400 if ((flg & WSATTR_WSCOLORS) == 0) { 401 #ifdef WS_DEFAULT_FG 402 fg = WS_DEFAULT_FG; 403 #else 404 fg = WSCOL_WHITE; 405 #endif 406 #ifdef WS_DEFAULT_BG 407 bg = WS_DEFAULT_BG; 408 #else 409 bg = WSCOL_BLACK; 410 #endif 411 } 412 413 if ((flg & WSATTR_REVERSE) != 0) { 414 swap = fg; 415 fg = bg; 416 bg = swap; 417 } 418 419 if ((flg & WSATTR_HILIT) != 0) 420 fg += 8; 421 422 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 423 424 if (rasops_isgray[fg]) 425 flg |= 2; 426 427 if (rasops_isgray[bg]) 428 flg |= 4; 429 430 *attr = (bg << 16) | (fg << 24) | flg; 431 return (0); 432 } 433 434 /* 435 * Allocate a mono attribute. 436 */ 437 static int 438 rasops_allocattr_mono(cookie, fg, bg, flg, attr) 439 void *cookie; 440 int fg, bg, flg; 441 long *attr; 442 { 443 int swap; 444 445 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 446 return (EINVAL); 447 448 fg = 1; 449 bg = 0; 450 451 if ((flg & WSATTR_REVERSE) != 0) { 452 swap = fg; 453 fg = bg; 454 bg = swap; 455 } 456 457 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 458 return (0); 459 } 460 461 /* 462 * Copy rows. 463 */ 464 static void 465 rasops_copyrows(cookie, src, dst, num) 466 void *cookie; 467 int src, dst, num; 468 { 469 int32_t *sp, *dp, *hp, *srp, *drp, *hrp; 470 struct rasops_info *ri; 471 int n8, n1, cnt, delta; 472 473 ri = (struct rasops_info *)cookie; 474 hp = hrp = NULL; 475 476 #ifdef RASOPS_CLIPPING 477 if (dst == src) 478 return; 479 480 if (src < 0) { 481 num += src; 482 src = 0; 483 } 484 485 if ((src + num) > ri->ri_rows) 486 num = ri->ri_rows - src; 487 488 if (dst < 0) { 489 num += dst; 490 dst = 0; 491 } 492 493 if ((dst + num) > ri->ri_rows) 494 num = ri->ri_rows - dst; 495 496 if (num <= 0) 497 return; 498 #endif 499 500 num *= ri->ri_font->fontheight; 501 n8 = ri->ri_emustride >> 5; 502 n1 = (ri->ri_emustride >> 2) & 7; 503 504 if (dst < src) { 505 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 506 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 507 if (ri->ri_hwbits) 508 hrp = (int32_t *)(ri->ri_hwbits + dst * 509 ri->ri_yscale); 510 delta = ri->ri_stride; 511 } else { 512 src = ri->ri_font->fontheight * src + num - 1; 513 dst = ri->ri_font->fontheight * dst + num - 1; 514 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 515 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 516 if (ri->ri_hwbits) 517 hrp = (int32_t *)(ri->ri_hwbits + dst * 518 ri->ri_stride); 519 520 delta = -ri->ri_stride; 521 } 522 523 while (num--) { 524 dp = drp; 525 sp = srp; 526 if (ri->ri_hwbits) 527 hp = hrp; 528 529 DELTA(drp, delta, int32_t *); 530 DELTA(srp, delta, int32_t *); 531 if (ri->ri_hwbits) 532 DELTA(hrp, delta, int32_t *); 533 534 for (cnt = n8; cnt; cnt--) { 535 dp[0] = sp[0]; 536 dp[1] = sp[1]; 537 dp[2] = sp[2]; 538 dp[3] = sp[3]; 539 dp[4] = sp[4]; 540 dp[5] = sp[5]; 541 dp[6] = sp[6]; 542 dp[7] = sp[7]; 543 dp += 8; 544 sp += 8; 545 } 546 if (ri->ri_hwbits) { 547 sp -= (8 * n8); 548 for (cnt = n8; cnt; cnt--) { 549 hp[0] = sp[0]; 550 hp[1] = sp[1]; 551 hp[2] = sp[2]; 552 hp[3] = sp[3]; 553 hp[4] = sp[4]; 554 hp[5] = sp[5]; 555 hp[6] = sp[6]; 556 hp[7] = sp[7]; 557 hp += 8; 558 sp += 8; 559 } 560 } 561 562 for (cnt = n1; cnt; cnt--) { 563 *dp++ = *sp++; 564 if (ri->ri_hwbits) 565 *hp++ = *(sp - 1); 566 } 567 } 568 } 569 570 /* 571 * Copy columns. This is slow, and hard to optimize due to alignment, 572 * and the fact that we have to copy both left->right and right->left. 573 * We simply cop-out here and use memmove(), since it handles all of 574 * these cases anyway. 575 */ 576 void 577 rasops_copycols(cookie, row, src, dst, num) 578 void *cookie; 579 int row, src, dst, num; 580 { 581 struct rasops_info *ri; 582 u_char *sp, *dp, *hp; 583 int height; 584 585 ri = (struct rasops_info *)cookie; 586 hp = NULL; 587 588 #ifdef RASOPS_CLIPPING 589 if (dst == src) 590 return; 591 592 /* Catches < 0 case too */ 593 if ((unsigned)row >= (unsigned)ri->ri_rows) 594 return; 595 596 if (src < 0) { 597 num += src; 598 src = 0; 599 } 600 601 if ((src + num) > ri->ri_cols) 602 num = ri->ri_cols - src; 603 604 if (dst < 0) { 605 num += dst; 606 dst = 0; 607 } 608 609 if ((dst + num) > ri->ri_cols) 610 num = ri->ri_cols - dst; 611 612 if (num <= 0) 613 return; 614 #endif 615 616 num *= ri->ri_xscale; 617 row *= ri->ri_yscale; 618 height = ri->ri_font->fontheight; 619 620 sp = ri->ri_bits + row + src * ri->ri_xscale; 621 dp = ri->ri_bits + row + dst * ri->ri_xscale; 622 if (ri->ri_hwbits) 623 hp = ri->ri_hwbits + row + dst * ri->ri_xscale; 624 625 while (height--) { 626 memmove(dp, sp, num); 627 if (ri->ri_hwbits) { 628 memcpy(hp, sp, num); 629 hp += ri->ri_stride; 630 } 631 dp += ri->ri_stride; 632 sp += ri->ri_stride; 633 } 634 } 635 636 /* 637 * Turn cursor off/on. 638 */ 639 static void 640 rasops_cursor(cookie, on, row, col) 641 void *cookie; 642 int on, row, col; 643 { 644 struct rasops_info *ri; 645 646 ri = (struct rasops_info *)cookie; 647 648 /* Turn old cursor off */ 649 if ((ri->ri_flg & RI_CURSOR) != 0) 650 #ifdef RASOPS_CLIPPING 651 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 652 #endif 653 ri->ri_do_cursor(ri); 654 655 /* Select new cursor */ 656 #ifdef RASOPS_CLIPPING 657 ri->ri_flg &= ~RI_CURSORCLIP; 658 659 if (row < 0 || row >= ri->ri_rows) 660 ri->ri_flg |= RI_CURSORCLIP; 661 else if (col < 0 || col >= ri->ri_cols) 662 ri->ri_flg |= RI_CURSORCLIP; 663 #endif 664 ri->ri_crow = row; 665 ri->ri_ccol = col; 666 667 if (on) { 668 ri->ri_flg |= RI_CURSOR; 669 #ifdef RASOPS_CLIPPING 670 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 671 #endif 672 ri->ri_do_cursor(ri); 673 } else 674 ri->ri_flg &= ~RI_CURSOR; 675 } 676 677 /* 678 * Make the device colormap 679 */ 680 static void 681 rasops_init_devcmap(ri) 682 struct rasops_info *ri; 683 { 684 const u_char *p; 685 int i, c; 686 687 switch (ri->ri_depth) { 688 case 1: 689 ri->ri_devcmap[0] = 0; 690 for (i = 1; i < 16; i++) 691 ri->ri_devcmap[i] = -1; 692 return; 693 694 case 2: 695 for (i = 1; i < 15; i++) 696 ri->ri_devcmap[i] = 0xaaaaaaaa; 697 698 ri->ri_devcmap[0] = 0; 699 ri->ri_devcmap[8] = 0x55555555; 700 ri->ri_devcmap[15] = -1; 701 return; 702 703 case 8: 704 for (i = 0; i < 16; i++) 705 ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24); 706 return; 707 } 708 709 p = rasops_cmap; 710 711 for (i = 0; i < 16; i++) { 712 if (ri->ri_rnum <= 8) 713 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 714 else 715 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 716 p++; 717 718 if (ri->ri_gnum <= 8) 719 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 720 else 721 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 722 p++; 723 724 if (ri->ri_bnum <= 8) 725 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 726 else 727 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 728 p++; 729 730 /* Fill the word for generic routines, which want this */ 731 if (ri->ri_depth == 24) 732 c = c | ((c & 0xff) << 24); 733 else if (ri->ri_depth <= 16) 734 c = c | (c << 16); 735 736 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 737 if ((ri->ri_flg & RI_BSWAP) == 0) 738 ri->ri_devcmap[i] = c; 739 else if (ri->ri_depth == 32) 740 ri->ri_devcmap[i] = bswap32(c); 741 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 742 ri->ri_devcmap[i] = bswap16(c); 743 else 744 ri->ri_devcmap[i] = c; 745 } 746 } 747 748 /* 749 * Unpack a rasops attribute 750 */ 751 void 752 rasops_unpack_attr(attr, fg, bg, underline) 753 long attr; 754 int *fg, *bg, *underline; 755 { 756 757 *fg = ((u_int)attr >> 24) & 0xf; 758 *bg = ((u_int)attr >> 16) & 0xf; 759 if (underline != NULL) 760 *underline = (u_int)attr & 1; 761 } 762 763 /* 764 * Erase rows. This isn't static, since 24-bpp uses it in special cases. 765 */ 766 void 767 rasops_eraserows(cookie, row, num, attr) 768 void *cookie; 769 int row, num; 770 long attr; 771 { 772 struct rasops_info *ri; 773 int np, nw, cnt, delta; 774 int32_t *dp, *hp, clr; 775 int i; 776 777 ri = (struct rasops_info *)cookie; 778 hp = NULL; 779 780 #ifdef RASOPS_CLIPPING 781 if (row < 0) { 782 num += row; 783 row = 0; 784 } 785 786 if ((row + num) > ri->ri_rows) 787 num = ri->ri_rows - row; 788 789 if (num <= 0) 790 return; 791 #endif 792 793 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 794 795 /* 796 * XXX The wsdisplay_emulops interface seems a little deficient in 797 * that there is no way to clear the *entire* screen. We provide a 798 * workaround here: if the entire console area is being cleared, and 799 * the RI_FULLCLEAR flag is set, clear the entire display. 800 */ 801 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 802 np = ri->ri_stride >> 5; 803 nw = (ri->ri_stride >> 2) & 7; 804 num = ri->ri_height; 805 dp = (int32_t *)ri->ri_origbits; 806 if (ri->ri_hwbits) 807 hp = (int32_t *)ri->ri_hwbits; 808 delta = 0; 809 } else { 810 np = ri->ri_emustride >> 5; 811 nw = (ri->ri_emustride >> 2) & 7; 812 num *= ri->ri_font->fontheight; 813 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 814 if (ri->ri_hwbits) 815 hp = (int32_t *)(ri->ri_hwbits + row * 816 ri->ri_yscale); 817 delta = ri->ri_delta; 818 } 819 820 while (num--) { 821 for (cnt = np; cnt; cnt--) { 822 for (i = 0; i < 8; i++) { 823 dp[i] = clr; 824 if (ri->ri_hwbits) 825 hp[i] = clr; 826 } 827 dp += 8; 828 if (ri->ri_hwbits) 829 hp += 8; 830 } 831 832 for (cnt = nw; cnt; cnt--) { 833 *(int32_t *)dp = clr; 834 DELTA(dp, 4, int32_t *); 835 if (ri->ri_hwbits) { 836 *(int32_t *)hp = clr; 837 DELTA(hp, 4, int32_t *); 838 } 839 } 840 841 DELTA(dp, delta, int32_t *); 842 if (ri->ri_hwbits) 843 DELTA(hp, delta, int32_t *); 844 } 845 } 846 847 /* 848 * Actually turn the cursor on or off. This does the dirty work for 849 * rasops_cursor(). 850 */ 851 static void 852 rasops_do_cursor(ri) 853 struct rasops_info *ri; 854 { 855 int full1, height, cnt, slop1, slop2, row, col; 856 u_char *dp, *rp, *hrp, *hp; 857 858 hrp = hp = NULL; 859 860 row = ri->ri_crow; 861 col = ri->ri_ccol; 862 863 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 864 if (ri->ri_hwbits) 865 hrp = ri->ri_hwbits + row * ri->ri_yscale + col 866 * ri->ri_xscale; 867 height = ri->ri_font->fontheight; 868 slop1 = (4 - ((long)rp & 3)) & 3; 869 870 if (slop1 > ri->ri_xscale) 871 slop1 = ri->ri_xscale; 872 873 slop2 = (ri->ri_xscale - slop1) & 3; 874 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 875 876 if ((slop1 | slop2) == 0) { 877 /* A common case */ 878 while (height--) { 879 dp = rp; 880 rp += ri->ri_stride; 881 if (ri->ri_hwbits) { 882 hp = hrp; 883 hrp += ri->ri_stride; 884 } 885 886 for (cnt = full1; cnt; cnt--) { 887 *(int32_t *)dp ^= ~0; 888 dp += 4; 889 if (ri->ri_hwbits) { 890 *(int32_t *)hp ^= ~0; 891 hp += 4; 892 } 893 } 894 } 895 } else { 896 /* XXX this is stupid.. use masks instead */ 897 while (height--) { 898 dp = rp; 899 rp += ri->ri_stride; 900 if (ri->ri_hwbits) { 901 hp = hrp; 902 hrp += ri->ri_stride; 903 } 904 905 if (slop1 & 1) { 906 *dp++ ^= ~0; 907 if (ri->ri_hwbits) 908 *hp++ ^= ~0; 909 } 910 911 if (slop1 & 2) { 912 *(int16_t *)dp ^= ~0; 913 dp += 2; 914 if (ri->ri_hwbits) { 915 *(int16_t *)hp ^= ~0; 916 hp += 2; 917 } 918 } 919 920 for (cnt = full1; cnt; cnt--) { 921 *(int32_t *)dp ^= ~0; 922 dp += 4; 923 if (ri->ri_hwbits) { 924 *(int32_t *)hp ^= ~0; 925 hp += 4; 926 } 927 } 928 929 if (slop2 & 1) { 930 *dp++ ^= ~0; 931 if (ri->ri_hwbits) 932 *hp++ ^= ~0; 933 } 934 935 if (slop2 & 2) { 936 *(int16_t *)dp ^= ~0; 937 if (ri->ri_hwbits) 938 *(int16_t *)hp ^= ~0; 939 } 940 } 941 } 942 } 943 944 /* 945 * Erase columns. 946 */ 947 void 948 rasops_erasecols(cookie, row, col, num, attr) 949 void *cookie; 950 int row, col, num; 951 long attr; 952 { 953 int n8, height, cnt, slop1, slop2, clr; 954 struct rasops_info *ri; 955 int32_t *rp, *dp, *hrp, *hp; 956 int i; 957 958 ri = (struct rasops_info *)cookie; 959 hrp = hp = NULL; 960 961 #ifdef RASOPS_CLIPPING 962 if ((unsigned)row >= (unsigned)ri->ri_rows) 963 return; 964 965 if (col < 0) { 966 num += col; 967 col = 0; 968 } 969 970 if ((col + num) > ri->ri_cols) 971 num = ri->ri_cols - col; 972 973 if (num <= 0) 974 return; 975 #endif 976 977 num = num * ri->ri_xscale; 978 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 979 if (ri->ri_hwbits) 980 hrp = (int32_t *)(ri->ri_hwbits + row*ri->ri_yscale + 981 col*ri->ri_xscale); 982 height = ri->ri_font->fontheight; 983 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 984 985 /* Don't bother using the full loop for <= 32 pels */ 986 if (num <= 32) { 987 if (((num | ri->ri_xscale) & 3) == 0) { 988 /* Word aligned blt */ 989 num >>= 2; 990 991 while (height--) { 992 dp = rp; 993 DELTA(rp, ri->ri_stride, int32_t *); 994 if (ri->ri_hwbits) { 995 hp = hrp; 996 DELTA(hrp, ri->ri_stride, int32_t *); 997 } 998 999 for (cnt = num; cnt; cnt--) { 1000 *dp++ = clr; 1001 if (ri->ri_hwbits) 1002 *hp++ = clr; 1003 } 1004 } 1005 } else if (((num | ri->ri_xscale) & 1) == 0) { 1006 /* 1007 * Halfword aligned blt. This is needed so the 1008 * 15/16 bit ops can use this function. 1009 */ 1010 num >>= 1; 1011 1012 while (height--) { 1013 dp = rp; 1014 DELTA(rp, ri->ri_stride, int32_t *); 1015 if (ri->ri_hwbits) { 1016 hp = hrp; 1017 DELTA(hrp, ri->ri_stride, int32_t *); 1018 } 1019 1020 for (cnt = num; cnt; cnt--) { 1021 *(int16_t *)dp = clr; 1022 DELTA(dp, 2, int32_t *); 1023 if (ri->ri_hwbits) { 1024 *(int16_t *)hp = clr; 1025 DELTA(hp, 2, int32_t *); 1026 } 1027 } 1028 } 1029 } else { 1030 while (height--) { 1031 dp = rp; 1032 DELTA(rp, ri->ri_stride, int32_t *); 1033 if (ri->ri_hwbits) { 1034 hp = hrp; 1035 DELTA(hrp, ri->ri_stride, int32_t *); 1036 } 1037 1038 for (cnt = num; cnt; cnt--) { 1039 *(u_char *)dp = clr; 1040 DELTA(dp, 1, int32_t *); 1041 if (ri->ri_hwbits) { 1042 *(u_char *)hp = clr; 1043 DELTA(hp, 1, int32_t *); 1044 } 1045 } 1046 } 1047 } 1048 1049 return; 1050 } 1051 1052 slop1 = (4 - ((long)rp & 3)) & 3; 1053 slop2 = (num - slop1) & 3; 1054 num -= slop1 + slop2; 1055 n8 = num >> 5; 1056 num = (num >> 2) & 7; 1057 1058 while (height--) { 1059 dp = rp; 1060 DELTA(rp, ri->ri_stride, int32_t *); 1061 if (ri->ri_hwbits) { 1062 hp = hrp; 1063 DELTA(hrp, ri->ri_stride, int32_t *); 1064 } 1065 1066 /* Align span to 4 bytes */ 1067 if (slop1 & 1) { 1068 *(u_char *)dp = clr; 1069 DELTA(dp, 1, int32_t *); 1070 if (ri->ri_hwbits) { 1071 *(u_char *)hp = clr; 1072 DELTA(hp, 1, int32_t *); 1073 } 1074 } 1075 1076 if (slop1 & 2) { 1077 *(int16_t *)dp = clr; 1078 DELTA(dp, 2, int32_t *); 1079 if (ri->ri_hwbits) { 1080 *(int16_t *)hp = clr; 1081 DELTA(hp, 2, int32_t *); 1082 } 1083 } 1084 1085 /* Write 32 bytes per loop */ 1086 for (cnt = n8; cnt; cnt--) { 1087 for (i = 0; i < 8; i++) { 1088 dp[i] = clr; 1089 if (ri->ri_hwbits) 1090 hp[i] = clr; 1091 } 1092 dp += 8; 1093 if (ri->ri_hwbits) 1094 hp += 8; 1095 } 1096 1097 /* Write 4 bytes per loop */ 1098 for (cnt = num; cnt; cnt--) { 1099 *dp++ = clr; 1100 if (ri->ri_hwbits) 1101 *hp++ = clr; 1102 } 1103 1104 /* Write unaligned trailing slop */ 1105 if (slop2 & 1) { 1106 *(u_char *)dp = clr; 1107 DELTA(dp, 1, int32_t *); 1108 if (ri->ri_hwbits) { 1109 *(u_char *)hp = clr; 1110 DELTA(hp, 1, int32_t *); 1111 } 1112 } 1113 1114 if (slop2 & 2) { 1115 *(int16_t *)dp = clr; 1116 if (ri->ri_hwbits) 1117 *(int16_t *)hp = clr; 1118 } 1119 } 1120 } 1121