1 /* $OpenBSD: rasops.c,v 1.31 2014/07/12 18:48:52 tedu 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/malloc.h> 35 #include <sys/systm.h> 36 #include <sys/time.h> 37 #include <sys/workq.h> 38 39 #include <machine/endian.h> 40 41 #include <dev/wscons/wsdisplayvar.h> 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/wsfont/wsfont.h> 44 #include <dev/rasops/rasops.h> 45 46 #ifndef _KERNEL 47 #include <errno.h> 48 #endif 49 50 /* ANSI colormap (R,G,B) */ 51 52 #define NORMAL_BLACK 0x000000 53 #define NORMAL_RED 0x7f0000 54 #define NORMAL_GREEN 0x007f00 55 #define NORMAL_BROWN 0x7f7f00 56 #define NORMAL_BLUE 0x00007f 57 #define NORMAL_MAGENTA 0x7f007f 58 #define NORMAL_CYAN 0x007f7f 59 #define NORMAL_WHITE 0xc7c7c7 /* XXX too dim? */ 60 61 #define HILITE_BLACK 0x7f7f7f 62 #define HILITE_RED 0xff0000 63 #define HILITE_GREEN 0x00ff00 64 #define HILITE_BROWN 0xffff00 65 #define HILITE_BLUE 0x0000ff 66 #define HILITE_MAGENTA 0xff00ff 67 #define HILITE_CYAN 0x00ffff 68 #define HILITE_WHITE 0xffffff 69 70 const u_char rasops_cmap[256 * 3] = { 71 #define _C(x) ((x) & 0xff0000) >> 16, ((x) & 0x00ff00) >> 8, ((x) & 0x0000ff) 72 73 _C(NORMAL_BLACK), 74 _C(NORMAL_RED), 75 _C(NORMAL_GREEN), 76 _C(NORMAL_BROWN), 77 _C(NORMAL_BLUE), 78 _C(NORMAL_MAGENTA), 79 _C(NORMAL_CYAN), 80 _C(NORMAL_WHITE), 81 82 _C(HILITE_BLACK), 83 _C(HILITE_RED), 84 _C(HILITE_GREEN), 85 _C(HILITE_BROWN), 86 _C(HILITE_BLUE), 87 _C(HILITE_MAGENTA), 88 _C(HILITE_CYAN), 89 _C(HILITE_WHITE), 90 91 /* 92 * For the cursor, we need the last 16 colors to be the 93 * opposite of the first 16. Fill the intermediate space with 94 * white completely for simplicity. 95 */ 96 #define _CMWHITE16 \ 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 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \ 100 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), 101 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 102 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 103 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 104 #undef _CMWHITE16 105 106 _C(~HILITE_WHITE), 107 _C(~HILITE_CYAN), 108 _C(~HILITE_MAGENTA), 109 _C(~HILITE_BLUE), 110 _C(~HILITE_BROWN), 111 _C(~HILITE_GREEN), 112 _C(~HILITE_RED), 113 _C(~HILITE_BLACK), 114 115 _C(~NORMAL_WHITE), 116 _C(~NORMAL_CYAN), 117 _C(~NORMAL_MAGENTA), 118 _C(~NORMAL_BLUE), 119 _C(~NORMAL_BROWN), 120 _C(~NORMAL_GREEN), 121 _C(~NORMAL_RED), 122 _C(~NORMAL_BLACK), 123 124 #undef _C 125 }; 126 127 /* True if color is gray */ 128 const u_char rasops_isgray[16] = { 129 1, 0, 0, 0, 130 0, 0, 0, 1, 131 1, 0, 0, 0, 132 0, 0, 0, 1 133 }; 134 135 /* Generic functions */ 136 int rasops_copycols(void *, int, int, int, int); 137 int rasops_copyrows(void *, int, int, int); 138 int rasops_mapchar(void *, int, u_int *); 139 int rasops_cursor(void *, int, int, int); 140 int rasops_alloc_cattr(void *, int, int, int, long *); 141 int rasops_alloc_mattr(void *, int, int, int, long *); 142 int rasops_do_cursor(struct rasops_info *); 143 void rasops_init_devcmap(struct rasops_info *); 144 void rasops_unpack_attr(void *, long, int *, int *, int *); 145 #if NRASOPS_BSWAP > 0 146 static void slow_ovbcopy(void *, void *, size_t); 147 #endif 148 #if NRASOPS_ROTATION > 0 149 void rasops_copychar(void *, int, int, int, int); 150 int rasops_copycols_rotated(void *, int, int, int, int); 151 int rasops_copyrows_rotated(void *, int, int, int); 152 int rasops_erasecols_rotated(void *, int, int, int, long); 153 int rasops_eraserows_rotated(void *, int, int, long); 154 int rasops_putchar_rotated(void *, int, int, u_int, long); 155 void rasops_rotate_font(int *); 156 157 /* 158 * List of all rotated fonts 159 */ 160 SLIST_HEAD(, rotatedfont) rotatedfonts = SLIST_HEAD_INITIALIZER(rotatedfonts); 161 struct rotatedfont { 162 SLIST_ENTRY(rotatedfont) rf_next; 163 int rf_cookie; 164 int rf_rotated; 165 }; 166 #endif 167 168 void rasops_doswitch(void *, void *); 169 int rasops_vcons_cursor(void *, int, int, int); 170 int rasops_vcons_mapchar(void *, int, u_int *); 171 int rasops_vcons_putchar(void *, int, int, u_int, long); 172 int rasops_vcons_copycols(void *, int, int, int, int); 173 int rasops_vcons_erasecols(void *, int, int, int, long); 174 int rasops_vcons_copyrows(void *, int, int, int); 175 int rasops_vcons_eraserows(void *, int, int, long); 176 int rasops_vcons_alloc_attr(void *, int, int, int, long *); 177 void rasops_vcons_unpack_attr(void *, long, int *, int *, int *); 178 179 int rasops_add_font(struct rasops_info *, struct wsdisplay_font *); 180 int rasops_use_font(struct rasops_info *, struct wsdisplay_font *); 181 int rasops_list_font_cb(void *, struct wsdisplay_font *); 182 183 /* 184 * Initialize a 'rasops_info' descriptor. 185 */ 186 int 187 rasops_init(struct rasops_info *ri, int wantrows, int wantcols) 188 { 189 190 #ifdef _KERNEL 191 /* Select a font if the caller doesn't care */ 192 if (ri->ri_font == NULL) { 193 int cookie; 194 195 wsfont_init(); 196 197 if (ri->ri_width > 80*12) 198 /* High res screen, choose a big font */ 199 cookie = wsfont_find(NULL, 12, 0, 0); 200 else 201 /* lower res, choose a 8 pixel wide font */ 202 cookie = wsfont_find(NULL, 8, 0, 0); 203 204 if (cookie <= 0) 205 cookie = wsfont_find(NULL, 0, 0, 0); 206 207 if (cookie <= 0) { 208 printf("rasops_init: font table is empty\n"); 209 return (-1); 210 } 211 212 #if NRASOPS_ROTATION > 0 213 /* 214 * Pick the rotated version of this font. This will create it 215 * if necessary. 216 */ 217 if (ri->ri_flg & RI_ROTATE_CW) 218 rasops_rotate_font(&cookie); 219 #endif 220 221 if (wsfont_lock(cookie, &ri->ri_font, 222 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) { 223 printf("rasops_init: couldn't lock font\n"); 224 return (-1); 225 } 226 227 ri->ri_wsfcookie = cookie; 228 } 229 #endif 230 231 /* This should never happen in reality... */ 232 #ifdef DEBUG 233 if ((long)ri->ri_bits & 3) { 234 printf("rasops_init: bits not aligned on 32-bit boundary\n"); 235 return (-1); 236 } 237 238 if ((int)ri->ri_stride & 3) { 239 printf("rasops_init: stride not aligned on 32-bit boundary\n"); 240 return (-1); 241 } 242 #endif 243 244 if (rasops_reconfig(ri, wantrows, wantcols)) 245 return (-1); 246 247 LIST_INIT(&ri->ri_screens); 248 ri->ri_nscreens = 0; 249 250 ri->ri_putchar = ri->ri_ops.putchar; 251 ri->ri_copycols = ri->ri_ops.copycols; 252 ri->ri_erasecols = ri->ri_ops.erasecols; 253 ri->ri_copyrows = ri->ri_ops.copyrows; 254 ri->ri_eraserows = ri->ri_ops.eraserows; 255 ri->ri_alloc_attr = ri->ri_ops.alloc_attr; 256 257 if (ri->ri_flg & RI_VCONS) { 258 void *cookie; 259 int curx, cury; 260 long attr; 261 262 if (rasops_alloc_screen(ri, &cookie, &curx, &cury, &attr)) 263 return (-1); 264 265 ri->ri_active = cookie; 266 267 ri->ri_ops.cursor = rasops_vcons_cursor; 268 ri->ri_ops.mapchar = rasops_vcons_mapchar; 269 ri->ri_ops.putchar = rasops_vcons_putchar; 270 ri->ri_ops.copycols = rasops_vcons_copycols; 271 ri->ri_ops.erasecols = rasops_vcons_erasecols; 272 ri->ri_ops.copyrows = rasops_vcons_copyrows; 273 ri->ri_ops.eraserows = rasops_vcons_eraserows; 274 ri->ri_ops.alloc_attr = rasops_vcons_alloc_attr; 275 ri->ri_ops.unpack_attr = rasops_vcons_unpack_attr; 276 } 277 278 rasops_init_devcmap(ri); 279 return (0); 280 } 281 282 /* 283 * Reconfigure (because parameters have changed in some way). 284 */ 285 int 286 rasops_reconfig(struct rasops_info *ri, int wantrows, int wantcols) 287 { 288 int l, bpp, s; 289 290 s = splhigh(); 291 292 if (ri->ri_font->fontwidth > 32 || ri->ri_font->fontwidth < 4) 293 panic("rasops_init: fontwidth assumptions botched!"); 294 295 /* Need this to frob the setup below */ 296 bpp = (ri->ri_depth == 15 ? 16 : ri->ri_depth); 297 298 if ((ri->ri_flg & RI_CFGDONE) != 0) 299 ri->ri_bits = ri->ri_origbits; 300 301 /* Don't care if the caller wants a hideously small console */ 302 if (wantrows < 10) 303 wantrows = 10; 304 305 if (wantcols < 20) 306 wantcols = 20; 307 308 /* Now constrain what they get */ 309 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 310 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 311 312 if (ri->ri_emuwidth > ri->ri_width) 313 ri->ri_emuwidth = ri->ri_width; 314 315 if (ri->ri_emuheight > ri->ri_height) 316 ri->ri_emuheight = ri->ri_height; 317 318 /* Reduce width until aligned on a 32-bit boundary */ 319 while ((ri->ri_emuwidth * bpp & 31) != 0) 320 ri->ri_emuwidth--; 321 322 #if NRASOPS_ROTATION > 0 323 if (ri->ri_flg & RI_ROTATE_CW) { 324 ri->ri_rows = ri->ri_emuwidth / ri->ri_font->fontwidth; 325 ri->ri_cols = ri->ri_emuheight / ri->ri_font->fontheight; 326 } else 327 #endif 328 { 329 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 330 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 331 } 332 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 333 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 334 ri->ri_ccol = 0; 335 ri->ri_crow = 0; 336 ri->ri_pelbytes = bpp >> 3; 337 338 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 339 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 340 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 341 342 #ifdef DEBUG 343 if ((ri->ri_delta & 3) != 0) 344 panic("rasops_init: ri_delta not aligned on 32-bit boundary"); 345 #endif 346 /* Clear the entire display */ 347 if ((ri->ri_flg & RI_CLEAR) != 0) { 348 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 349 ri->ri_flg &= ~RI_CLEARMARGINS; 350 } 351 352 /* Now centre our window if needs be */ 353 ri->ri_origbits = ri->ri_bits; 354 355 if ((ri->ri_flg & RI_CENTER) != 0) { 356 ri->ri_bits += (((ri->ri_width * bpp >> 3) - 357 ri->ri_emustride) >> 1) & ~3; 358 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 359 ri->ri_stride; 360 361 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) 362 / ri->ri_stride; 363 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) 364 % ri->ri_stride) * 8 / bpp); 365 } else 366 ri->ri_xorigin = ri->ri_yorigin = 0; 367 368 /* Clear the margins */ 369 if ((ri->ri_flg & RI_CLEARMARGINS) != 0) { 370 memset(ri->ri_origbits, 0, ri->ri_bits - ri->ri_origbits); 371 for (l = 0; l < ri->ri_emuheight; l++) 372 memset(ri->ri_bits + ri->ri_emustride + 373 l * ri->ri_stride, 0, 374 ri->ri_stride - ri->ri_emustride); 375 memset(ri->ri_bits + ri->ri_emuheight * ri->ri_stride, 0, 376 (ri->ri_origbits + ri->ri_height * ri->ri_stride) - 377 (ri->ri_bits + ri->ri_emuheight * ri->ri_stride)); 378 } 379 380 /* 381 * Fill in defaults for operations set. XXX this nukes private 382 * routines used by accelerated fb drivers. 383 */ 384 ri->ri_ops.mapchar = rasops_mapchar; 385 ri->ri_ops.copyrows = rasops_copyrows; 386 ri->ri_ops.copycols = rasops_copycols; 387 ri->ri_ops.erasecols = rasops_erasecols; 388 ri->ri_ops.eraserows = rasops_eraserows; 389 ri->ri_ops.cursor = rasops_cursor; 390 ri->ri_ops.unpack_attr = rasops_unpack_attr; 391 ri->ri_do_cursor = rasops_do_cursor; 392 ri->ri_updatecursor = NULL; 393 394 if (ri->ri_depth < 8 || (ri->ri_flg & RI_FORCEMONO) != 0) { 395 ri->ri_ops.alloc_attr = rasops_alloc_mattr; 396 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_REVERSE; 397 } else { 398 ri->ri_ops.alloc_attr = rasops_alloc_cattr; 399 ri->ri_caps = WSSCREEN_UNDERLINE | WSSCREEN_HILIT | 400 WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; 401 } 402 403 switch (ri->ri_depth) { 404 #if NRASOPS1 > 0 405 case 1: 406 rasops1_init(ri); 407 break; 408 #endif 409 #if NRASOPS2 > 0 410 case 2: 411 rasops2_init(ri); 412 break; 413 #endif 414 #if NRASOPS4 > 0 415 case 4: 416 rasops4_init(ri); 417 break; 418 #endif 419 #if NRASOPS8 > 0 420 case 8: 421 rasops8_init(ri); 422 break; 423 #endif 424 #if NRASOPS15 > 0 || NRASOPS16 > 0 425 case 15: 426 case 16: 427 rasops15_init(ri); 428 break; 429 #endif 430 #if NRASOPS24 > 0 431 case 24: 432 rasops24_init(ri); 433 break; 434 #endif 435 #if NRASOPS32 > 0 436 case 32: 437 rasops32_init(ri); 438 break; 439 #endif 440 default: 441 ri->ri_flg &= ~RI_CFGDONE; 442 splx(s); 443 return (-1); 444 } 445 446 #if NRASOPS_ROTATION > 0 447 if (ri->ri_flg & RI_ROTATE_CW) { 448 ri->ri_real_ops = ri->ri_ops; 449 ri->ri_ops.copycols = rasops_copycols_rotated; 450 ri->ri_ops.copyrows = rasops_copyrows_rotated; 451 ri->ri_ops.erasecols = rasops_erasecols_rotated; 452 ri->ri_ops.eraserows = rasops_eraserows_rotated; 453 ri->ri_ops.putchar = rasops_putchar_rotated; 454 } 455 #endif 456 457 ri->ri_flg |= RI_CFGDONE; 458 splx(s); 459 return (0); 460 } 461 462 /* 463 * Map a character. 464 */ 465 int 466 rasops_mapchar(void *cookie, int c, u_int *cp) 467 { 468 struct rasops_info *ri; 469 470 ri = (struct rasops_info *)cookie; 471 472 #ifdef DIAGNOSTIC 473 if (ri->ri_font == NULL) 474 panic("rasops_mapchar: no font selected"); 475 #endif 476 if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) { 477 478 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 479 480 *cp = '?'; 481 return (0); 482 483 } 484 } 485 486 487 if (c < ri->ri_font->firstchar) { 488 *cp = '?'; 489 return (0); 490 } 491 492 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 493 *cp = '?'; 494 return (0); 495 } 496 497 *cp = c; 498 return (5); 499 } 500 501 /* 502 * Allocate a color attribute. 503 */ 504 int 505 rasops_alloc_cattr(void *cookie, int fg, int bg, int flg, long *attr) 506 { 507 int swap; 508 509 #ifdef RASOPS_CLIPPING 510 fg &= 7; 511 bg &= 7; 512 #endif 513 if ((flg & WSATTR_BLINK) != 0) 514 return (EINVAL); 515 516 if ((flg & WSATTR_WSCOLORS) == 0) { 517 fg = WS_DEFAULT_FG; 518 bg = WS_DEFAULT_BG; 519 } 520 521 if ((flg & WSATTR_REVERSE) != 0) { 522 swap = fg; 523 fg = bg; 524 bg = swap; 525 } 526 527 if ((flg & WSATTR_HILIT) != 0) 528 fg += 8; 529 530 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 531 532 if (rasops_isgray[fg]) 533 flg |= 2; 534 535 if (rasops_isgray[bg]) 536 flg |= 4; 537 538 *attr = (bg << 16) | (fg << 24) | flg; 539 return (0); 540 } 541 542 /* 543 * Allocate a mono attribute. 544 */ 545 int 546 rasops_alloc_mattr(void *cookie, int fg, int bg, int flg, long *attr) 547 { 548 int swap; 549 550 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 551 return (EINVAL); 552 553 fg = 1; 554 bg = 0; 555 556 if ((flg & WSATTR_REVERSE) != 0) { 557 swap = fg; 558 fg = bg; 559 bg = swap; 560 } 561 562 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 563 return (0); 564 } 565 566 /* 567 * Copy rows. 568 */ 569 int 570 rasops_copyrows(void *cookie, int src, int dst, int num) 571 { 572 int32_t *sp, *dp, *srp, *drp; 573 struct rasops_info *ri; 574 int n8, n1, cnt, delta; 575 576 ri = (struct rasops_info *)cookie; 577 578 #ifdef RASOPS_CLIPPING 579 if (dst == src) 580 return 0; 581 582 if (src < 0) { 583 num += src; 584 src = 0; 585 } 586 587 if ((src + num) > ri->ri_rows) 588 num = ri->ri_rows - src; 589 590 if (dst < 0) { 591 num += dst; 592 dst = 0; 593 } 594 595 if ((dst + num) > ri->ri_rows) 596 num = ri->ri_rows - dst; 597 598 if (num <= 0) 599 return 0; 600 #endif 601 602 num *= ri->ri_font->fontheight; 603 n8 = ri->ri_emustride >> 5; 604 n1 = (ri->ri_emustride >> 2) & 7; 605 606 if (dst < src) { 607 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 608 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 609 delta = ri->ri_stride; 610 } else { 611 src = ri->ri_font->fontheight * src + num - 1; 612 dst = ri->ri_font->fontheight * dst + num - 1; 613 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 614 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 615 delta = -ri->ri_stride; 616 } 617 618 while (num--) { 619 dp = drp; 620 sp = srp; 621 DELTA(drp, delta, int32_t *); 622 DELTA(srp, delta, int32_t *); 623 624 for (cnt = n8; cnt; cnt--) { 625 dp[0] = sp[0]; 626 dp[1] = sp[1]; 627 dp[2] = sp[2]; 628 dp[3] = sp[3]; 629 dp[4] = sp[4]; 630 dp[5] = sp[5]; 631 dp[6] = sp[6]; 632 dp[7] = sp[7]; 633 dp += 8; 634 sp += 8; 635 } 636 637 for (cnt = n1; cnt; cnt--) 638 *dp++ = *sp++; 639 } 640 641 return 0; 642 } 643 644 /* 645 * Copy columns. This is slow, and hard to optimize due to alignment, 646 * and the fact that we have to copy both left->right and right->left. 647 * We simply cop-out here and use ovbcopy(), since it handles all of 648 * these cases anyway. 649 */ 650 int 651 rasops_copycols(void *cookie, int row, int src, int dst, int num) 652 { 653 struct rasops_info *ri; 654 u_char *sp, *dp; 655 int height; 656 657 ri = (struct rasops_info *)cookie; 658 659 #ifdef RASOPS_CLIPPING 660 if (dst == src) 661 return 0; 662 663 /* Catches < 0 case too */ 664 if ((unsigned)row >= (unsigned)ri->ri_rows) 665 return 0; 666 667 if (src < 0) { 668 num += src; 669 src = 0; 670 } 671 672 if ((src + num) > ri->ri_cols) 673 num = ri->ri_cols - src; 674 675 if (dst < 0) { 676 num += dst; 677 dst = 0; 678 } 679 680 if ((dst + num) > ri->ri_cols) 681 num = ri->ri_cols - dst; 682 683 if (num <= 0) 684 return 0; 685 #endif 686 687 num *= ri->ri_xscale; 688 row *= ri->ri_yscale; 689 height = ri->ri_font->fontheight; 690 691 sp = ri->ri_bits + row + src * ri->ri_xscale; 692 dp = ri->ri_bits + row + dst * ri->ri_xscale; 693 694 #if NRASOPS_BSWAP > 0 695 if (ri->ri_flg & RI_BSWAP) { 696 while (height--) { 697 slow_ovbcopy(sp, dp, num); 698 dp += ri->ri_stride; 699 sp += ri->ri_stride; 700 } 701 } else 702 #endif 703 { 704 while (height--) { 705 memmove(dp, sp, num); 706 dp += ri->ri_stride; 707 sp += ri->ri_stride; 708 } 709 } 710 711 return 0; 712 } 713 714 /* 715 * Turn cursor off/on. 716 */ 717 int 718 rasops_cursor(void *cookie, int on, int row, int col) 719 { 720 struct rasops_info *ri; 721 int rc; 722 723 ri = (struct rasops_info *)cookie; 724 725 /* Turn old cursor off */ 726 if ((ri->ri_flg & RI_CURSOR) != 0) { 727 #ifdef RASOPS_CLIPPING 728 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 729 #endif 730 if ((rc = ri->ri_do_cursor(ri)) != 0) 731 return rc; 732 ri->ri_flg &= ~RI_CURSOR; 733 } 734 735 /* Select new cursor */ 736 #ifdef RASOPS_CLIPPING 737 ri->ri_flg &= ~RI_CURSORCLIP; 738 739 if (row < 0 || row >= ri->ri_rows) 740 ri->ri_flg |= RI_CURSORCLIP; 741 else if (col < 0 || col >= ri->ri_cols) 742 ri->ri_flg |= RI_CURSORCLIP; 743 #endif 744 ri->ri_crow = row; 745 ri->ri_ccol = col; 746 747 if (ri->ri_updatecursor != NULL) 748 ri->ri_updatecursor(ri); 749 750 if (on) { 751 #ifdef RASOPS_CLIPPING 752 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 753 #endif 754 if ((rc = ri->ri_do_cursor(ri)) != 0) 755 return rc; 756 ri->ri_flg |= RI_CURSOR; 757 } 758 759 return 0; 760 } 761 762 /* 763 * Make the device colormap 764 */ 765 void 766 rasops_init_devcmap(struct rasops_info *ri) 767 { 768 int i; 769 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 770 const u_char *p; 771 #endif 772 #if NRASOPS4 > 0 || NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 773 int c; 774 #endif 775 776 if (ri->ri_depth == 1 || (ri->ri_flg & RI_FORCEMONO) != 0) { 777 ri->ri_devcmap[0] = 0; 778 for (i = 1; i < 16; i++) 779 ri->ri_devcmap[i] = 0xffffffff; 780 return; 781 } 782 783 switch (ri->ri_depth) { 784 #if NRASOPS2 > 0 785 case 2: 786 for (i = 1; i < 15; i++) 787 ri->ri_devcmap[i] = 0xaaaaaaaa; 788 789 ri->ri_devcmap[0] = 0; 790 ri->ri_devcmap[8] = 0x55555555; 791 ri->ri_devcmap[15] = 0xffffffff; 792 return; 793 #endif 794 #if NRASOPS4 > 0 795 case 4: 796 for (i = 0; i < 16; i++) { 797 c = i | (i << 4); 798 ri->ri_devcmap[i] = c | (c<<8) | (c<<16) | (c<<24); 799 } 800 return; 801 #endif 802 #if NRASOPS8 > 0 803 case 8: 804 for (i = 0; i < 16; i++) 805 ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24); 806 return; 807 #endif 808 default: 809 break; 810 } 811 812 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 813 p = rasops_cmap; 814 815 for (i = 0; i < 16; i++) { 816 if (ri->ri_rnum <= 8) 817 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 818 else 819 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 820 p++; 821 822 if (ri->ri_gnum <= 8) 823 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 824 else 825 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 826 p++; 827 828 if (ri->ri_bnum <= 8) 829 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 830 else 831 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 832 p++; 833 834 /* Fill the word for generic routines, which want this */ 835 if (ri->ri_depth == 24) 836 c = c | ((c & 0xff) << 24); 837 else if (ri->ri_depth <= 16) 838 c = c | (c << 16); 839 840 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 841 #if NRASOPS_BSWAP > 0 842 if ((ri->ri_flg & RI_BSWAP) == 0) 843 ri->ri_devcmap[i] = c; 844 else if (ri->ri_depth == 32) 845 ri->ri_devcmap[i] = swap32(c); 846 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 847 ri->ri_devcmap[i] = swap16(c); 848 else 849 ri->ri_devcmap[i] = c; 850 #else 851 ri->ri_devcmap[i] = c; 852 #endif 853 } 854 #endif 855 } 856 857 /* 858 * Unpack a rasops attribute 859 */ 860 void 861 rasops_unpack_attr(void *cookie, long attr, int *fg, int *bg, int *underline) 862 { 863 *fg = ((u_int)attr >> 24) & 0xf; 864 *bg = ((u_int)attr >> 16) & 0xf; 865 if (underline != NULL) 866 *underline = (u_int)attr & 1; 867 } 868 869 /* 870 * Erase rows 871 */ 872 int 873 rasops_eraserows(void *cookie, int row, int num, long attr) 874 { 875 struct rasops_info *ri; 876 int np, nw, cnt, delta; 877 int32_t *dp, clr; 878 879 ri = (struct rasops_info *)cookie; 880 881 #ifdef RASOPS_CLIPPING 882 if (row < 0) { 883 num += row; 884 row = 0; 885 } 886 887 if ((row + num) > ri->ri_rows) 888 num = ri->ri_rows - row; 889 890 if (num <= 0) 891 return 0; 892 #endif 893 894 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 895 896 /* 897 * XXX The wsdisplay_emulops interface seems a little deficient in 898 * that there is no way to clear the *entire* screen. We provide a 899 * workaround here: if the entire console area is being cleared, and 900 * the RI_FULLCLEAR flag is set, clear the entire display. 901 */ 902 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 903 np = ri->ri_stride >> 5; 904 nw = (ri->ri_stride >> 2) & 7; 905 num = ri->ri_height; 906 dp = (int32_t *)ri->ri_origbits; 907 delta = 0; 908 } else { 909 np = ri->ri_emustride >> 5; 910 nw = (ri->ri_emustride >> 2) & 7; 911 num *= ri->ri_font->fontheight; 912 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 913 delta = ri->ri_delta; 914 } 915 916 while (num--) { 917 for (cnt = np; cnt; cnt--) { 918 dp[0] = clr; 919 dp[1] = clr; 920 dp[2] = clr; 921 dp[3] = clr; 922 dp[4] = clr; 923 dp[5] = clr; 924 dp[6] = clr; 925 dp[7] = clr; 926 dp += 8; 927 } 928 929 for (cnt = nw; cnt; cnt--) { 930 *(int32_t *)dp = clr; 931 DELTA(dp, 4, int32_t *); 932 } 933 934 DELTA(dp, delta, int32_t *); 935 } 936 937 return 0; 938 } 939 940 /* 941 * Actually turn the cursor on or off. This does the dirty work for 942 * rasops_cursor(). 943 */ 944 int 945 rasops_do_cursor(struct rasops_info *ri) 946 { 947 int full1, height, cnt, slop1, slop2, row, col; 948 u_char *dp, *rp; 949 950 #if NRASOPS_ROTATION > 0 951 if (ri->ri_flg & RI_ROTATE_CW) { 952 /* Rotate rows/columns */ 953 row = ri->ri_ccol; 954 col = ri->ri_rows - ri->ri_crow - 1; 955 } else 956 #endif 957 { 958 row = ri->ri_crow; 959 col = ri->ri_ccol; 960 } 961 962 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 963 height = ri->ri_font->fontheight; 964 slop1 = (4 - ((long)rp & 3)) & 3; 965 966 if (slop1 > ri->ri_xscale) 967 slop1 = ri->ri_xscale; 968 969 slop2 = (ri->ri_xscale - slop1) & 3; 970 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 971 972 if ((slop1 | slop2) == 0) { 973 /* A common case */ 974 while (height--) { 975 dp = rp; 976 rp += ri->ri_stride; 977 978 for (cnt = full1; cnt; cnt--) { 979 *(int32_t *)dp ^= ~0; 980 dp += 4; 981 } 982 } 983 } else { 984 /* XXX this is stupid.. use masks instead */ 985 while (height--) { 986 dp = rp; 987 rp += ri->ri_stride; 988 989 if (slop1 & 1) 990 *dp++ ^= ~0; 991 992 if (slop1 & 2) { 993 *(int16_t *)dp ^= ~0; 994 dp += 2; 995 } 996 997 for (cnt = full1; cnt; cnt--) { 998 *(int32_t *)dp ^= ~0; 999 dp += 4; 1000 } 1001 1002 if (slop2 & 1) 1003 *dp++ ^= ~0; 1004 1005 if (slop2 & 2) 1006 *(int16_t *)dp ^= ~0; 1007 } 1008 } 1009 1010 return 0; 1011 } 1012 1013 /* 1014 * Erase columns. 1015 */ 1016 int 1017 rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1018 { 1019 int n8, height, cnt, slop1, slop2, clr; 1020 struct rasops_info *ri; 1021 int32_t *rp, *dp; 1022 1023 ri = (struct rasops_info *)cookie; 1024 1025 #ifdef RASOPS_CLIPPING 1026 if ((unsigned)row >= (unsigned)ri->ri_rows) 1027 return 0; 1028 1029 if (col < 0) { 1030 num += col; 1031 col = 0; 1032 } 1033 1034 if ((col + num) > ri->ri_cols) 1035 num = ri->ri_cols - col; 1036 1037 if (num <= 0) 1038 return 0; 1039 #endif 1040 1041 num = num * ri->ri_xscale; 1042 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1043 height = ri->ri_font->fontheight; 1044 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1045 1046 /* Don't bother using the full loop for <= 32 pels */ 1047 if (num <= 32) { 1048 if (((num | ri->ri_xscale) & 3) == 0) { 1049 /* Word aligned blt */ 1050 num >>= 2; 1051 1052 while (height--) { 1053 dp = rp; 1054 DELTA(rp, ri->ri_stride, int32_t *); 1055 1056 for (cnt = num; cnt; cnt--) 1057 *dp++ = clr; 1058 } 1059 } else if (((num | ri->ri_xscale) & 1) == 0) { 1060 /* 1061 * Halfword aligned blt. This is needed so the 1062 * 15/16 bit ops can use this function. 1063 */ 1064 num >>= 1; 1065 1066 while (height--) { 1067 dp = rp; 1068 DELTA(rp, ri->ri_stride, int32_t *); 1069 1070 for (cnt = num; cnt; cnt--) { 1071 *(int16_t *)dp = clr; 1072 DELTA(dp, 2, int32_t *); 1073 } 1074 } 1075 } else { 1076 while (height--) { 1077 dp = rp; 1078 DELTA(rp, ri->ri_stride, int32_t *); 1079 1080 for (cnt = num; cnt; cnt--) { 1081 *(u_char *)dp = clr; 1082 DELTA(dp, 1, int32_t *); 1083 } 1084 } 1085 } 1086 1087 return 0; 1088 } 1089 1090 slop1 = (4 - ((long)rp & 3)) & 3; 1091 slop2 = (num - slop1) & 3; 1092 num -= slop1 + slop2; 1093 n8 = num >> 5; 1094 num = (num >> 2) & 7; 1095 1096 while (height--) { 1097 dp = rp; 1098 DELTA(rp, ri->ri_stride, int32_t *); 1099 1100 /* Align span to 4 bytes */ 1101 if (slop1 & 1) { 1102 *(u_char *)dp = clr; 1103 DELTA(dp, 1, int32_t *); 1104 } 1105 1106 if (slop1 & 2) { 1107 *(int16_t *)dp = clr; 1108 DELTA(dp, 2, int32_t *); 1109 } 1110 1111 /* Write 32 bytes per loop */ 1112 for (cnt = n8; cnt; cnt--) { 1113 dp[0] = clr; 1114 dp[1] = clr; 1115 dp[2] = clr; 1116 dp[3] = clr; 1117 dp[4] = clr; 1118 dp[5] = clr; 1119 dp[6] = clr; 1120 dp[7] = clr; 1121 dp += 8; 1122 } 1123 1124 /* Write 4 bytes per loop */ 1125 for (cnt = num; cnt; cnt--) 1126 *dp++ = clr; 1127 1128 /* Write unaligned trailing slop */ 1129 if (slop2 & 1) { 1130 *(u_char *)dp = clr; 1131 DELTA(dp, 1, int32_t *); 1132 } 1133 1134 if (slop2 & 2) 1135 *(int16_t *)dp = clr; 1136 } 1137 1138 return 0; 1139 } 1140 1141 #if NRASOPS_ROTATION > 0 1142 /* 1143 * Quarter clockwise rotation routines (originally intended for the 1144 * built-in Zaurus C3x00 display in 16bpp). 1145 */ 1146 1147 #include <sys/malloc.h> 1148 1149 void 1150 rasops_rotate_font(int *cookie) 1151 { 1152 struct rotatedfont *f; 1153 int ncookie; 1154 1155 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1156 if (f->rf_cookie == *cookie) { 1157 *cookie = f->rf_rotated; 1158 return; 1159 } 1160 } 1161 1162 /* 1163 * We did not find a rotated version of this font. Ask the wsfont 1164 * code to compute one for us. 1165 */ 1166 1167 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK); 1168 1169 if ((ncookie = wsfont_rotate(*cookie)) == -1) 1170 return; 1171 1172 f->rf_cookie = *cookie; 1173 f->rf_rotated = ncookie; 1174 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1175 1176 *cookie = ncookie; 1177 } 1178 1179 void 1180 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1181 { 1182 struct rasops_info *ri; 1183 u_char *sp, *dp; 1184 int height; 1185 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1186 1187 ri = (struct rasops_info *)cookie; 1188 1189 r_srcrow = srccol; 1190 r_dstrow = dstcol; 1191 r_srccol = ri->ri_rows - srcrow - 1; 1192 r_dstcol = ri->ri_rows - dstrow - 1; 1193 1194 r_srcrow *= ri->ri_yscale; 1195 r_dstrow *= ri->ri_yscale; 1196 height = ri->ri_font->fontheight; 1197 1198 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1199 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1200 1201 #if NRASOPS_BSWAP > 0 1202 if (ri->ri_flg & RI_BSWAP) { 1203 while (height--) { 1204 slow_ovbcopy(sp, dp, ri->ri_xscale); 1205 dp += ri->ri_stride; 1206 sp += ri->ri_stride; 1207 } 1208 } else 1209 #endif 1210 { 1211 while (height--) { 1212 memmove(dp, sp, ri->ri_xscale); 1213 dp += ri->ri_stride; 1214 sp += ri->ri_stride; 1215 } 1216 } 1217 } 1218 1219 int 1220 rasops_putchar_rotated(void *cookie, int row, int col, u_int uc, long attr) 1221 { 1222 struct rasops_info *ri; 1223 u_char *rp; 1224 int height; 1225 int rc; 1226 1227 ri = (struct rasops_info *)cookie; 1228 1229 /* Do rotated char sans (side)underline */ 1230 rc = ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1231 attr & ~1); 1232 if (rc != 0) 1233 return rc; 1234 1235 /* Do rotated underline */ 1236 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1237 ri->ri_xscale; 1238 height = ri->ri_font->fontheight; 1239 1240 /* XXX this assumes 16-bit color depth */ 1241 if ((attr & 1) != 0) { 1242 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1243 1244 while (height--) { 1245 *(int16_t *)rp = c; 1246 rp += ri->ri_stride; 1247 } 1248 } 1249 1250 return 0; 1251 } 1252 1253 int 1254 rasops_erasecols_rotated(void *cookie, int row, int col, int num, long attr) 1255 { 1256 struct rasops_info *ri; 1257 int i; 1258 int rc; 1259 1260 ri = (struct rasops_info *)cookie; 1261 1262 for (i = col; i < col + num; i++) { 1263 rc = ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1264 if (rc != 0) 1265 return rc; 1266 } 1267 1268 return 0; 1269 } 1270 1271 /* XXX: these could likely be optimised somewhat. */ 1272 int 1273 rasops_copyrows_rotated(void *cookie, int src, int dst, int num) 1274 { 1275 struct rasops_info *ri = (struct rasops_info *)cookie; 1276 int col, roff; 1277 1278 if (src > dst) { 1279 for (roff = 0; roff < num; roff++) 1280 for (col = 0; col < ri->ri_cols; col++) 1281 rasops_copychar(cookie, src + roff, dst + roff, 1282 col, col); 1283 } else { 1284 for (roff = num - 1; roff >= 0; roff--) 1285 for (col = 0; col < ri->ri_cols; col++) 1286 rasops_copychar(cookie, src + roff, dst + roff, 1287 col, col); 1288 } 1289 1290 return 0; 1291 } 1292 1293 int 1294 rasops_copycols_rotated(void *cookie, int row, int src, int dst, int num) 1295 { 1296 int coff; 1297 1298 if (src > dst) { 1299 for (coff = 0; coff < num; coff++) 1300 rasops_copychar(cookie, row, row, src + coff, 1301 dst + coff); 1302 } else { 1303 for (coff = num - 1; coff >= 0; coff--) 1304 rasops_copychar(cookie, row, row, src + coff, 1305 dst + coff); 1306 } 1307 1308 return 0; 1309 } 1310 1311 int 1312 rasops_eraserows_rotated(void *cookie, int row, int num, 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 1357 struct rasops_screen { 1358 LIST_ENTRY(rasops_screen) rs_next; 1359 struct rasops_info *rs_ri; 1360 1361 struct wsdisplay_charcell *rs_bs; 1362 int rs_visible; 1363 int rs_crow; 1364 int rs_ccol; 1365 }; 1366 1367 int 1368 rasops_alloc_screen(void *v, void **cookiep, 1369 int *curxp, int *curyp, long *attrp) 1370 { 1371 struct rasops_info *ri = v; 1372 struct rasops_screen *scr; 1373 size_t size; 1374 int i; 1375 1376 scr = malloc(sizeof(struct rasops_screen), M_DEVBUF, M_NOWAIT); 1377 if (scr == NULL) 1378 return (ENOMEM); 1379 1380 size = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell); 1381 scr->rs_bs = malloc(size, M_DEVBUF, M_NOWAIT); 1382 if (scr->rs_bs == NULL) { 1383 free(scr, M_DEVBUF, 0); 1384 return (ENOMEM); 1385 } 1386 1387 *cookiep = scr; 1388 *curxp = 0; 1389 *curyp = 0; 1390 ri->ri_alloc_attr(ri, 0, 0, 0, attrp); 1391 1392 scr->rs_ri = ri; 1393 scr->rs_visible = (ri->ri_nscreens == 0); 1394 scr->rs_crow = -1; 1395 scr->rs_ccol = -1; 1396 1397 for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) { 1398 scr->rs_bs[i].uc = ' '; 1399 scr->rs_bs[i].attr = *attrp; 1400 } 1401 1402 LIST_INSERT_HEAD(&ri->ri_screens, scr, rs_next); 1403 ri->ri_nscreens++; 1404 1405 return (0); 1406 } 1407 1408 void 1409 rasops_free_screen(void *v, void *cookie) 1410 { 1411 struct rasops_info *ri = v; 1412 struct rasops_screen *scr = cookie; 1413 1414 LIST_REMOVE(scr, rs_next); 1415 ri->ri_nscreens--; 1416 1417 free(scr->rs_bs, M_DEVBUF, 0); 1418 free(scr, M_DEVBUF, 0); 1419 } 1420 1421 int 1422 rasops_show_screen(void *v, void *cookie, int waitok, 1423 void (*cb)(void *, int, int), void *cbarg) 1424 { 1425 struct rasops_info *ri = v; 1426 1427 if (cb) { 1428 ri->ri_switchcb = cb; 1429 ri->ri_switchcbarg = cbarg; 1430 workq_queue_task(NULL, &ri->ri_switchwqt, 0, 1431 rasops_doswitch, v, cookie); 1432 return (EAGAIN); 1433 } 1434 1435 rasops_doswitch(v, cookie); 1436 return (0); 1437 } 1438 1439 void 1440 rasops_doswitch(void *v, void *cookie) 1441 { 1442 struct rasops_info *ri = v; 1443 struct rasops_screen *scr = cookie; 1444 int row, col; 1445 long attr; 1446 1447 rasops_cursor(ri, 0, 0, 0); 1448 ri->ri_active->rs_visible = 0; 1449 ri->ri_alloc_attr(ri, 0, 0, 0, &attr); 1450 ri->ri_eraserows(ri, 0, ri->ri_rows, attr); 1451 ri->ri_active = scr; 1452 ri->ri_active->rs_visible = 1; 1453 for (row = 0; row < ri->ri_rows; row++) { 1454 for (col = 0; col < ri->ri_cols; col++) { 1455 int off = row * scr->rs_ri->ri_cols + col; 1456 1457 ri->ri_putchar(ri, row, col, scr->rs_bs[off].uc, 1458 scr->rs_bs[off].attr); 1459 } 1460 } 1461 if (scr->rs_crow != -1) 1462 rasops_cursor(ri, 1, scr->rs_crow, scr->rs_ccol); 1463 1464 if (ri->ri_switchcb) 1465 (*ri->ri_switchcb)(ri->ri_switchcbarg, 0, 0); 1466 } 1467 1468 int 1469 rasops_getchar(void *v, int row, int col, struct wsdisplay_charcell *cell) 1470 { 1471 struct rasops_info *ri = v; 1472 struct rasops_screen *scr = ri->ri_active; 1473 1474 if (scr == NULL || scr->rs_bs == NULL) 1475 return (1); 1476 1477 *cell = scr->rs_bs[row * ri->ri_cols + col]; 1478 return (0); 1479 } 1480 1481 int 1482 rasops_vcons_cursor(void *cookie, int on, int row, int col) 1483 { 1484 struct rasops_screen *scr = cookie; 1485 1486 scr->rs_crow = on ? row : -1; 1487 scr->rs_ccol = on ? col : -1; 1488 1489 if (!scr->rs_visible) 1490 return 0; 1491 1492 return rasops_cursor(scr->rs_ri, on, row, col); 1493 } 1494 1495 int 1496 rasops_vcons_mapchar(void *cookie, int c, u_int *cp) 1497 { 1498 struct rasops_screen *scr = cookie; 1499 1500 return rasops_mapchar(scr->rs_ri, c, cp); 1501 } 1502 1503 int 1504 rasops_vcons_putchar(void *cookie, int row, int col, u_int uc, long attr) 1505 { 1506 struct rasops_screen *scr = cookie; 1507 int off = row * scr->rs_ri->ri_cols + col; 1508 1509 scr->rs_bs[off].uc = uc; 1510 scr->rs_bs[off].attr = attr; 1511 1512 if (!scr->rs_visible) 1513 return 0; 1514 1515 return scr->rs_ri->ri_putchar(scr->rs_ri, row, col, uc, attr); 1516 } 1517 1518 int 1519 rasops_vcons_copycols(void *cookie, int row, int src, int dst, int num) 1520 { 1521 struct rasops_screen *scr = cookie; 1522 struct rasops_info *ri = scr->rs_ri; 1523 int cols = scr->rs_ri->ri_cols; 1524 int col, rc; 1525 1526 memmove(&scr->rs_bs[row * cols + dst], &scr->rs_bs[row * cols + src], 1527 num * sizeof(struct wsdisplay_charcell)); 1528 1529 if (!scr->rs_visible) 1530 return 0; 1531 1532 if ((ri->ri_flg & RI_WRONLY) == 0) 1533 return ri->ri_copycols(ri, row, src, dst, num); 1534 1535 for (col = dst; col < dst + num; col++) { 1536 int off = row * cols + col; 1537 1538 rc = ri->ri_putchar(ri, row, col, 1539 scr->rs_bs[off].uc, scr->rs_bs[off].attr); 1540 if (rc != 0) 1541 return rc; 1542 } 1543 1544 return 0; 1545 } 1546 1547 int 1548 rasops_vcons_erasecols(void *cookie, int row, int col, int num, long attr) 1549 { 1550 struct rasops_screen *scr = cookie; 1551 int cols = scr->rs_ri->ri_cols; 1552 int i; 1553 1554 for (i = 0; i < num; i++) { 1555 scr->rs_bs[row * cols + col + i].uc = ' '; 1556 scr->rs_bs[row * cols + col + i].attr = attr; 1557 } 1558 1559 if (!scr->rs_visible) 1560 return 0; 1561 1562 return scr->rs_ri->ri_erasecols(scr->rs_ri, row, col, num, attr); 1563 } 1564 1565 int 1566 rasops_vcons_copyrows(void *cookie, int src, int dst, int num) 1567 { 1568 struct rasops_screen *scr = cookie; 1569 struct rasops_info *ri = scr->rs_ri; 1570 int cols = ri->ri_cols; 1571 int row, col, rc; 1572 1573 memmove(&scr->rs_bs[dst * cols], &scr->rs_bs[src * cols], 1574 num * cols * sizeof(struct wsdisplay_charcell)); 1575 1576 if (!scr->rs_visible) 1577 return 0; 1578 1579 if ((ri->ri_flg & RI_WRONLY) == 0) 1580 return ri->ri_copyrows(ri, src, dst, num); 1581 1582 for (row = dst; row < dst + num; row++) { 1583 for (col = 0; col < cols; col++) { 1584 int off = row * cols + col; 1585 1586 rc = ri->ri_putchar(ri, row, col, 1587 scr->rs_bs[off].uc, scr->rs_bs[off].attr); 1588 if (rc != 0) 1589 return rc; 1590 } 1591 } 1592 1593 return 0; 1594 } 1595 1596 int 1597 rasops_vcons_eraserows(void *cookie, int row, int num, long attr) 1598 { 1599 struct rasops_screen *scr = cookie; 1600 int cols = scr->rs_ri->ri_cols; 1601 int i; 1602 1603 for (i = 0; i < num * cols; i++) { 1604 scr->rs_bs[row * cols + i].uc = ' '; 1605 scr->rs_bs[row * cols + i].attr = attr; 1606 } 1607 1608 if (!scr->rs_visible) 1609 return 0; 1610 1611 return scr->rs_ri->ri_eraserows(scr->rs_ri, row, num, attr); 1612 } 1613 1614 int 1615 rasops_vcons_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 1616 { 1617 struct rasops_screen *scr = cookie; 1618 1619 return scr->rs_ri->ri_alloc_attr(scr->rs_ri, fg, bg, flg, attr); 1620 } 1621 1622 void 1623 rasops_vcons_unpack_attr(void *cookie, long attr, int *fg, int *bg, 1624 int *underline) 1625 { 1626 struct rasops_screen *scr = cookie; 1627 1628 rasops_unpack_attr(scr->rs_ri, attr, fg, bg, underline); 1629 } 1630 1631 /* 1632 * Font management. 1633 * 1634 * Fonts usable on raster frame buffers are managed by wsfont, and are not 1635 * tied to any particular display. 1636 */ 1637 1638 int 1639 rasops_add_font(struct rasops_info *ri, struct wsdisplay_font *font) 1640 { 1641 /* only accept matching metrics */ 1642 if (font->fontwidth != ri->ri_font->fontwidth || 1643 font->fontheight != ri->ri_font->fontheight) 1644 return EINVAL; 1645 1646 /* for raster consoles, only accept ISO Latin-1 or Unicode encoding */ 1647 if (font->encoding != WSDISPLAY_FONTENC_ISO) 1648 return EINVAL; 1649 1650 if (wsfont_add(font, 1) != 0) 1651 return EEXIST; /* name collision */ 1652 1653 font->index = -1; /* do not store in wsdisplay_softc */ 1654 1655 return 0; 1656 } 1657 1658 int 1659 rasops_use_font(struct rasops_info *ri, struct wsdisplay_font *font) 1660 { 1661 int wsfcookie; 1662 struct wsdisplay_font *wsf; 1663 const char *name; 1664 1665 /* allow an empty font name to revert to the initial font choice */ 1666 name = font->name; 1667 if (*name == '\0') 1668 name = NULL; 1669 1670 wsfcookie = wsfont_find(name, ri->ri_font->fontwidth, 1671 ri->ri_font->fontheight, 0); 1672 if (wsfcookie < 0) { 1673 wsfcookie = wsfont_find(name, 0, 0, 0); 1674 if (wsfcookie < 0) 1675 return ENOENT; /* font exist, but different metrics */ 1676 else 1677 return EINVAL; 1678 } 1679 if (wsfont_lock(wsfcookie, &wsf, WSDISPLAY_FONTORDER_KNOWN, 1680 WSDISPLAY_FONTORDER_KNOWN) < 0) 1681 return EINVAL; 1682 1683 /* if (ri->ri_wsfcookie >= 0) */ 1684 wsfont_unlock(ri->ri_wsfcookie); 1685 ri->ri_wsfcookie = wsfcookie; 1686 ri->ri_font = wsf; 1687 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 1688 1689 return 0; 1690 } 1691 1692 int 1693 rasops_load_font(void *v, void *cookie, struct wsdisplay_font *font) 1694 { 1695 struct rasops_info *ri = v; 1696 1697 /* 1698 * For now, we want to only allow loading fonts of the same 1699 * metrics as the currently in-use font. This requires the 1700 * rasops struct to have been correctly configured, and a 1701 * font to have been selected. 1702 */ 1703 if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL) 1704 return EINVAL; 1705 1706 if (font->data != NULL) 1707 return rasops_add_font(ri, font); 1708 else 1709 return rasops_use_font(ri, font); 1710 } 1711 1712 struct rasops_list_font_ctx { 1713 struct rasops_info *ri; 1714 int cnt; 1715 struct wsdisplay_font *font; 1716 }; 1717 1718 int 1719 rasops_list_font_cb(void *cbarg, struct wsdisplay_font *font) 1720 { 1721 struct rasops_list_font_ctx *ctx = cbarg; 1722 1723 if (font->fontheight != ctx->ri->ri_font->fontheight || 1724 font->fontwidth != ctx->ri->ri_font->fontwidth) 1725 return 0; 1726 1727 if (ctx->cnt-- == 0) { 1728 ctx->font = font; 1729 return 1; 1730 } 1731 1732 return 0; 1733 } 1734 1735 int 1736 rasops_list_font(void *v, struct wsdisplay_font *font) 1737 { 1738 struct rasops_info *ri = v; 1739 struct rasops_list_font_ctx ctx; 1740 int idx; 1741 1742 if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL) 1743 return EINVAL; 1744 1745 if (font->index < 0) 1746 return EINVAL; 1747 1748 ctx.ri = ri; 1749 ctx.cnt = font->index; 1750 ctx.font = NULL; 1751 wsfont_enum(rasops_list_font_cb, &ctx); 1752 1753 if (ctx.font == NULL) 1754 return EINVAL; 1755 1756 idx = font->index; 1757 *font = *ctx.font; /* struct copy */ 1758 font->index = idx; 1759 font->cookie = font->data = NULL; /* don't leak kernel pointers */ 1760 return 0; 1761 } 1762