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