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