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