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