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