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