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