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