1 /* $OpenBSD: rasops.c,v 1.42 2015/09/07 18:00:58 kettenis Exp $ */ 2 /* $NetBSD: rasops.c,v 1.35 2001/02/02 06:01:01 marcus Exp $ */ 3 4 /*- 5 * Copyright (c) 1999 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Andrew Doran. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/malloc.h> 35 #include <sys/systm.h> 36 #include <sys/time.h> 37 #include <sys/task.h> 38 39 #include <dev/wscons/wsdisplayvar.h> 40 #include <dev/wscons/wsconsio.h> 41 #include <dev/wsfont/wsfont.h> 42 #include <dev/rasops/rasops.h> 43 44 #ifndef _KERNEL 45 #include <errno.h> 46 #endif 47 48 /* ANSI colormap (R,G,B) */ 49 50 #define NORMAL_BLACK 0x000000 51 #define NORMAL_RED 0x7f0000 52 #define NORMAL_GREEN 0x007f00 53 #define NORMAL_BROWN 0x7f7f00 54 #define NORMAL_BLUE 0x00007f 55 #define NORMAL_MAGENTA 0x7f007f 56 #define NORMAL_CYAN 0x007f7f 57 #define NORMAL_WHITE 0xc7c7c7 /* XXX too dim? */ 58 59 #define HILITE_BLACK 0x7f7f7f 60 #define HILITE_RED 0xff0000 61 #define HILITE_GREEN 0x00ff00 62 #define HILITE_BROWN 0xffff00 63 #define HILITE_BLUE 0x0000ff 64 #define HILITE_MAGENTA 0xff00ff 65 #define HILITE_CYAN 0x00ffff 66 #define HILITE_WHITE 0xffffff 67 68 const u_char rasops_cmap[256 * 3] = { 69 #define _C(x) ((x) & 0xff0000) >> 16, ((x) & 0x00ff00) >> 8, ((x) & 0x0000ff) 70 71 _C(NORMAL_BLACK), 72 _C(NORMAL_RED), 73 _C(NORMAL_GREEN), 74 _C(NORMAL_BROWN), 75 _C(NORMAL_BLUE), 76 _C(NORMAL_MAGENTA), 77 _C(NORMAL_CYAN), 78 _C(NORMAL_WHITE), 79 80 _C(HILITE_BLACK), 81 _C(HILITE_RED), 82 _C(HILITE_GREEN), 83 _C(HILITE_BROWN), 84 _C(HILITE_BLUE), 85 _C(HILITE_MAGENTA), 86 _C(HILITE_CYAN), 87 _C(HILITE_WHITE), 88 89 /* 90 * For the cursor, we need the last 16 colors to be the 91 * opposite of the first 16. Fill the intermediate space with 92 * white completely for simplicity. 93 */ 94 #define _CMWHITE16 \ 95 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \ 96 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \ 97 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), \ 98 _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), _C(HILITE_WHITE), 99 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 100 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 101 _CMWHITE16 _CMWHITE16 _CMWHITE16 _CMWHITE16 102 #undef _CMWHITE16 103 104 _C(~HILITE_WHITE), 105 _C(~HILITE_CYAN), 106 _C(~HILITE_MAGENTA), 107 _C(~HILITE_BLUE), 108 _C(~HILITE_BROWN), 109 _C(~HILITE_GREEN), 110 _C(~HILITE_RED), 111 _C(~HILITE_BLACK), 112 113 _C(~NORMAL_WHITE), 114 _C(~NORMAL_CYAN), 115 _C(~NORMAL_MAGENTA), 116 _C(~NORMAL_BLUE), 117 _C(~NORMAL_BROWN), 118 _C(~NORMAL_GREEN), 119 _C(~NORMAL_RED), 120 _C(~NORMAL_BLACK), 121 122 #undef _C 123 }; 124 125 /* True if color is gray */ 126 const u_char rasops_isgray[16] = { 127 1, 0, 0, 0, 128 0, 0, 0, 1, 129 1, 0, 0, 0, 130 0, 0, 0, 1 131 }; 132 133 /* 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 NRASOPS2 > 0 431 case 2: 432 rasops2_init(ri); 433 break; 434 #endif 435 #if NRASOPS4 > 0 436 case 4: 437 rasops4_init(ri); 438 break; 439 #endif 440 #if NRASOPS8 > 0 441 case 8: 442 rasops8_init(ri); 443 break; 444 #endif 445 #if NRASOPS15 > 0 || NRASOPS16 > 0 446 case 15: 447 case 16: 448 rasops15_init(ri); 449 break; 450 #endif 451 #if NRASOPS24 > 0 452 case 24: 453 rasops24_init(ri); 454 break; 455 #endif 456 #if NRASOPS32 > 0 457 case 32: 458 rasops32_init(ri); 459 break; 460 #endif 461 default: 462 ri->ri_flg &= ~RI_CFGDONE; 463 splx(s); 464 return (-1); 465 } 466 467 #if NRASOPS_ROTATION > 0 468 if (ri->ri_flg & RI_ROTATE_CW) { 469 ri->ri_real_ops = ri->ri_ops; 470 ri->ri_ops.copycols = rasops_copycols_rotated; 471 ri->ri_ops.copyrows = rasops_copyrows_rotated; 472 ri->ri_ops.erasecols = rasops_erasecols_rotated; 473 ri->ri_ops.eraserows = rasops_eraserows_rotated; 474 ri->ri_ops.putchar = rasops_putchar_rotated; 475 } 476 #endif 477 478 ri->ri_flg |= RI_CFGDONE; 479 splx(s); 480 return (0); 481 } 482 483 /* 484 * Map a character. 485 */ 486 int 487 rasops_mapchar(void *cookie, int c, u_int *cp) 488 { 489 struct rasops_info *ri; 490 491 ri = (struct rasops_info *)cookie; 492 493 #ifdef DIAGNOSTIC 494 if (ri->ri_font == NULL) 495 panic("rasops_mapchar: no font selected"); 496 #endif 497 if (ri->ri_font->encoding != WSDISPLAY_FONTENC_ISO) { 498 499 if ( (c = wsfont_map_unichar(ri->ri_font, c)) < 0) { 500 501 *cp = '?'; 502 return (0); 503 504 } 505 } 506 507 508 if (c < ri->ri_font->firstchar) { 509 *cp = '?'; 510 return (0); 511 } 512 513 if (c - ri->ri_font->firstchar >= ri->ri_font->numchars) { 514 *cp = '?'; 515 return (0); 516 } 517 518 *cp = c; 519 return (5); 520 } 521 522 /* 523 * Allocate a color attribute. 524 */ 525 int 526 rasops_alloc_cattr(void *cookie, int fg, int bg, int flg, long *attr) 527 { 528 int swap; 529 530 #ifdef RASOPS_CLIPPING 531 fg &= 7; 532 bg &= 7; 533 #endif 534 if ((flg & WSATTR_BLINK) != 0) 535 return (EINVAL); 536 537 if ((flg & WSATTR_WSCOLORS) == 0) { 538 fg = WS_DEFAULT_FG; 539 bg = WS_DEFAULT_BG; 540 } 541 542 if ((flg & WSATTR_REVERSE) != 0) { 543 swap = fg; 544 fg = bg; 545 bg = swap; 546 } 547 548 if ((flg & WSATTR_HILIT) != 0) 549 fg += 8; 550 551 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 552 553 if (rasops_isgray[fg]) 554 flg |= 2; 555 556 if (rasops_isgray[bg]) 557 flg |= 4; 558 559 *attr = (bg << 16) | (fg << 24) | flg; 560 return (0); 561 } 562 563 /* 564 * Allocate a mono attribute. 565 */ 566 int 567 rasops_alloc_mattr(void *cookie, int fg, int bg, int flg, long *attr) 568 { 569 int swap; 570 571 if ((flg & (WSATTR_BLINK | WSATTR_HILIT | WSATTR_WSCOLORS)) != 0) 572 return (EINVAL); 573 574 fg = 1; 575 bg = 0; 576 577 if ((flg & WSATTR_REVERSE) != 0) { 578 swap = fg; 579 fg = bg; 580 bg = swap; 581 } 582 583 *attr = (bg << 16) | (fg << 24) | ((flg & WSATTR_UNDERLINE) ? 7 : 6); 584 return (0); 585 } 586 587 /* 588 * Copy rows. 589 */ 590 int 591 rasops_copyrows(void *cookie, int src, int dst, int num) 592 { 593 int32_t *sp, *dp, *srp, *drp; 594 struct rasops_info *ri; 595 int n8, n1, cnt, delta; 596 597 ri = (struct rasops_info *)cookie; 598 599 #ifdef RASOPS_CLIPPING 600 if (dst == src) 601 return 0; 602 603 if (src < 0) { 604 num += src; 605 src = 0; 606 } 607 608 if ((src + num) > ri->ri_rows) 609 num = ri->ri_rows - src; 610 611 if (dst < 0) { 612 num += dst; 613 dst = 0; 614 } 615 616 if ((dst + num) > ri->ri_rows) 617 num = ri->ri_rows - dst; 618 619 if (num <= 0) 620 return 0; 621 #endif 622 623 num *= ri->ri_font->fontheight; 624 n8 = ri->ri_emustride >> 5; 625 n1 = (ri->ri_emustride >> 2) & 7; 626 627 if (dst < src) { 628 srp = (int32_t *)(ri->ri_bits + src * ri->ri_yscale); 629 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_yscale); 630 delta = ri->ri_stride; 631 } else { 632 src = ri->ri_font->fontheight * src + num - 1; 633 dst = ri->ri_font->fontheight * dst + num - 1; 634 srp = (int32_t *)(ri->ri_bits + src * ri->ri_stride); 635 drp = (int32_t *)(ri->ri_bits + dst * ri->ri_stride); 636 delta = -ri->ri_stride; 637 } 638 639 while (num--) { 640 dp = drp; 641 sp = srp; 642 DELTA(drp, delta, int32_t *); 643 DELTA(srp, delta, int32_t *); 644 645 for (cnt = n8; cnt; cnt--) { 646 dp[0] = sp[0]; 647 dp[1] = sp[1]; 648 dp[2] = sp[2]; 649 dp[3] = sp[3]; 650 dp[4] = sp[4]; 651 dp[5] = sp[5]; 652 dp[6] = sp[6]; 653 dp[7] = sp[7]; 654 dp += 8; 655 sp += 8; 656 } 657 658 for (cnt = n1; cnt; cnt--) 659 *dp++ = *sp++; 660 } 661 662 return 0; 663 } 664 665 /* 666 * Copy columns. This is slow, and hard to optimize due to alignment, 667 * and the fact that we have to copy both left->right and right->left. 668 * We simply cop-out here and use bcopy(), since it handles all of 669 * these cases anyway. 670 */ 671 int 672 rasops_copycols(void *cookie, int row, int src, int dst, int num) 673 { 674 struct rasops_info *ri; 675 u_char *sp, *dp; 676 int height; 677 678 ri = (struct rasops_info *)cookie; 679 680 #ifdef RASOPS_CLIPPING 681 if (dst == src) 682 return 0; 683 684 /* Catches < 0 case too */ 685 if ((unsigned)row >= (unsigned)ri->ri_rows) 686 return 0; 687 688 if (src < 0) { 689 num += src; 690 src = 0; 691 } 692 693 if ((src + num) > ri->ri_cols) 694 num = ri->ri_cols - src; 695 696 if (dst < 0) { 697 num += dst; 698 dst = 0; 699 } 700 701 if ((dst + num) > ri->ri_cols) 702 num = ri->ri_cols - dst; 703 704 if (num <= 0) 705 return 0; 706 #endif 707 708 num *= ri->ri_xscale; 709 row *= ri->ri_yscale; 710 height = ri->ri_font->fontheight; 711 712 sp = ri->ri_bits + row + src * ri->ri_xscale; 713 dp = ri->ri_bits + row + dst * ri->ri_xscale; 714 715 #if NRASOPS_BSWAP > 0 716 if (ri->ri_flg & RI_BSWAP) { 717 while (height--) { 718 slow_bcopy(sp, dp, num); 719 dp += ri->ri_stride; 720 sp += ri->ri_stride; 721 } 722 } else 723 #endif 724 { 725 while (height--) { 726 memmove(dp, sp, num); 727 dp += ri->ri_stride; 728 sp += ri->ri_stride; 729 } 730 } 731 732 return 0; 733 } 734 735 /* 736 * Turn cursor off/on. 737 */ 738 int 739 rasops_cursor(void *cookie, int on, int row, int col) 740 { 741 struct rasops_info *ri; 742 int rc; 743 744 ri = (struct rasops_info *)cookie; 745 746 /* Turn old cursor off */ 747 if ((ri->ri_flg & RI_CURSOR) != 0) { 748 #ifdef RASOPS_CLIPPING 749 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 750 #endif 751 if ((rc = ri->ri_do_cursor(ri)) != 0) 752 return rc; 753 ri->ri_flg &= ~RI_CURSOR; 754 } 755 756 /* Select new cursor */ 757 #ifdef RASOPS_CLIPPING 758 ri->ri_flg &= ~RI_CURSORCLIP; 759 760 if (row < 0 || row >= ri->ri_rows) 761 ri->ri_flg |= RI_CURSORCLIP; 762 else if (col < 0 || col >= ri->ri_cols) 763 ri->ri_flg |= RI_CURSORCLIP; 764 #endif 765 ri->ri_crow = row; 766 ri->ri_ccol = col; 767 768 if (ri->ri_updatecursor != NULL) 769 ri->ri_updatecursor(ri); 770 771 if (on) { 772 #ifdef RASOPS_CLIPPING 773 if ((ri->ri_flg & RI_CURSORCLIP) == 0) 774 #endif 775 if ((rc = ri->ri_do_cursor(ri)) != 0) 776 return rc; 777 ri->ri_flg |= RI_CURSOR; 778 } 779 780 return 0; 781 } 782 783 /* 784 * Make the device colormap 785 */ 786 void 787 rasops_init_devcmap(struct rasops_info *ri) 788 { 789 int i; 790 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 791 const u_char *p; 792 #endif 793 #if NRASOPS4 > 0 || NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 794 int c; 795 #endif 796 797 if (ri->ri_depth == 1 || (ri->ri_flg & RI_FORCEMONO) != 0) { 798 ri->ri_devcmap[0] = 0; 799 for (i = 1; i < 16; i++) 800 ri->ri_devcmap[i] = 0xffffffff; 801 return; 802 } 803 804 switch (ri->ri_depth) { 805 #if NRASOPS2 > 0 806 case 2: 807 for (i = 1; i < 15; i++) 808 ri->ri_devcmap[i] = 0xaaaaaaaa; 809 810 ri->ri_devcmap[0] = 0; 811 ri->ri_devcmap[8] = 0x55555555; 812 ri->ri_devcmap[15] = 0xffffffff; 813 return; 814 #endif 815 #if NRASOPS4 > 0 816 case 4: 817 for (i = 0; i < 16; i++) { 818 c = i | (i << 4); 819 ri->ri_devcmap[i] = c | (c<<8) | (c<<16) | (c<<24); 820 } 821 return; 822 #endif 823 #if NRASOPS8 > 0 824 case 8: 825 for (i = 0; i < 16; i++) 826 ri->ri_devcmap[i] = i | (i<<8) | (i<<16) | (i<<24); 827 return; 828 #endif 829 default: 830 break; 831 } 832 833 #if NRASOPS15 > 0 || NRASOPS16 > 0 || NRASOPS24 > 0 || NRASOPS32 > 0 834 p = rasops_cmap; 835 836 for (i = 0; i < 16; i++) { 837 if (ri->ri_rnum <= 8) 838 c = (*p >> (8 - ri->ri_rnum)) << ri->ri_rpos; 839 else 840 c = (*p << (ri->ri_rnum - 8)) << ri->ri_rpos; 841 p++; 842 843 if (ri->ri_gnum <= 8) 844 c |= (*p >> (8 - ri->ri_gnum)) << ri->ri_gpos; 845 else 846 c |= (*p << (ri->ri_gnum - 8)) << ri->ri_gpos; 847 p++; 848 849 if (ri->ri_bnum <= 8) 850 c |= (*p >> (8 - ri->ri_bnum)) << ri->ri_bpos; 851 else 852 c |= (*p << (ri->ri_bnum - 8)) << ri->ri_bpos; 853 p++; 854 855 /* Fill the word for generic routines, which want this */ 856 if (ri->ri_depth == 24) 857 c = c | ((c & 0xff) << 24); 858 else if (ri->ri_depth <= 16) 859 c = c | (c << 16); 860 861 /* 24bpp does bswap on the fly. {32,16,15}bpp do it here. */ 862 #if NRASOPS_BSWAP > 0 863 if ((ri->ri_flg & RI_BSWAP) == 0) 864 ri->ri_devcmap[i] = c; 865 else if (ri->ri_depth == 32) 866 ri->ri_devcmap[i] = swap32(c); 867 else if (ri->ri_depth == 16 || ri->ri_depth == 15) 868 ri->ri_devcmap[i] = swap16(c); 869 else 870 ri->ri_devcmap[i] = c; 871 #else 872 ri->ri_devcmap[i] = c; 873 #endif 874 } 875 #endif 876 } 877 878 /* 879 * Unpack a rasops attribute 880 */ 881 void 882 rasops_unpack_attr(void *cookie, long attr, int *fg, int *bg, int *underline) 883 { 884 *fg = ((u_int)attr >> 24) & 0xf; 885 *bg = ((u_int)attr >> 16) & 0xf; 886 if (underline != NULL) 887 *underline = (u_int)attr & 1; 888 } 889 890 /* 891 * Erase rows 892 */ 893 int 894 rasops_eraserows(void *cookie, int row, int num, long attr) 895 { 896 struct rasops_info *ri; 897 int np, nw, cnt, delta; 898 int32_t *dp, clr; 899 900 ri = (struct rasops_info *)cookie; 901 902 #ifdef RASOPS_CLIPPING 903 if (row < 0) { 904 num += row; 905 row = 0; 906 } 907 908 if ((row + num) > ri->ri_rows) 909 num = ri->ri_rows - row; 910 911 if (num <= 0) 912 return 0; 913 #endif 914 915 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 916 917 /* 918 * XXX The wsdisplay_emulops interface seems a little deficient in 919 * that there is no way to clear the *entire* screen. We provide a 920 * workaround here: if the entire console area is being cleared, and 921 * the RI_FULLCLEAR flag is set, clear the entire display. 922 */ 923 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR) != 0) { 924 np = ri->ri_stride >> 5; 925 nw = (ri->ri_stride >> 2) & 7; 926 num = ri->ri_height; 927 dp = (int32_t *)ri->ri_origbits; 928 delta = 0; 929 } else { 930 np = ri->ri_emustride >> 5; 931 nw = (ri->ri_emustride >> 2) & 7; 932 num *= ri->ri_font->fontheight; 933 dp = (int32_t *)(ri->ri_bits + row * ri->ri_yscale); 934 delta = ri->ri_delta; 935 } 936 937 while (num--) { 938 for (cnt = np; cnt; cnt--) { 939 dp[0] = clr; 940 dp[1] = clr; 941 dp[2] = clr; 942 dp[3] = clr; 943 dp[4] = clr; 944 dp[5] = clr; 945 dp[6] = clr; 946 dp[7] = clr; 947 dp += 8; 948 } 949 950 for (cnt = nw; cnt; cnt--) { 951 *(int32_t *)dp = clr; 952 DELTA(dp, 4, int32_t *); 953 } 954 955 DELTA(dp, delta, int32_t *); 956 } 957 958 return 0; 959 } 960 961 /* 962 * Actually turn the cursor on or off. This does the dirty work for 963 * rasops_cursor(). 964 */ 965 int 966 rasops_do_cursor(struct rasops_info *ri) 967 { 968 int full1, height, cnt, slop1, slop2, row, col; 969 u_char *dp, *rp; 970 971 #if NRASOPS_ROTATION > 0 972 if (ri->ri_flg & RI_ROTATE_CW) { 973 /* Rotate rows/columns */ 974 row = ri->ri_ccol; 975 col = ri->ri_rows - ri->ri_crow - 1; 976 } else 977 #endif 978 { 979 row = ri->ri_crow; 980 col = ri->ri_ccol; 981 } 982 983 rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale; 984 height = ri->ri_font->fontheight; 985 slop1 = (4 - ((long)rp & 3)) & 3; 986 987 if (slop1 > ri->ri_xscale) 988 slop1 = ri->ri_xscale; 989 990 slop2 = (ri->ri_xscale - slop1) & 3; 991 full1 = (ri->ri_xscale - slop1 - slop2) >> 2; 992 993 if ((slop1 | slop2) == 0) { 994 /* A common case */ 995 while (height--) { 996 dp = rp; 997 rp += ri->ri_stride; 998 999 for (cnt = full1; cnt; cnt--) { 1000 *(int32_t *)dp ^= ~0; 1001 dp += 4; 1002 } 1003 } 1004 } else { 1005 /* XXX this is stupid.. use masks instead */ 1006 while (height--) { 1007 dp = rp; 1008 rp += ri->ri_stride; 1009 1010 if (slop1 & 1) 1011 *dp++ ^= ~0; 1012 1013 if (slop1 & 2) { 1014 *(int16_t *)dp ^= ~0; 1015 dp += 2; 1016 } 1017 1018 for (cnt = full1; cnt; cnt--) { 1019 *(int32_t *)dp ^= ~0; 1020 dp += 4; 1021 } 1022 1023 if (slop2 & 1) 1024 *dp++ ^= ~0; 1025 1026 if (slop2 & 2) 1027 *(int16_t *)dp ^= ~0; 1028 } 1029 } 1030 1031 return 0; 1032 } 1033 1034 /* 1035 * Erase columns. 1036 */ 1037 int 1038 rasops_erasecols(void *cookie, int row, int col, int num, long attr) 1039 { 1040 int n8, height, cnt, slop1, slop2, clr; 1041 struct rasops_info *ri; 1042 int32_t *rp, *dp; 1043 1044 ri = (struct rasops_info *)cookie; 1045 1046 #ifdef RASOPS_CLIPPING 1047 if ((unsigned)row >= (unsigned)ri->ri_rows) 1048 return 0; 1049 1050 if (col < 0) { 1051 num += col; 1052 col = 0; 1053 } 1054 1055 if ((col + num) > ri->ri_cols) 1056 num = ri->ri_cols - col; 1057 1058 if (num <= 0) 1059 return 0; 1060 #endif 1061 1062 num = num * ri->ri_xscale; 1063 rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1064 height = ri->ri_font->fontheight; 1065 clr = ri->ri_devcmap[(attr >> 16) & 0xf]; 1066 1067 /* Don't bother using the full loop for <= 32 pels */ 1068 if (num <= 32) { 1069 if (((num | ri->ri_xscale) & 3) == 0) { 1070 /* Word aligned blt */ 1071 num >>= 2; 1072 1073 while (height--) { 1074 dp = rp; 1075 DELTA(rp, ri->ri_stride, int32_t *); 1076 1077 for (cnt = num; cnt; cnt--) 1078 *dp++ = clr; 1079 } 1080 } else if (((num | ri->ri_xscale) & 1) == 0) { 1081 /* 1082 * Halfword aligned blt. This is needed so the 1083 * 15/16 bit ops can use this function. 1084 */ 1085 num >>= 1; 1086 1087 while (height--) { 1088 dp = rp; 1089 DELTA(rp, ri->ri_stride, int32_t *); 1090 1091 for (cnt = num; cnt; cnt--) { 1092 *(int16_t *)dp = clr; 1093 DELTA(dp, 2, int32_t *); 1094 } 1095 } 1096 } else { 1097 while (height--) { 1098 dp = rp; 1099 DELTA(rp, ri->ri_stride, int32_t *); 1100 1101 for (cnt = num; cnt; cnt--) { 1102 *(u_char *)dp = clr; 1103 DELTA(dp, 1, int32_t *); 1104 } 1105 } 1106 } 1107 1108 return 0; 1109 } 1110 1111 slop1 = (4 - ((long)rp & 3)) & 3; 1112 slop2 = (num - slop1) & 3; 1113 num -= slop1 + slop2; 1114 n8 = num >> 5; 1115 num = (num >> 2) & 7; 1116 1117 while (height--) { 1118 dp = rp; 1119 DELTA(rp, ri->ri_stride, int32_t *); 1120 1121 /* Align span to 4 bytes */ 1122 if (slop1 & 1) { 1123 *(u_char *)dp = clr; 1124 DELTA(dp, 1, int32_t *); 1125 } 1126 1127 if (slop1 & 2) { 1128 *(int16_t *)dp = clr; 1129 DELTA(dp, 2, int32_t *); 1130 } 1131 1132 /* Write 32 bytes per loop */ 1133 for (cnt = n8; cnt; cnt--) { 1134 dp[0] = clr; 1135 dp[1] = clr; 1136 dp[2] = clr; 1137 dp[3] = clr; 1138 dp[4] = clr; 1139 dp[5] = clr; 1140 dp[6] = clr; 1141 dp[7] = clr; 1142 dp += 8; 1143 } 1144 1145 /* Write 4 bytes per loop */ 1146 for (cnt = num; cnt; cnt--) 1147 *dp++ = clr; 1148 1149 /* Write unaligned trailing slop */ 1150 if (slop2 & 1) { 1151 *(u_char *)dp = clr; 1152 DELTA(dp, 1, int32_t *); 1153 } 1154 1155 if (slop2 & 2) 1156 *(int16_t *)dp = clr; 1157 } 1158 1159 return 0; 1160 } 1161 1162 #if NRASOPS_ROTATION > 0 1163 /* 1164 * Quarter clockwise rotation routines (originally intended for the 1165 * built-in Zaurus C3x00 display in 16bpp). 1166 */ 1167 1168 #include <sys/malloc.h> 1169 1170 void 1171 rasops_rotate_font(int *cookie) 1172 { 1173 struct rotatedfont *f; 1174 int ncookie; 1175 1176 SLIST_FOREACH(f, &rotatedfonts, rf_next) { 1177 if (f->rf_cookie == *cookie) { 1178 *cookie = f->rf_rotated; 1179 return; 1180 } 1181 } 1182 1183 /* 1184 * We did not find a rotated version of this font. Ask the wsfont 1185 * code to compute one for us. 1186 */ 1187 if ((ncookie = wsfont_rotate(*cookie)) == -1) 1188 return; 1189 1190 f = malloc(sizeof(struct rotatedfont), M_DEVBUF, M_WAITOK); 1191 f->rf_cookie = *cookie; 1192 f->rf_rotated = ncookie; 1193 SLIST_INSERT_HEAD(&rotatedfonts, f, rf_next); 1194 1195 *cookie = ncookie; 1196 } 1197 1198 void 1199 rasops_copychar(void *cookie, int srcrow, int dstrow, int srccol, int dstcol) 1200 { 1201 struct rasops_info *ri; 1202 u_char *sp, *dp; 1203 int height; 1204 int r_srcrow, r_dstrow, r_srccol, r_dstcol; 1205 1206 ri = (struct rasops_info *)cookie; 1207 1208 r_srcrow = srccol; 1209 r_dstrow = dstcol; 1210 r_srccol = ri->ri_rows - srcrow - 1; 1211 r_dstcol = ri->ri_rows - dstrow - 1; 1212 1213 r_srcrow *= ri->ri_yscale; 1214 r_dstrow *= ri->ri_yscale; 1215 height = ri->ri_font->fontheight; 1216 1217 sp = ri->ri_bits + r_srcrow + r_srccol * ri->ri_xscale; 1218 dp = ri->ri_bits + r_dstrow + r_dstcol * ri->ri_xscale; 1219 1220 #if NRASOPS_BSWAP > 0 1221 if (ri->ri_flg & RI_BSWAP) { 1222 while (height--) { 1223 slow_bcopy(sp, dp, ri->ri_xscale); 1224 dp += ri->ri_stride; 1225 sp += ri->ri_stride; 1226 } 1227 } else 1228 #endif 1229 { 1230 while (height--) { 1231 memmove(dp, sp, ri->ri_xscale); 1232 dp += ri->ri_stride; 1233 sp += ri->ri_stride; 1234 } 1235 } 1236 } 1237 1238 int 1239 rasops_putchar_rotated(void *cookie, int row, int col, u_int uc, long attr) 1240 { 1241 struct rasops_info *ri; 1242 u_char *rp; 1243 int height; 1244 int rc; 1245 1246 ri = (struct rasops_info *)cookie; 1247 1248 /* Do rotated char sans (side)underline */ 1249 rc = ri->ri_real_ops.putchar(cookie, col, ri->ri_rows - row - 1, uc, 1250 attr & ~1); 1251 if (rc != 0) 1252 return rc; 1253 1254 /* Do rotated underline */ 1255 rp = ri->ri_bits + col * ri->ri_yscale + (ri->ri_rows - row - 1) * 1256 ri->ri_xscale; 1257 height = ri->ri_font->fontheight; 1258 1259 /* XXX this assumes 16-bit color depth */ 1260 if ((attr & 1) != 0) { 1261 int16_t c = (int16_t)ri->ri_devcmap[((u_int)attr >> 24) & 0xf]; 1262 1263 while (height--) { 1264 *(int16_t *)rp = c; 1265 rp += ri->ri_stride; 1266 } 1267 } 1268 1269 return 0; 1270 } 1271 1272 int 1273 rasops_erasecols_rotated(void *cookie, int row, int col, int num, long attr) 1274 { 1275 struct rasops_info *ri; 1276 int i; 1277 int rc; 1278 1279 ri = (struct rasops_info *)cookie; 1280 1281 for (i = col; i < col + num; i++) { 1282 rc = ri->ri_ops.putchar(cookie, row, i, ' ', attr); 1283 if (rc != 0) 1284 return rc; 1285 } 1286 1287 return 0; 1288 } 1289 1290 /* XXX: these could likely be optimised somewhat. */ 1291 int 1292 rasops_copyrows_rotated(void *cookie, int src, int dst, int num) 1293 { 1294 struct rasops_info *ri = (struct rasops_info *)cookie; 1295 int col, roff; 1296 1297 if (src > dst) { 1298 for (roff = 0; roff < num; roff++) 1299 for (col = 0; col < ri->ri_cols; col++) 1300 rasops_copychar(cookie, src + roff, dst + roff, 1301 col, col); 1302 } else { 1303 for (roff = num - 1; roff >= 0; roff--) 1304 for (col = 0; col < ri->ri_cols; col++) 1305 rasops_copychar(cookie, src + roff, dst + roff, 1306 col, col); 1307 } 1308 1309 return 0; 1310 } 1311 1312 int 1313 rasops_copycols_rotated(void *cookie, int row, int src, int dst, int num) 1314 { 1315 int coff; 1316 1317 if (src > dst) { 1318 for (coff = 0; coff < num; coff++) 1319 rasops_copychar(cookie, row, row, src + coff, 1320 dst + coff); 1321 } else { 1322 for (coff = num - 1; coff >= 0; coff--) 1323 rasops_copychar(cookie, row, row, src + coff, 1324 dst + coff); 1325 } 1326 1327 return 0; 1328 } 1329 1330 int 1331 rasops_eraserows_rotated(void *cookie, int row, int num, long attr) 1332 { 1333 struct rasops_info *ri; 1334 int col, rn; 1335 int rc; 1336 1337 ri = (struct rasops_info *)cookie; 1338 1339 for (rn = row; rn < row + num; rn++) 1340 for (col = 0; col < ri->ri_cols; col++) { 1341 rc = ri->ri_ops.putchar(cookie, rn, col, ' ', attr); 1342 if (rc != 0) 1343 return rc; 1344 } 1345 1346 return 0; 1347 } 1348 #endif /* NRASOPS_ROTATION */ 1349 1350 #if NRASOPS_BSWAP > 0 1351 /* 1352 * Strictly byte-only bcopy() version, to be used with RI_BSWAP, as the 1353 * regular bcopy() may want to optimize things by doing larger-than-byte 1354 * reads or write. This may confuse things if src and dst have different 1355 * alignments. 1356 */ 1357 void 1358 slow_bcopy(void *s, void *d, size_t len) 1359 { 1360 u_int8_t *src = s; 1361 u_int8_t *dst = d; 1362 1363 if ((vaddr_t)dst <= (vaddr_t)src) { 1364 while (len-- != 0) 1365 *dst++ = *src++; 1366 } else { 1367 src += len; 1368 dst += len; 1369 if (len != 0) 1370 while (--len != 0) 1371 *--dst = *--src; 1372 } 1373 } 1374 #endif /* NRASOPS_BSWAP */ 1375 1376 struct rasops_screen { 1377 LIST_ENTRY(rasops_screen) rs_next; 1378 struct rasops_info *rs_ri; 1379 1380 struct wsdisplay_charcell *rs_bs; 1381 int rs_visible; 1382 int rs_crow; 1383 int rs_ccol; 1384 }; 1385 1386 int 1387 rasops_alloc_screen(void *v, void **cookiep, 1388 int *curxp, int *curyp, long *attrp) 1389 { 1390 struct rasops_info *ri = v; 1391 struct rasops_screen *scr; 1392 int i; 1393 1394 scr = malloc(sizeof(*scr), M_DEVBUF, M_NOWAIT); 1395 if (scr == NULL) 1396 return (ENOMEM); 1397 1398 scr->rs_bs = mallocarray(ri->ri_rows, 1399 ri->ri_cols * sizeof(struct wsdisplay_charcell), M_DEVBUF, 1400 M_NOWAIT); 1401 if (scr->rs_bs == NULL) { 1402 free(scr, M_DEVBUF, sizeof(*scr)); 1403 return (ENOMEM); 1404 } 1405 1406 *cookiep = scr; 1407 *curxp = 0; 1408 *curyp = 0; 1409 ri->ri_alloc_attr(ri, 0, 0, 0, attrp); 1410 1411 scr->rs_ri = ri; 1412 scr->rs_visible = (ri->ri_nscreens == 0); 1413 scr->rs_crow = -1; 1414 scr->rs_ccol = -1; 1415 1416 if (ri->ri_bs) { 1417 memcpy(scr->rs_bs, ri->ri_bs, ri->ri_rows * ri->ri_cols * 1418 sizeof(struct wsdisplay_charcell)); 1419 } else { 1420 for (i = 0; i < ri->ri_rows * ri->ri_cols; i++) { 1421 scr->rs_bs[i].uc = ' '; 1422 scr->rs_bs[i].attr = *attrp; 1423 } 1424 } 1425 1426 LIST_INSERT_HEAD(&ri->ri_screens, scr, rs_next); 1427 ri->ri_nscreens++; 1428 1429 return (0); 1430 } 1431 1432 void 1433 rasops_free_screen(void *v, void *cookie) 1434 { 1435 struct rasops_info *ri = v; 1436 struct rasops_screen *scr = cookie; 1437 1438 LIST_REMOVE(scr, rs_next); 1439 ri->ri_nscreens--; 1440 1441 free(scr->rs_bs, M_DEVBUF, 1442 ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell)); 1443 free(scr, M_DEVBUF, sizeof(*scr)); 1444 } 1445 1446 int 1447 rasops_show_screen(void *v, void *cookie, int waitok, 1448 void (*cb)(void *, int, int), void *cbarg) 1449 { 1450 struct rasops_info *ri = v; 1451 1452 ri->ri_switchcookie = cookie; 1453 if (cb) { 1454 ri->ri_switchcb = cb; 1455 ri->ri_switchcbarg = cbarg; 1456 task_add(systq, &ri->ri_switchtask); 1457 return (EAGAIN); 1458 } 1459 1460 rasops_doswitch(ri); 1461 return (0); 1462 } 1463 1464 void 1465 rasops_doswitch(void *v) 1466 { 1467 struct rasops_info *ri = v; 1468 struct rasops_screen *scr = ri->ri_switchcookie; 1469 int row, col; 1470 long attr; 1471 1472 rasops_cursor(ri, 0, 0, 0); 1473 ri->ri_active->rs_visible = 0; 1474 ri->ri_alloc_attr(ri, 0, 0, 0, &attr); 1475 ri->ri_eraserows(ri, 0, ri->ri_rows, attr); 1476 ri->ri_active = scr; 1477 ri->ri_active->rs_visible = 1; 1478 for (row = 0; row < ri->ri_rows; row++) { 1479 for (col = 0; col < ri->ri_cols; col++) { 1480 int off = row * scr->rs_ri->ri_cols + col; 1481 1482 ri->ri_putchar(ri, row, col, scr->rs_bs[off].uc, 1483 scr->rs_bs[off].attr); 1484 } 1485 } 1486 if (scr->rs_crow != -1) 1487 rasops_cursor(ri, 1, scr->rs_crow, scr->rs_ccol); 1488 1489 if (ri->ri_switchcb) 1490 (*ri->ri_switchcb)(ri->ri_switchcbarg, 0, 0); 1491 } 1492 1493 int 1494 rasops_getchar(void *v, int row, int col, struct wsdisplay_charcell *cell) 1495 { 1496 struct rasops_info *ri = v; 1497 struct rasops_screen *scr = ri->ri_active; 1498 1499 if (scr == NULL || scr->rs_bs == NULL) 1500 return (1); 1501 1502 *cell = scr->rs_bs[row * ri->ri_cols + col]; 1503 return (0); 1504 } 1505 1506 int 1507 rasops_vcons_cursor(void *cookie, int on, int row, int col) 1508 { 1509 struct rasops_screen *scr = cookie; 1510 1511 scr->rs_crow = on ? row : -1; 1512 scr->rs_ccol = on ? col : -1; 1513 1514 if (!scr->rs_visible) 1515 return 0; 1516 1517 return rasops_cursor(scr->rs_ri, on, row, col); 1518 } 1519 1520 int 1521 rasops_vcons_mapchar(void *cookie, int c, u_int *cp) 1522 { 1523 struct rasops_screen *scr = cookie; 1524 1525 return rasops_mapchar(scr->rs_ri, c, cp); 1526 } 1527 1528 int 1529 rasops_vcons_putchar(void *cookie, int row, int col, u_int uc, long attr) 1530 { 1531 struct rasops_screen *scr = cookie; 1532 int off = row * scr->rs_ri->ri_cols + col; 1533 1534 scr->rs_bs[off].uc = uc; 1535 scr->rs_bs[off].attr = attr; 1536 1537 if (!scr->rs_visible) 1538 return 0; 1539 1540 return scr->rs_ri->ri_putchar(scr->rs_ri, row, col, uc, attr); 1541 } 1542 1543 int 1544 rasops_vcons_copycols(void *cookie, int row, int src, int dst, int num) 1545 { 1546 struct rasops_screen *scr = cookie; 1547 struct rasops_info *ri = scr->rs_ri; 1548 int cols = scr->rs_ri->ri_cols; 1549 int col, rc; 1550 1551 memmove(&scr->rs_bs[row * cols + dst], &scr->rs_bs[row * cols + src], 1552 num * sizeof(struct wsdisplay_charcell)); 1553 1554 if (!scr->rs_visible) 1555 return 0; 1556 1557 if ((ri->ri_flg & RI_WRONLY) == 0) 1558 return ri->ri_copycols(ri, row, src, dst, num); 1559 1560 for (col = dst; col < dst + num; col++) { 1561 int off = row * cols + col; 1562 1563 rc = ri->ri_putchar(ri, row, col, 1564 scr->rs_bs[off].uc, scr->rs_bs[off].attr); 1565 if (rc != 0) 1566 return rc; 1567 } 1568 1569 return 0; 1570 } 1571 1572 int 1573 rasops_vcons_erasecols(void *cookie, int row, int col, int num, long attr) 1574 { 1575 struct rasops_screen *scr = cookie; 1576 int cols = scr->rs_ri->ri_cols; 1577 int i; 1578 1579 for (i = 0; i < num; i++) { 1580 scr->rs_bs[row * cols + col + i].uc = ' '; 1581 scr->rs_bs[row * cols + col + i].attr = attr; 1582 } 1583 1584 if (!scr->rs_visible) 1585 return 0; 1586 1587 return scr->rs_ri->ri_erasecols(scr->rs_ri, row, col, num, attr); 1588 } 1589 1590 int 1591 rasops_vcons_copyrows(void *cookie, int src, int dst, int num) 1592 { 1593 struct rasops_screen *scr = cookie; 1594 struct rasops_info *ri = scr->rs_ri; 1595 int cols = ri->ri_cols; 1596 int row, col, rc; 1597 1598 memmove(&scr->rs_bs[dst * cols], &scr->rs_bs[src * cols], 1599 num * cols * sizeof(struct wsdisplay_charcell)); 1600 1601 if (!scr->rs_visible) 1602 return 0; 1603 1604 if ((ri->ri_flg & RI_WRONLY) == 0) 1605 return ri->ri_copyrows(ri, src, dst, num); 1606 1607 for (row = dst; row < dst + num; row++) { 1608 for (col = 0; col < cols; col++) { 1609 int off = row * cols + col; 1610 1611 rc = ri->ri_putchar(ri, row, col, 1612 scr->rs_bs[off].uc, scr->rs_bs[off].attr); 1613 if (rc != 0) 1614 return rc; 1615 } 1616 } 1617 1618 return 0; 1619 } 1620 1621 int 1622 rasops_vcons_eraserows(void *cookie, int row, int num, long attr) 1623 { 1624 struct rasops_screen *scr = cookie; 1625 int cols = scr->rs_ri->ri_cols; 1626 int i; 1627 1628 for (i = 0; i < num * cols; i++) { 1629 scr->rs_bs[row * cols + i].uc = ' '; 1630 scr->rs_bs[row * cols + i].attr = attr; 1631 } 1632 1633 if (!scr->rs_visible) 1634 return 0; 1635 1636 return scr->rs_ri->ri_eraserows(scr->rs_ri, row, num, attr); 1637 } 1638 1639 int 1640 rasops_vcons_alloc_attr(void *cookie, int fg, int bg, int flg, long *attr) 1641 { 1642 struct rasops_screen *scr = cookie; 1643 1644 return scr->rs_ri->ri_alloc_attr(scr->rs_ri, fg, bg, flg, attr); 1645 } 1646 1647 void 1648 rasops_vcons_unpack_attr(void *cookie, long attr, int *fg, int *bg, 1649 int *underline) 1650 { 1651 struct rasops_screen *scr = cookie; 1652 1653 rasops_unpack_attr(scr->rs_ri, attr, fg, bg, underline); 1654 } 1655 1656 int 1657 rasops_wronly_putchar(void *cookie, int row, int col, u_int uc, long attr) 1658 { 1659 struct rasops_info *ri = cookie; 1660 int off = row * ri->ri_cols + col; 1661 1662 ri->ri_bs[off].uc = uc; 1663 ri->ri_bs[off].attr = attr; 1664 1665 return ri->ri_putchar(ri, row, col, uc, attr); 1666 } 1667 1668 int 1669 rasops_wronly_copycols(void *cookie, int row, int src, int dst, int num) 1670 { 1671 struct rasops_info *ri = cookie; 1672 int cols = ri->ri_cols; 1673 int col, rc; 1674 1675 memmove(&ri->ri_bs[row * cols + dst], &ri->ri_bs[row * cols + src], 1676 num * sizeof(struct wsdisplay_charcell)); 1677 1678 for (col = dst; col < dst + num; col++) { 1679 int off = row * cols + col; 1680 1681 rc = ri->ri_putchar(ri, row, col, 1682 ri->ri_bs[off].uc, ri->ri_bs[off].attr); 1683 if (rc != 0) 1684 return rc; 1685 } 1686 1687 return 0; 1688 } 1689 1690 int 1691 rasops_wronly_erasecols(void *cookie, int row, int col, int num, long attr) 1692 { 1693 struct rasops_info *ri = cookie; 1694 int cols = ri->ri_cols; 1695 int i; 1696 1697 for (i = 0; i < num; i++) { 1698 ri->ri_bs[row * cols + col + i].uc = ' '; 1699 ri->ri_bs[row * cols + col + i].attr = attr; 1700 } 1701 1702 return ri->ri_erasecols(ri, row, col, num, attr); 1703 } 1704 1705 int 1706 rasops_wronly_copyrows(void *cookie, int src, int dst, int num) 1707 { 1708 struct rasops_info *ri = cookie; 1709 int cols = ri->ri_cols; 1710 int row, col, rc; 1711 1712 memmove(&ri->ri_bs[dst * cols], &ri->ri_bs[src * cols], 1713 num * cols * sizeof(struct wsdisplay_charcell)); 1714 1715 for (row = dst; row < dst + num; row++) { 1716 for (col = 0; col < cols; col++) { 1717 int off = row * cols + col; 1718 1719 rc = ri->ri_putchar(ri, row, col, 1720 ri->ri_bs[off].uc, ri->ri_bs[off].attr); 1721 if (rc != 0) 1722 return rc; 1723 } 1724 } 1725 1726 return 0; 1727 } 1728 1729 int 1730 rasops_wronly_eraserows(void *cookie, int row, int num, long attr) 1731 { 1732 struct rasops_info *ri = cookie; 1733 int cols = ri->ri_cols; 1734 int i; 1735 1736 for (i = 0; i < num * cols; i++) { 1737 ri->ri_bs[row * cols + i].uc = ' '; 1738 ri->ri_bs[row * cols + i].attr = attr; 1739 } 1740 1741 return ri->ri_eraserows(ri, row, num, attr); 1742 } 1743 1744 /* 1745 * Font management. 1746 * 1747 * Fonts usable on raster frame buffers are managed by wsfont, and are not 1748 * tied to any particular display. 1749 */ 1750 1751 int 1752 rasops_add_font(struct rasops_info *ri, struct wsdisplay_font *font) 1753 { 1754 /* only accept matching metrics */ 1755 if (font->fontwidth != ri->ri_font->fontwidth || 1756 font->fontheight != ri->ri_font->fontheight) 1757 return EINVAL; 1758 1759 /* for raster consoles, only accept ISO Latin-1 or Unicode encoding */ 1760 if (font->encoding != WSDISPLAY_FONTENC_ISO) 1761 return EINVAL; 1762 1763 if (wsfont_add(font, 1) != 0) 1764 return EEXIST; /* name collision */ 1765 1766 font->index = -1; /* do not store in wsdisplay_softc */ 1767 1768 return 0; 1769 } 1770 1771 int 1772 rasops_use_font(struct rasops_info *ri, struct wsdisplay_font *font) 1773 { 1774 int wsfcookie; 1775 struct wsdisplay_font *wsf; 1776 const char *name; 1777 1778 /* allow an empty font name to revert to the initial font choice */ 1779 name = font->name; 1780 if (*name == '\0') 1781 name = NULL; 1782 1783 wsfcookie = wsfont_find(name, ri->ri_font->fontwidth, 1784 ri->ri_font->fontheight, 0); 1785 if (wsfcookie < 0) { 1786 wsfcookie = wsfont_find(name, 0, 0, 0); 1787 if (wsfcookie < 0) 1788 return ENOENT; /* font exist, but different metrics */ 1789 else 1790 return EINVAL; 1791 } 1792 if (wsfont_lock(wsfcookie, &wsf, WSDISPLAY_FONTORDER_KNOWN, 1793 WSDISPLAY_FONTORDER_KNOWN) < 0) 1794 return EINVAL; 1795 1796 /* if (ri->ri_wsfcookie >= 0) */ 1797 wsfont_unlock(ri->ri_wsfcookie); 1798 ri->ri_wsfcookie = wsfcookie; 1799 ri->ri_font = wsf; 1800 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 1801 1802 return 0; 1803 } 1804 1805 int 1806 rasops_load_font(void *v, void *cookie, struct wsdisplay_font *font) 1807 { 1808 struct rasops_info *ri = v; 1809 1810 /* 1811 * For now, we want to only allow loading fonts of the same 1812 * metrics as the currently in-use font. This requires the 1813 * rasops struct to have been correctly configured, and a 1814 * font to have been selected. 1815 */ 1816 if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL) 1817 return EINVAL; 1818 1819 if (font->data != NULL) 1820 return rasops_add_font(ri, font); 1821 else 1822 return rasops_use_font(ri, font); 1823 } 1824 1825 struct rasops_list_font_ctx { 1826 struct rasops_info *ri; 1827 int cnt; 1828 struct wsdisplay_font *font; 1829 }; 1830 1831 int 1832 rasops_list_font_cb(void *cbarg, struct wsdisplay_font *font) 1833 { 1834 struct rasops_list_font_ctx *ctx = cbarg; 1835 1836 if (font->fontheight != ctx->ri->ri_font->fontheight || 1837 font->fontwidth != ctx->ri->ri_font->fontwidth) 1838 return 0; 1839 1840 if (ctx->cnt-- == 0) { 1841 ctx->font = font; 1842 return 1; 1843 } 1844 1845 return 0; 1846 } 1847 1848 int 1849 rasops_list_font(void *v, struct wsdisplay_font *font) 1850 { 1851 struct rasops_info *ri = v; 1852 struct rasops_list_font_ctx ctx; 1853 int idx; 1854 1855 if ((ri->ri_flg & RI_CFGDONE) == 0 || ri->ri_font == NULL) 1856 return EINVAL; 1857 1858 if (font->index < 0) 1859 return EINVAL; 1860 1861 ctx.ri = ri; 1862 ctx.cnt = font->index; 1863 ctx.font = NULL; 1864 wsfont_enum(rasops_list_font_cb, &ctx); 1865 1866 if (ctx.font == NULL) 1867 return EINVAL; 1868 1869 idx = font->index; 1870 *font = *ctx.font; /* struct copy */ 1871 font->index = idx; 1872 font->cookie = font->data = NULL; /* don't leak kernel pointers */ 1873 return 0; 1874 } 1875