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