1 /* $NetBSD: wsdisplay_vcons.c,v 1.53 2021/05/16 08:46:38 mlelstv Exp $ */ 2 3 /*- 4 * Copyright (c) 2005, 2006 Michael Lorenz 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: wsdisplay_vcons.c,v 1.53 2021/05/16 08:46:38 mlelstv Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/buf.h> 36 #include <sys/device.h> 37 #include <sys/ioctl.h> 38 #include <sys/malloc.h> 39 #include <sys/mman.h> 40 #include <sys/tty.h> 41 #include <sys/conf.h> 42 #include <sys/proc.h> 43 #include <sys/kthread.h> 44 #include <sys/tprintf.h> 45 #include <sys/atomic.h> 46 47 #include <dev/wscons/wsdisplayvar.h> 48 #include <dev/wscons/wsconsio.h> 49 #include <dev/wsfont/wsfont.h> 50 #include <dev/rasops/rasops.h> 51 52 #include <dev/wscons/wsdisplay_vconsvar.h> 53 54 #ifdef _KERNEL_OPT 55 #include "opt_wsemul.h" 56 #include "opt_wsdisplay_compat.h" 57 #include "opt_vcons.h" 58 #endif 59 60 #ifdef VCONS_DEBUG 61 #define DPRINTF printf 62 #else 63 #define DPRINTF if (0) printf 64 #endif 65 66 static void vcons_dummy_init_screen(void *, struct vcons_screen *, int, 67 long *); 68 69 static int vcons_ioctl(void *, void *, u_long, void *, int, struct lwp *); 70 static int vcons_alloc_screen(void *, const struct wsscreen_descr *, void **, 71 int *, int *, long *); 72 static void vcons_free_screen(void *, void *); 73 static int vcons_show_screen(void *, void *, int, void (*)(void *, int, int), 74 void *); 75 static int vcons_load_font(void *, void *, struct wsdisplay_font *); 76 77 #ifdef WSDISPLAY_SCROLLSUPPORT 78 static void vcons_scroll(void *, void *, int); 79 static void vcons_do_scroll(struct vcons_screen *); 80 #endif 81 82 static void vcons_do_switch(void *); 83 84 /* methods that work only on text buffers */ 85 static void vcons_copycols_buffer(void *, int, int, int, int); 86 static void vcons_erasecols_buffer(void *, int, int, int, long); 87 static void vcons_copyrows_buffer(void *, int, int, int); 88 static void vcons_eraserows_buffer(void *, int, int, long); 89 static void vcons_putchar_buffer(void *, int, int, u_int, long); 90 91 /* 92 * actual wrapper methods which call both the _buffer ones above and the 93 * driver supplied ones to do the drawing 94 */ 95 static void vcons_copycols(void *, int, int, int, int); 96 static void vcons_erasecols(void *, int, int, int, long); 97 static void vcons_copyrows(void *, int, int, int); 98 static void vcons_eraserows(void *, int, int, long); 99 static void vcons_putchar(void *, int, int, u_int, long); 100 #ifdef VCONS_DRAW_INTR 101 static void vcons_erasecols_cached(void *, int, int, int, long); 102 static void vcons_eraserows_cached(void *, int, int, long); 103 static void vcons_putchar_cached(void *, int, int, u_int, long); 104 #endif 105 static void vcons_cursor(void *, int, int, int); 106 static void vcons_cursor_noread(void *, int, int, int); 107 108 /* 109 * methods that avoid framebuffer reads 110 */ 111 static void vcons_copycols_noread(void *, int, int, int, int); 112 static void vcons_copyrows_noread(void *, int, int, int); 113 114 115 /* support for reading/writing text buffers. For wsmoused */ 116 static int vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *); 117 static int vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *); 118 119 static void vcons_lock(struct vcons_screen *); 120 static void vcons_unlock(struct vcons_screen *); 121 122 #ifdef VCONS_DRAW_INTR 123 static void vcons_intr(void *); 124 static void vcons_softintr(void *); 125 static void vcons_init_thread(void *); 126 #endif 127 128 static int 129 vcons_init_common(struct vcons_data *vd, void *cookie, 130 struct wsscreen_descr *def, struct wsdisplay_accessops *ao, 131 int enable_intr) 132 { 133 134 /* zero out everything so we can rely on untouched fields being 0 */ 135 memset(vd, 0, sizeof(struct vcons_data)); 136 137 vd->cookie = cookie; 138 139 vd->init_screen = vcons_dummy_init_screen; 140 vd->show_screen_cb = NULL; 141 142 /* keep a copy of the accessops that we replace below with our 143 * own wrappers */ 144 vd->ioctl = ao->ioctl; 145 146 /* configure the accessops */ 147 ao->ioctl = vcons_ioctl; 148 ao->alloc_screen = vcons_alloc_screen; 149 ao->free_screen = vcons_free_screen; 150 ao->show_screen = vcons_show_screen; 151 ao->load_font = vcons_load_font; 152 #ifdef WSDISPLAY_SCROLLSUPPORT 153 ao->scroll = vcons_scroll; 154 #endif 155 156 LIST_INIT(&vd->screens); 157 vd->active = NULL; 158 vd->wanted = NULL; 159 vd->currenttype = def; 160 vd->defaulttype = def; 161 callout_init(&vd->switch_callout, 0); 162 callout_setfunc(&vd->switch_callout, vcons_do_switch, vd); 163 #ifdef VCONS_DRAW_INTR 164 vd->cells = 0; 165 vd->attrs = NULL; 166 vd->chars = NULL; 167 vd->cursor_offset = -1; 168 #endif 169 170 /* 171 * a lock to serialize access to the framebuffer. 172 * when switching screens we need to make sure there's no rasops 173 * operation in progress 174 */ 175 #ifdef DIAGNOSTIC 176 vd->switch_poll_count = 0; 177 #endif 178 #ifdef VCONS_DRAW_INTR 179 if (enable_intr) { 180 vd->intr_softint = softint_establish(SOFTINT_SERIAL, 181 vcons_softintr, vd); 182 callout_init(&vd->intr, CALLOUT_MPSAFE); 183 callout_setfunc(&vd->intr, vcons_intr, vd); 184 vd->intr_valid = 1; 185 186 if (kthread_create(PRI_NONE, 0, NULL, vcons_init_thread, vd, 187 NULL, "vcons_init") != 0) { 188 printf("%s: unable to create thread.\n", __func__); 189 return -1; 190 } 191 } 192 #endif 193 return 0; 194 } 195 196 int 197 vcons_init(struct vcons_data *vd, void *cookie, 198 struct wsscreen_descr *def, struct wsdisplay_accessops *ao) 199 { 200 return vcons_init_common(vd, cookie, def, ao, 1); 201 } 202 203 int 204 vcons_earlyinit(struct vcons_data *vd, void *cookie, 205 struct wsscreen_descr *def, struct wsdisplay_accessops *ao) 206 { 207 return vcons_init_common(vd, cookie, def, ao, 0); 208 } 209 210 static void 211 vcons_lock(struct vcons_screen *scr) 212 { 213 #ifdef VCONS_PARANOIA 214 int s; 215 216 s = splhigh(); 217 #endif 218 SCREEN_BUSY(scr); 219 #ifdef VCONS_PARANOIA 220 splx(s); 221 #endif 222 } 223 224 static void 225 vcons_unlock(struct vcons_screen *scr) 226 { 227 #ifdef VCONS_PARANOIA 228 int s; 229 230 s = splhigh(); 231 #endif 232 SCREEN_IDLE(scr); 233 #ifdef VCONS_PARANOIA 234 splx(s); 235 #endif 236 } 237 238 static void 239 vcons_dummy_init_screen(void *cookie, 240 struct vcons_screen *scr, int exists, 241 long *defattr) 242 { 243 244 /* 245 * default init_screen() method. 246 * Needs to be overwritten so we bitch and whine in case anyone ends 247 * up in here. 248 */ 249 printf("vcons_init_screen: dummy function called. Your driver is " 250 "supposed to supply a replacement for proper operation\n"); 251 } 252 253 static int 254 vcons_alloc_buffers(struct vcons_data *vd, struct vcons_screen *scr) 255 { 256 struct rasops_info *ri = &scr->scr_ri; 257 int cnt, i; 258 #ifdef VCONS_DRAW_INTR 259 int size; 260 #endif 261 262 /* 263 * we allocate both chars and attributes in one chunk, attributes first 264 * because they have the (potentially) bigger alignment 265 */ 266 #ifdef WSDISPLAY_SCROLLSUPPORT 267 cnt = (ri->ri_rows + WSDISPLAY_SCROLLBACK_LINES) * ri->ri_cols; 268 scr->scr_lines_in_buffer = WSDISPLAY_SCROLLBACK_LINES; 269 scr->scr_current_line = 0; 270 scr->scr_line_wanted = 0; 271 scr->scr_offset_to_zero = ri->ri_cols * WSDISPLAY_SCROLLBACK_LINES; 272 scr->scr_current_offset = scr->scr_offset_to_zero; 273 #else 274 cnt = ri->ri_rows * ri->ri_cols; 275 #endif 276 scr->scr_attrs = malloc(cnt * (sizeof(long) + 277 sizeof(uint32_t)), M_DEVBUF, M_WAITOK); 278 if (scr->scr_attrs == NULL) 279 return ENOMEM; 280 281 scr->scr_chars = (uint32_t *)&scr->scr_attrs[cnt]; 282 283 /* 284 * fill the attribute buffer with *defattr, chars with 0x20 285 * since we don't know if the driver tries to mimic firmware output or 286 * reset everything we do nothing to VRAM here, any driver that feels 287 * the need to clear screen or something will have to do it on its own 288 * Additional screens will start out in the background anyway so 289 * cleaning or not only really affects the initial console screen 290 */ 291 for (i = 0; i < cnt; i++) { 292 scr->scr_attrs[i] = scr->scr_defattr; 293 scr->scr_chars[i] = 0x20; 294 } 295 296 #ifdef VCONS_DRAW_INTR 297 size = ri->ri_cols * ri->ri_rows; 298 if (size > vd->cells) { 299 if (vd->chars != NULL) free(vd->chars, M_DEVBUF); 300 if (vd->attrs != NULL) free(vd->attrs, M_DEVBUF); 301 vd->cells = size; 302 vd->chars = malloc(size * sizeof(uint32_t), M_DEVBUF, 303 M_WAITOK|M_ZERO); 304 vd->attrs = malloc(size * sizeof(long), M_DEVBUF, 305 M_WAITOK|M_ZERO); 306 vcons_invalidate_cache(vd); 307 } else if (SCREEN_IS_VISIBLE(scr)) 308 vcons_invalidate_cache(vd); 309 #endif 310 return 0; 311 } 312 313 int 314 vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr, 315 int existing, long *defattr) 316 { 317 struct rasops_info *ri = &scr->scr_ri; 318 int i; 319 320 scr->scr_cookie = vd->cookie; 321 scr->scr_vd = scr->scr_origvd = vd; 322 scr->scr_busy = 0; 323 324 if (scr->scr_type == NULL) 325 scr->scr_type = vd->defaulttype; 326 327 /* 328 * call the driver-supplied init_screen function which is expected 329 * to set up rasops_info, override cursor() and probably others 330 */ 331 vd->init_screen(vd->cookie, scr, existing, defattr); 332 333 /* 334 * save the non virtual console aware rasops and replace them with 335 * our wrappers 336 */ 337 vd->eraserows = ri->ri_ops.eraserows; 338 vd->erasecols = ri->ri_ops.erasecols; 339 scr->putchar = ri->ri_ops.putchar; 340 341 if (scr->scr_flags & VCONS_NO_COPYCOLS) { 342 vd->copycols = vcons_copycols_noread; 343 } else { 344 vd->copycols = ri->ri_ops.copycols; 345 } 346 347 if (scr->scr_flags & VCONS_NO_COPYROWS) { 348 vd->copyrows = vcons_copyrows_noread; 349 } else { 350 vd->copyrows = ri->ri_ops.copyrows; 351 } 352 353 if (scr->scr_flags & VCONS_NO_CURSOR) { 354 vd->cursor = vcons_cursor_noread; 355 } else { 356 vd->cursor = ri->ri_ops.cursor; 357 } 358 359 ri->ri_ops.eraserows = vcons_eraserows; 360 ri->ri_ops.erasecols = vcons_erasecols; 361 ri->ri_ops.putchar = vcons_putchar; 362 ri->ri_ops.cursor = vcons_cursor; 363 ri->ri_ops.copycols = vcons_copycols; 364 ri->ri_ops.copyrows = vcons_copyrows; 365 366 367 ri->ri_hw = scr; 368 369 i = ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr); 370 if (i != 0) { 371 #ifdef DIAGNOSTIC 372 printf("vcons: error allocating attribute %d\n", i); 373 #endif 374 scr->scr_defattr = 0; 375 } else 376 scr->scr_defattr = *defattr; 377 378 vcons_alloc_buffers(vd, scr); 379 380 if(vd->active == NULL) { 381 vd->active = scr; 382 SCREEN_VISIBLE(scr); 383 } 384 385 if (existing) { 386 SCREEN_VISIBLE(scr); 387 vd->active = scr; 388 } else { 389 SCREEN_INVISIBLE(scr); 390 } 391 392 LIST_INSERT_HEAD(&vd->screens, scr, next); 393 return 0; 394 } 395 396 static int 397 vcons_load_font(void *v, void *cookie, struct wsdisplay_font *f) 398 { 399 struct vcons_data *vd = v; 400 struct vcons_screen *scr = cookie; 401 struct rasops_info *ri; 402 struct wsdisplay_font *font; 403 int flags = WSFONT_FIND_BITMAP, fcookie; 404 405 /* see if we're asked to add a font or use it */ 406 if (scr == NULL) 407 return 0; 408 409 ri = &scr->scr_ri; 410 411 /* see if the driver knows how to handle multiple fonts */ 412 if ((scr->scr_flags & VCONS_LOADFONT) == 0) { 413 return EOPNOTSUPP; 414 } 415 416 /* now see what fonts we can use */ 417 if (ri->ri_flg & RI_ENABLE_ALPHA) { 418 flags |= WSFONT_FIND_ALPHA; 419 } 420 421 fcookie = wsfont_find(f->name, 0, 0, 0, 0, 0, flags); 422 if (fcookie == -1) 423 return EINVAL; 424 425 wsfont_lock(fcookie, &font); 426 if (font == NULL) 427 return EINVAL; 428 429 /* ok, we got a font. Now clear the screen with the old parameters */ 430 if (SCREEN_IS_VISIBLE(scr)) 431 vd->eraserows(ri, 0, ri->ri_rows, scr->scr_defattr); 432 433 vcons_lock(vd->active); 434 #ifdef VCONS_DRAW_INTR 435 callout_halt(&vd->intr, NULL); 436 #endif 437 /* set the new font and re-initialize things */ 438 ri->ri_font = font; 439 wsfont_unlock(ri->ri_wsfcookie); 440 ri->ri_wsfcookie = fcookie; 441 442 vd->init_screen(vd->cookie, scr, 1, &scr->scr_defattr); 443 DPRINTF("caps %x %x\n", scr->scr_type->capabilities, ri->ri_caps); 444 if (scr->scr_type->capabilities & WSSCREEN_RESIZE) { 445 scr->scr_type->nrows = ri->ri_rows; 446 scr->scr_type->ncols = ri->ri_cols; 447 DPRINTF("new size %d %d\n", ri->ri_rows, ri->ri_cols); 448 } 449 450 451 /* now, throw the old buffers away */ 452 if (scr->scr_attrs) 453 free(scr->scr_attrs, M_DEVBUF); 454 /* allocate new buffers */ 455 vcons_alloc_buffers(vd, scr); 456 457 /* save the potentially changed ri_ops */ 458 vd->eraserows = ri->ri_ops.eraserows; 459 vd->erasecols = ri->ri_ops.erasecols; 460 scr->putchar = ri->ri_ops.putchar; 461 vd->cursor = ri->ri_ops.cursor; 462 463 if (scr->scr_flags & VCONS_NO_COPYCOLS) { 464 vd->copycols = vcons_copycols_noread; 465 } else { 466 vd->copycols = ri->ri_ops.copycols; 467 } 468 469 if (scr->scr_flags & VCONS_NO_COPYROWS) { 470 vd->copyrows = vcons_copyrows_noread; 471 } else { 472 vd->copyrows = ri->ri_ops.copyrows; 473 } 474 475 if (scr->scr_flags & VCONS_NO_CURSOR) { 476 vd->cursor = vcons_cursor_noread; 477 } else { 478 vd->cursor = ri->ri_ops.cursor; 479 } 480 481 /* and put our wrappers back */ 482 ri->ri_ops.eraserows = vcons_eraserows; 483 ri->ri_ops.erasecols = vcons_erasecols; 484 ri->ri_ops.putchar = vcons_putchar; 485 ri->ri_ops.cursor = vcons_cursor; 486 ri->ri_ops.copycols = vcons_copycols; 487 ri->ri_ops.copyrows = vcons_copyrows; 488 vcons_unlock(vd->active); 489 490 /* notify things that we're about to redraw */ 491 if (vd->show_screen_cb != NULL) 492 vd->show_screen_cb(scr, vd->show_screen_cookie); 493 494 #ifdef VCONS_DRAW_INTR 495 /* 496 * XXX 497 * Something(tm) craps all over VRAM somewhere up there if we're 498 * using VCONS_DRAW_INTR. Until I figure out what causes it, just 499 * redraw the screen for now. 500 */ 501 vcons_redraw_screen(vd->active); 502 callout_schedule(&vd->intr, mstohz(33)); 503 #endif 504 /* no need to draw anything, wsdisplay should reset the terminal */ 505 506 return 0; 507 } 508 509 static void 510 vcons_do_switch(void *arg) 511 { 512 struct vcons_data *vd = arg; 513 struct vcons_screen *scr, *oldscr; 514 515 scr = vd->wanted; 516 if (!scr) { 517 printf("vcons_switch_screen: disappeared\n"); 518 vd->switch_cb(vd->switch_cb_arg, EIO, 0); 519 return; 520 } 521 oldscr = vd->active; /* can be NULL! */ 522 523 /* 524 * if there's an old, visible screen we mark it invisible and wait 525 * until it's not busy so we can safely switch 526 */ 527 if (oldscr != NULL) { 528 SCREEN_INVISIBLE(oldscr); 529 if (SCREEN_IS_BUSY(oldscr)) { 530 callout_schedule(&vd->switch_callout, 1); 531 #ifdef DIAGNOSTIC 532 /* bitch if we wait too long */ 533 vd->switch_poll_count++; 534 if (vd->switch_poll_count > 100) { 535 panic("vcons: screen still busy"); 536 } 537 #endif 538 return; 539 } 540 /* invisible screen -> no visible cursor image */ 541 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 542 #ifdef DIAGNOSTIC 543 vd->switch_poll_count = 0; 544 #endif 545 } 546 547 if (scr == oldscr) 548 return; 549 550 #ifdef DIAGNOSTIC 551 if (SCREEN_IS_VISIBLE(scr)) 552 printf("vcons_switch_screen: already active"); 553 #endif 554 555 #ifdef notyet 556 if (vd->currenttype != type) { 557 vcons_set_screentype(vd, type); 558 vd->currenttype = type; 559 } 560 #endif 561 562 SCREEN_VISIBLE(scr); 563 vd->active = scr; 564 vd->wanted = NULL; 565 566 #ifdef VCONS_DRAW_INTR 567 vcons_invalidate_cache(vd); 568 #endif 569 570 if (vd->show_screen_cb != NULL) 571 vd->show_screen_cb(scr, vd->show_screen_cookie); 572 573 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 574 vcons_redraw_screen(scr); 575 576 if (vd->switch_cb) 577 vd->switch_cb(vd->switch_cb_arg, 0, 0); 578 } 579 580 void 581 vcons_redraw_screen(struct vcons_screen *scr) 582 { 583 uint32_t *charptr = scr->scr_chars, c; 584 long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp; 585 struct rasops_info *ri = &scr->scr_ri; 586 struct vcons_data *vd = scr->scr_vd; 587 int i, j, offset, boffset = 0, start = -1; 588 589 mask = 0x00ff00ff; /* background and flags */ 590 cmp = 0xffffffff; /* never match anything */ 591 vcons_lock(scr); 592 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 593 594 /* 595 * only clear the screen when RI_FULLCLEAR is set since we're 596 * going to overwrite every single character cell anyway 597 */ 598 if (ri->ri_flg & RI_FULLCLEAR) { 599 vd->eraserows(ri, 0, ri->ri_rows, 600 scr->scr_defattr); 601 cmp = scr->scr_defattr & mask; 602 } 603 604 /* redraw the screen */ 605 #ifdef WSDISPLAY_SCROLLSUPPORT 606 offset = scr->scr_current_offset; 607 #else 608 offset = 0; 609 #endif 610 for (i = 0; i < ri->ri_rows; i++) { 611 start = -1; 612 for (j = 0; j < ri->ri_cols; j++) { 613 /* 614 * no need to use the wrapper function - we 615 * don't change any characters or attributes 616 * and we already made sure the screen we're 617 * working on is visible 618 */ 619 c = charptr[offset]; 620 a = attrptr[offset]; 621 acmp = a & mask; 622 if (c == ' ') { 623 /* 624 * if we already erased the background 625 * and if this blank uses the same 626 * colour and flags we don't need to do 627 * anything here 628 */ 629 if (acmp == cmp && start == -1) 630 goto next; 631 /* 632 * see if we can optimize things a 633 * little bit by drawing stretches of 634 * blanks using erasecols 635 */ 636 637 if (start == -1) { 638 start = j; 639 last_a = acmp; 640 } else if (acmp != last_a) { 641 /* 642 * different attr, need to 643 * flush & restart 644 */ 645 vd->erasecols(ri, i, start, 646 j - start, last_a); 647 start = j; 648 last_a = acmp; 649 } 650 } else { 651 if (start != -1) { 652 vd->erasecols(ri, i, start, 653 j - start, last_a); 654 start = -1; 655 } 656 657 scr->putchar(ri, i, j, c, a); 658 } 659 next: 660 #ifdef VCONS_DRAW_INTR 661 vd->chars[boffset] = charptr[offset]; 662 vd->attrs[boffset] = attrptr[offset]; 663 #endif 664 offset++; 665 boffset++; 666 } 667 /* end of the line - draw all defered blanks, if any */ 668 if (start != -1) { 669 vd->erasecols(ri, i, start, j - start, last_a); 670 } 671 } 672 ri->ri_flg &= ~RI_CURSOR; 673 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 674 #ifdef VCONS_DRAW_INTR 675 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 676 #endif 677 } 678 vcons_unlock(scr); 679 } 680 681 #ifdef VCONS_DRAW_INTR 682 void 683 vcons_update_screen(struct vcons_screen *scr) 684 { 685 uint32_t *charptr = scr->scr_chars; 686 long *attrptr = scr->scr_attrs; 687 struct rasops_info *ri = &scr->scr_ri; 688 struct vcons_data *vd = scr->scr_vd; 689 int i, j, offset, boffset = 0; 690 691 vcons_lock(scr); 692 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 693 694 /* redraw the screen */ 695 #ifdef WSDISPLAY_SCROLLSUPPORT 696 offset = scr->scr_current_offset; 697 #else 698 offset = 0; 699 #endif 700 /* 701 * we mark the character cell occupied by the cursor as dirty 702 * so we don't have to deal with it 703 * notice that this isn't necessarily the position where rasops 704 * thinks it is, just where we drew it the last time 705 */ 706 if (vd->cursor_offset >= 0) 707 vd->attrs[vd->cursor_offset] = 0xffffffff; 708 709 for (i = 0; i < ri->ri_rows; i++) { 710 for (j = 0; j < ri->ri_cols; j++) { 711 /* 712 * no need to use the wrapper function - we 713 * don't change any characters or attributes 714 * and we already made sure the screen we're 715 * working on is visible 716 */ 717 if ((vd->chars[boffset] != charptr[offset]) || 718 (vd->attrs[boffset] != attrptr[offset])) { 719 scr->putchar(ri, i, j, 720 charptr[offset], attrptr[offset]); 721 vd->chars[boffset] = charptr[offset]; 722 vd->attrs[boffset] = attrptr[offset]; 723 } 724 offset++; 725 boffset++; 726 } 727 } 728 ri->ri_flg &= ~RI_CURSOR; 729 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 730 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 731 } 732 vcons_unlock(scr); 733 } 734 #endif 735 736 static int 737 vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 738 struct lwp *l) 739 { 740 struct vcons_data *vd = v; 741 int error = 0; 742 743 744 switch (cmd) { 745 case WSDISPLAYIO_GETWSCHAR: 746 error = vcons_getwschar((struct vcons_screen *)vs, 747 (struct wsdisplay_char *)data); 748 break; 749 750 case WSDISPLAYIO_PUTWSCHAR: 751 error = vcons_putwschar((struct vcons_screen *)vs, 752 (struct wsdisplay_char *)data); 753 break; 754 755 case WSDISPLAYIO_SET_POLLING: { 756 int poll = *(int *)data; 757 758 /* first call the driver's ioctl handler */ 759 if (vd->ioctl != NULL) 760 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 761 if (poll) { 762 vcons_enable_polling(vd); 763 vcons_hard_switch(LIST_FIRST(&vd->screens)); 764 } else 765 vcons_disable_polling(vd); 766 } 767 break; 768 769 default: 770 if (vd->ioctl != NULL) 771 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 772 else 773 error = EPASSTHROUGH; 774 } 775 776 return error; 777 } 778 779 static int 780 vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 781 int *curxp, int *curyp, long *defattrp) 782 { 783 struct vcons_data *vd = v; 784 struct vcons_screen *scr; 785 struct wsscreen_descr *t = __UNCONST(type); 786 int ret; 787 788 scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO); 789 if (scr == NULL) 790 return ENOMEM; 791 792 scr->scr_flags = 0; 793 scr->scr_status = 0; 794 scr->scr_busy = 0; 795 scr->scr_type = __UNCONST(type); 796 797 ret = vcons_init_screen(vd, scr, 0, defattrp); 798 if (ret != 0) { 799 free(scr, M_DEVBUF); 800 return ret; 801 } 802 if (t->capabilities & WSSCREEN_RESIZE) { 803 t->nrows = scr->scr_ri.ri_rows; 804 t->ncols = scr->scr_ri.ri_cols; 805 } 806 807 if (vd->active == NULL) { 808 SCREEN_VISIBLE(scr); 809 vd->active = scr; 810 vd->currenttype = type; 811 } 812 813 *cookiep = scr; 814 *curxp = scr->scr_ri.ri_ccol; 815 *curyp = scr->scr_ri.ri_crow; 816 return 0; 817 } 818 819 static void 820 vcons_free_screen(void *v, void *cookie) 821 { 822 struct vcons_data *vd = v; 823 struct vcons_screen *scr = cookie; 824 825 vcons_lock(scr); 826 /* there should be no rasops activity here */ 827 828 LIST_REMOVE(scr, next); 829 830 if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) { 831 free(scr->scr_attrs, M_DEVBUF); 832 free(scr, M_DEVBUF); 833 } else { 834 /* 835 * maybe we should just restore the old rasops_info methods 836 * and free the character/attribute buffer here? 837 */ 838 #ifdef VCONS_DEBUG 839 panic("vcons_free_screen: console"); 840 #else 841 printf("vcons_free_screen: console\n"); 842 #endif 843 } 844 845 if (vd->active == scr) 846 vd->active = NULL; 847 } 848 849 static int 850 vcons_show_screen(void *v, void *cookie, int waitok, 851 void (*cb)(void *, int, int), void *cb_arg) 852 { 853 struct vcons_data *vd = v; 854 struct vcons_screen *scr; 855 856 scr = cookie; 857 if (scr == vd->active) 858 return 0; 859 860 vd->wanted = scr; 861 vd->switch_cb = cb; 862 vd->switch_cb_arg = cb_arg; 863 if (cb) { 864 callout_schedule(&vd->switch_callout, 0); 865 return EAGAIN; 866 } 867 868 vcons_do_switch(vd); 869 return 0; 870 } 871 872 /* wrappers for rasops_info methods */ 873 874 static void 875 vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols) 876 { 877 struct rasops_info *ri = cookie; 878 struct vcons_screen *scr = ri->ri_hw; 879 int from = srccol + row * ri->ri_cols; 880 int to = dstcol + row * ri->ri_cols; 881 882 #ifdef WSDISPLAY_SCROLLSUPPORT 883 int offset; 884 offset = scr->scr_offset_to_zero; 885 886 memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from], 887 ncols * sizeof(long)); 888 memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from], 889 ncols * sizeof(uint32_t)); 890 #else 891 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 892 ncols * sizeof(long)); 893 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 894 ncols * sizeof(uint32_t)); 895 #endif 896 897 #ifdef VCONS_DRAW_INTR 898 atomic_inc_uint(&scr->scr_dirty); 899 #endif 900 } 901 902 static void 903 vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 904 { 905 struct rasops_info *ri = cookie; 906 struct vcons_screen *scr = ri->ri_hw; 907 908 vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols); 909 910 #if defined(VCONS_DRAW_INTR) 911 if (scr->scr_vd->use_intr) 912 return; 913 #endif 914 915 vcons_lock(scr); 916 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 917 #if defined(VCONS_DRAW_INTR) 918 vcons_update_screen(scr); 919 #else 920 scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols); 921 #endif 922 } 923 vcons_unlock(scr); 924 } 925 926 static void 927 vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols) 928 { 929 struct rasops_info *ri = cookie; 930 struct vcons_screen *scr = ri->ri_hw; 931 #ifdef VCONS_DRAW_INTR 932 struct vcons_data *vd = scr->scr_vd; 933 #endif 934 935 vcons_lock(scr); 936 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 937 int pos, c, offset, ppos; 938 939 #ifdef WSDISPLAY_SCROLLSUPPORT 940 offset = scr->scr_current_offset; 941 #else 942 offset = 0; 943 #endif 944 ppos = ri->ri_cols * row + dstcol; 945 pos = ppos + offset; 946 for (c = dstcol; c < (dstcol + ncols); c++) { 947 #ifdef VCONS_DRAW_INTR 948 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 949 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 950 scr->putchar(cookie, row, c, 951 scr->scr_chars[pos], scr->scr_attrs[pos]); 952 vd->chars[ppos] = scr->scr_chars[pos]; 953 vd->attrs[ppos] = scr->scr_attrs[pos]; 954 } 955 #else 956 scr->putchar(cookie, row, c, scr->scr_chars[pos], 957 scr->scr_attrs[pos]); 958 #endif 959 pos++; 960 ppos++; 961 } 962 if (ri->ri_crow == row && 963 (ri->ri_ccol >= dstcol && ri->ri_ccol < (dstcol + ncols ))) 964 ri->ri_flg &= ~RI_CURSOR; 965 } 966 vcons_unlock(scr); 967 } 968 969 static void 970 vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr) 971 { 972 struct rasops_info *ri = cookie; 973 struct vcons_screen *scr = ri->ri_hw; 974 int start = startcol + row * ri->ri_cols; 975 int end = start + ncols, i; 976 977 #ifdef WSDISPLAY_SCROLLSUPPORT 978 int offset; 979 offset = scr->scr_offset_to_zero; 980 981 for (i = start; i < end; i++) { 982 scr->scr_attrs[offset + i] = fillattr; 983 scr->scr_chars[offset + i] = 0x20; 984 } 985 #else 986 for (i = start; i < end; i++) { 987 scr->scr_attrs[i] = fillattr; 988 scr->scr_chars[i] = 0x20; 989 } 990 #endif 991 992 #ifdef VCONS_DRAW_INTR 993 atomic_inc_uint(&scr->scr_dirty); 994 #endif 995 } 996 997 #ifdef VCONS_DRAW_INTR 998 static void 999 vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr) 1000 { 1001 struct rasops_info *ri = cookie; 1002 struct vcons_screen *scr = ri->ri_hw; 1003 struct vcons_data *vd = scr->scr_vd; 1004 int i, pos = row * ri->ri_cols + startcol; 1005 1006 for (i = pos; i < ncols; i++) { 1007 vd->chars[i] = 0x20; 1008 vd->attrs[i] = fillattr; 1009 } 1010 vd->erasecols(cookie, row, startcol, ncols, fillattr); 1011 } 1012 #endif 1013 1014 static void 1015 vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1016 { 1017 struct rasops_info *ri = cookie; 1018 struct vcons_screen *scr = ri->ri_hw; 1019 1020 vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr); 1021 1022 #if defined(VCONS_DRAW_INTR) 1023 if (scr->scr_vd->use_intr) 1024 return; 1025 #endif 1026 1027 vcons_lock(scr); 1028 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1029 #ifdef VCONS_DRAW_INTR 1030 vcons_erasecols_cached(cookie, row, startcol, ncols, 1031 fillattr); 1032 #else 1033 scr->scr_vd->erasecols(cookie, row, startcol, ncols, fillattr); 1034 #endif 1035 } 1036 vcons_unlock(scr); 1037 } 1038 1039 static void 1040 vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows) 1041 { 1042 struct rasops_info *ri = cookie; 1043 struct vcons_screen *scr = ri->ri_hw; 1044 int from, to, len; 1045 1046 #ifdef WSDISPLAY_SCROLLSUPPORT 1047 int offset; 1048 offset = scr->scr_offset_to_zero; 1049 1050 /* do we need to scroll the back buffer? */ 1051 if (dstrow == 0) { 1052 from = ri->ri_cols * srcrow; 1053 to = ri->ri_cols * dstrow; 1054 1055 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 1056 scr->scr_offset_to_zero * sizeof(long)); 1057 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 1058 scr->scr_offset_to_zero * sizeof(uint32_t)); 1059 } 1060 from = ri->ri_cols * srcrow + offset; 1061 to = ri->ri_cols * dstrow + offset; 1062 len = ri->ri_cols * nrows; 1063 1064 #else 1065 from = ri->ri_cols * srcrow; 1066 to = ri->ri_cols * dstrow; 1067 len = ri->ri_cols * nrows; 1068 #endif 1069 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 1070 len * sizeof(long)); 1071 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 1072 len * sizeof(uint32_t)); 1073 1074 #ifdef VCONS_DRAW_INTR 1075 atomic_inc_uint(&scr->scr_dirty); 1076 #endif 1077 } 1078 1079 static void 1080 vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1081 { 1082 struct rasops_info *ri = cookie; 1083 struct vcons_screen *scr = ri->ri_hw; 1084 1085 vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows); 1086 1087 #if defined(VCONS_DRAW_INTR) 1088 if (scr->scr_vd->use_intr) 1089 return; 1090 #endif 1091 1092 vcons_lock(scr); 1093 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1094 #if defined(VCONS_DRAW_INTR) 1095 vcons_update_screen(scr); 1096 #else 1097 scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows); 1098 #endif 1099 } 1100 vcons_unlock(scr); 1101 } 1102 1103 static void 1104 vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows) 1105 { 1106 struct rasops_info *ri = cookie; 1107 struct vcons_screen *scr = ri->ri_hw; 1108 #ifdef VCONS_DRAW_INTR 1109 struct vcons_data *vd = scr->scr_vd; 1110 #endif 1111 vcons_lock(scr); 1112 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1113 int pos, l, c, offset, ppos; 1114 1115 #ifdef WSDISPLAY_SCROLLSUPPORT 1116 offset = scr->scr_current_offset; 1117 #else 1118 offset = 0; 1119 #endif 1120 ppos = ri->ri_cols * dstrow; 1121 pos = ppos + offset; 1122 for (l = dstrow; l < (dstrow + nrows); l++) { 1123 for (c = 0; c < ri->ri_cols; c++) { 1124 #ifdef VCONS_DRAW_INTR 1125 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 1126 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 1127 scr->putchar(cookie, l, c, 1128 scr->scr_chars[pos], scr->scr_attrs[pos]); 1129 vd->chars[ppos] = scr->scr_chars[pos]; 1130 vd->attrs[ppos] = scr->scr_attrs[pos]; 1131 } 1132 #else 1133 scr->putchar(cookie, l, c, scr->scr_chars[pos], 1134 scr->scr_attrs[pos]); 1135 #endif 1136 pos++; 1137 ppos++; 1138 } 1139 } 1140 if (ri->ri_crow >= dstrow && ri->ri_crow < (dstrow + nrows)) 1141 ri->ri_flg &= ~RI_CURSOR; 1142 } 1143 vcons_unlock(scr); 1144 } 1145 1146 static void 1147 vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr) 1148 { 1149 struct rasops_info *ri = cookie; 1150 struct vcons_screen *scr = ri->ri_hw; 1151 int start, end, i; 1152 1153 #ifdef WSDISPLAY_SCROLLSUPPORT 1154 int offset; 1155 offset = scr->scr_offset_to_zero; 1156 1157 start = ri->ri_cols * row + offset; 1158 end = ri->ri_cols * (row + nrows) + offset; 1159 #else 1160 start = ri->ri_cols * row; 1161 end = ri->ri_cols * (row + nrows); 1162 #endif 1163 1164 for (i = start; i < end; i++) { 1165 scr->scr_attrs[i] = fillattr; 1166 scr->scr_chars[i] = 0x20; 1167 } 1168 1169 #ifdef VCONS_DRAW_INTR 1170 atomic_inc_uint(&scr->scr_dirty); 1171 #endif 1172 } 1173 1174 #ifdef VCONS_DRAW_INTR 1175 static void 1176 vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr) 1177 { 1178 struct rasops_info *ri = cookie; 1179 struct vcons_screen *scr = ri->ri_hw; 1180 struct vcons_data *vd = scr->scr_vd; 1181 int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols; 1182 1183 for (i = pos; i < end; i++) { 1184 vd->chars[i] = 0x20; 1185 vd->attrs[i] = fillattr; 1186 } 1187 vd->eraserows(cookie, row, nrows, fillattr); 1188 } 1189 #endif 1190 1191 static void 1192 vcons_eraserows(void *cookie, int row, int nrows, long fillattr) 1193 { 1194 struct rasops_info *ri = cookie; 1195 struct vcons_screen *scr = ri->ri_hw; 1196 1197 vcons_eraserows_buffer(cookie, row, nrows, fillattr); 1198 1199 #if defined(VCONS_DRAW_INTR) 1200 if (scr->scr_vd->use_intr) 1201 return; 1202 #endif 1203 1204 vcons_lock(scr); 1205 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1206 #ifdef VCONS_DRAW_INTR 1207 vcons_eraserows_cached(cookie, row, nrows, fillattr); 1208 #else 1209 scr->scr_vd->eraserows(cookie, row, nrows, fillattr); 1210 #endif 1211 } 1212 vcons_unlock(scr); 1213 } 1214 1215 static void 1216 vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr) 1217 { 1218 struct rasops_info *ri = cookie; 1219 struct vcons_screen *scr = ri->ri_hw; 1220 int pos; 1221 1222 #ifdef WSDISPLAY_SCROLLSUPPORT 1223 int offset; 1224 offset = scr->scr_offset_to_zero; 1225 1226 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1227 (col < ri->ri_cols)) { 1228 pos = col + row * ri->ri_cols; 1229 scr->scr_attrs[pos + offset] = attr; 1230 scr->scr_chars[pos + offset] = c; 1231 } 1232 #else 1233 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1234 (col < ri->ri_cols)) { 1235 pos = col + row * ri->ri_cols; 1236 scr->scr_attrs[pos] = attr; 1237 scr->scr_chars[pos] = c; 1238 } 1239 #endif 1240 1241 #ifdef VCONS_DRAW_INTR 1242 atomic_inc_uint(&scr->scr_dirty); 1243 #endif 1244 } 1245 1246 #ifdef VCONS_DRAW_INTR 1247 static void 1248 vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr) 1249 { 1250 struct rasops_info *ri = cookie; 1251 struct vcons_screen *scr = ri->ri_hw; 1252 struct vcons_data *vd = scr->scr_vd; 1253 int pos = row * ri->ri_cols + col; 1254 1255 if ((vd->chars == NULL) || (vd->attrs == NULL)) { 1256 scr->putchar(cookie, row, col, c, attr); 1257 return; 1258 } 1259 if ((vd->chars[pos] != c) || (vd->attrs[pos] != attr)) { 1260 vd->attrs[pos] = attr; 1261 vd->chars[pos] = c; 1262 scr->putchar(cookie, row, col, c, attr); 1263 } 1264 } 1265 #endif 1266 1267 static void 1268 vcons_putchar(void *cookie, int row, int col, u_int c, long attr) 1269 { 1270 struct rasops_info *ri = cookie; 1271 struct vcons_screen *scr = ri->ri_hw; 1272 1273 vcons_putchar_buffer(cookie, row, col, c, attr); 1274 1275 #if defined(VCONS_DRAW_INTR) 1276 if (scr->scr_vd->use_intr) 1277 return; 1278 #endif 1279 1280 vcons_lock(scr); 1281 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1282 #ifdef VCONS_DRAW_INTR 1283 vcons_putchar_cached(cookie, row, col, c, attr); 1284 #else 1285 if (row == ri->ri_crow && col == ri->ri_ccol) { 1286 ri->ri_flg &= ~RI_CURSOR; 1287 } 1288 scr->putchar(cookie, row, col, c, attr); 1289 #endif 1290 } 1291 vcons_unlock(scr); 1292 } 1293 1294 static void 1295 vcons_cursor(void *cookie, int on, int row, int col) 1296 { 1297 struct rasops_info *ri = cookie; 1298 struct vcons_screen *scr = ri->ri_hw; 1299 1300 1301 #if defined(VCONS_DRAW_INTR) 1302 if (scr->scr_vd->use_intr) { 1303 vcons_lock(scr); 1304 if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) { 1305 scr->scr_ri.ri_crow = row; 1306 scr->scr_ri.ri_ccol = col; 1307 atomic_inc_uint(&scr->scr_dirty); 1308 } 1309 vcons_unlock(scr); 1310 return; 1311 } 1312 #endif 1313 1314 vcons_lock(scr); 1315 1316 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1317 scr->scr_vd->cursor(cookie, on, row, col); 1318 } else { 1319 scr->scr_ri.ri_crow = row; 1320 scr->scr_ri.ri_ccol = col; 1321 } 1322 vcons_unlock(scr); 1323 } 1324 1325 static void 1326 vcons_cursor_noread(void *cookie, int on, int row, int col) 1327 { 1328 struct rasops_info *ri = cookie; 1329 struct vcons_screen *scr = ri->ri_hw; 1330 int offset = 0, ofs; 1331 1332 #ifdef WSDISPLAY_SCROLLSUPPORT 1333 offset = scr->scr_current_offset; 1334 #endif 1335 ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol; 1336 if ((ri->ri_flg & RI_CURSOR) && 1337 (((scr->scr_flags & VCONS_DONT_READ) != VCONS_DONT_READ) || on)) { 1338 scr->putchar(cookie, ri->ri_crow, ri->ri_ccol, 1339 scr->scr_chars[ofs], scr->scr_attrs[ofs]); 1340 ri->ri_flg &= ~RI_CURSOR; 1341 } 1342 ri->ri_crow = row; 1343 ri->ri_ccol = col; 1344 ofs = offset + ri->ri_crow * ri->ri_cols + ri->ri_ccol; 1345 if (on) { 1346 scr->putchar(cookie, row, col, scr->scr_chars[ofs], 1347 #ifdef VCONS_DEBUG_CURSOR_NOREAD 1348 /* draw a red cursor so we can tell which cursor() 1349 * implementation is being used */ 1350 ((scr->scr_attrs[ofs] & 0xff00ffff) ^ 0x0f000000) | 1351 0x00010000); 1352 #else 1353 scr->scr_attrs[ofs] ^ 0x0f0f0000); 1354 #endif 1355 ri->ri_flg |= RI_CURSOR; 1356 } 1357 } 1358 1359 /* methods to read/write characters via ioctl() */ 1360 1361 static int 1362 vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1363 { 1364 long attr; 1365 struct rasops_info *ri; 1366 int error; 1367 1368 KASSERT(scr != NULL && wsc != NULL); 1369 1370 ri = &scr->scr_ri; 1371 1372 /* allow col as linear index if row == 0 */ 1373 if (wsc->row == 0) { 1374 if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows)) 1375 return EINVAL; 1376 int rem; 1377 rem = wsc->col % ri->ri_cols; 1378 wsc->row = wsc->col / ri->ri_cols; 1379 DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row); 1380 wsc->col = rem; 1381 } else { 1382 if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols)) 1383 return (EINVAL); 1384 1385 if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows)) 1386 return (EINVAL); 1387 } 1388 1389 error = ri->ri_ops.allocattr(ri, wsc->foreground, 1390 wsc->background, wsc->flags, &attr); 1391 if (error) 1392 return error; 1393 vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr); 1394 #ifdef VCONS_DEBUG 1395 printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col, 1396 wsc->letter, attr); 1397 #endif 1398 return 0; 1399 } 1400 1401 static int 1402 vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1403 { 1404 int offset; 1405 long attr; 1406 struct rasops_info *ri; 1407 int fg, bg, ul; 1408 1409 KASSERT(scr != NULL && wsc != NULL); 1410 1411 ri = &scr->scr_ri; 1412 1413 /* allow col as linear index if row == 0 */ 1414 if (wsc->row == 0) { 1415 if (wsc->col < 0 || wsc->col > (ri->ri_cols * ri->ri_rows)) 1416 return EINVAL; 1417 int rem; 1418 rem = wsc->col % ri->ri_cols; 1419 wsc->row = wsc->col / ri->ri_cols; 1420 DPRINTF("off %d -> %d, %d\n", wsc->col, rem, wsc->row); 1421 wsc->col = rem; 1422 } else { 1423 if (__predict_false(wsc->col < 0 || wsc->col >= ri->ri_cols)) 1424 return (EINVAL); 1425 1426 if (__predict_false(wsc->row < 0 || wsc->row >= ri->ri_rows)) 1427 return (EINVAL); 1428 } 1429 1430 offset = ri->ri_cols * wsc->row + wsc->col; 1431 #ifdef WSDISPLAY_SCROLLSUPPORT 1432 offset += scr->scr_offset_to_zero; 1433 #endif 1434 wsc->letter = scr->scr_chars[offset]; 1435 attr = scr->scr_attrs[offset]; 1436 1437 #ifdef VCONS_DEBUG 1438 printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row, 1439 wsc->col, wsc->letter, attr); 1440 #endif 1441 1442 /* 1443 * this is ugly. We need to break up an attribute into colours and 1444 * flags but there's no rasops method to do that so we must rely on 1445 * the 'canonical' encoding. 1446 */ 1447 1448 /* only fetches underline attribute */ 1449 /* rasops_unpack_attr(attr, &fg, &bg, &ul); */ 1450 fg = (attr >> 24) & 0xf; 1451 bg = (attr >> 16) & 0xf; 1452 ul = (attr & 1); 1453 1454 wsc->foreground = fg; 1455 wsc->background = bg; 1456 1457 /* clear trashed bits and restore underline flag */ 1458 attr &= ~(WSATTR_HILIT | WSATTR_BLINK | WSATTR_UNDERLINE); 1459 if (ul) 1460 attr |= WSATTR_UNDERLINE; 1461 1462 /* restore highlight boost */ 1463 if (attr & WSATTR_HILIT) 1464 if (wsc->foreground >= 8) 1465 wsc->foreground -= 8; 1466 1467 /* we always use colors, even when not stored */ 1468 attr |= WSATTR_WSCOLORS; 1469 return 0; 1470 } 1471 1472 #ifdef WSDISPLAY_SCROLLSUPPORT 1473 1474 static void 1475 vcons_scroll(void *cookie, void *vs, int where) 1476 { 1477 struct vcons_screen *scr = vs; 1478 1479 if (where == 0) { 1480 scr->scr_line_wanted = 0; 1481 } else { 1482 scr->scr_line_wanted = scr->scr_line_wanted - where; 1483 if (scr->scr_line_wanted < 0) 1484 scr->scr_line_wanted = 0; 1485 if (scr->scr_line_wanted > scr->scr_lines_in_buffer) 1486 scr->scr_line_wanted = scr->scr_lines_in_buffer; 1487 } 1488 1489 if (scr->scr_line_wanted != scr->scr_current_line) { 1490 1491 vcons_do_scroll(scr); 1492 } 1493 } 1494 1495 static void 1496 vcons_do_scroll(struct vcons_screen *scr) 1497 { 1498 int dist, from, to, num; 1499 int r_offset, r_start; 1500 int i, j; 1501 1502 if (scr->scr_line_wanted == scr->scr_current_line) 1503 return; 1504 dist = scr->scr_line_wanted - scr->scr_current_line; 1505 scr->scr_current_line = scr->scr_line_wanted; 1506 scr->scr_current_offset = scr->scr_ri.ri_cols * 1507 (scr->scr_lines_in_buffer - scr->scr_current_line); 1508 if (abs(dist) >= scr->scr_ri.ri_rows) { 1509 vcons_redraw_screen(scr); 1510 return; 1511 } 1512 /* scroll and redraw only what we really have to */ 1513 if (dist > 0) { 1514 /* we scroll down */ 1515 from = 0; 1516 to = dist; 1517 num = scr->scr_ri.ri_rows - dist; 1518 /* now the redraw parameters */ 1519 r_offset = scr->scr_current_offset; 1520 r_start = 0; 1521 } else { 1522 /* scrolling up */ 1523 to = 0; 1524 from = -dist; 1525 num = scr->scr_ri.ri_rows + dist; 1526 r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols; 1527 r_start = num; 1528 } 1529 scr->scr_vd->copyrows(scr, from, to, num); 1530 for (i = 0; i < abs(dist); i++) { 1531 for (j = 0; j < scr->scr_ri.ri_cols; j++) { 1532 #ifdef VCONS_DRAW_INTR 1533 vcons_putchar_cached(scr, i + r_start, j, 1534 scr->scr_chars[r_offset], 1535 scr->scr_attrs[r_offset]); 1536 #else 1537 scr->putchar(scr, i + r_start, j, 1538 scr->scr_chars[r_offset], 1539 scr->scr_attrs[r_offset]); 1540 #endif 1541 r_offset++; 1542 } 1543 } 1544 1545 if (scr->scr_line_wanted == 0) { 1546 /* this was a reset - need to draw the cursor */ 1547 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1548 scr->scr_vd->cursor(scr, 1, scr->scr_ri.ri_crow, 1549 scr->scr_ri.ri_ccol); 1550 } 1551 } 1552 1553 #endif /* WSDISPLAY_SCROLLSUPPORT */ 1554 1555 #ifdef VCONS_DRAW_INTR 1556 static void 1557 vcons_intr(void *cookie) 1558 { 1559 struct vcons_data *vd = cookie; 1560 1561 softint_schedule(vd->intr_softint); 1562 } 1563 1564 static void 1565 vcons_softintr(void *cookie) 1566 { 1567 struct vcons_data *vd = cookie; 1568 struct vcons_screen *scr = vd->active; 1569 unsigned int dirty; 1570 1571 if (scr && vd->use_intr) { 1572 if (!SCREEN_IS_BUSY(scr)) { 1573 dirty = atomic_swap_uint(&scr->scr_dirty, 0); 1574 if (vd->use_intr == 2) { 1575 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) { 1576 vd->use_intr = 1; 1577 vcons_redraw_screen(scr); 1578 } 1579 } else if (dirty > 0) { 1580 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1581 vcons_update_screen(scr); 1582 } 1583 } 1584 } 1585 1586 callout_schedule(&vd->intr, mstohz(33)); 1587 } 1588 1589 static void 1590 vcons_init_thread(void *cookie) 1591 { 1592 struct vcons_data *vd = (struct vcons_data *)cookie; 1593 1594 vd->use_intr = 2; 1595 callout_schedule(&vd->intr, mstohz(33)); 1596 kthread_exit(0); 1597 } 1598 #endif /* VCONS_DRAW_INTR */ 1599 1600 void 1601 vcons_enable_polling(struct vcons_data *vd) 1602 { 1603 struct vcons_screen *scr = vd->active; 1604 1605 #ifdef VCONS_DRAW_INTR 1606 vd->use_intr = 0; 1607 #endif 1608 1609 if (scr && !SCREEN_IS_BUSY(scr)) { 1610 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1611 vcons_redraw_screen(scr); 1612 } 1613 } 1614 1615 void 1616 vcons_disable_polling(struct vcons_data *vd) 1617 { 1618 #ifdef VCONS_DRAW_INTR 1619 struct vcons_screen *scr = vd->active; 1620 1621 if (!vd->intr_valid) 1622 return; 1623 1624 vd->use_intr = 2; 1625 if (scr) 1626 atomic_inc_uint(&scr->scr_dirty); 1627 #endif 1628 } 1629 1630 void 1631 vcons_hard_switch(struct vcons_screen *scr) 1632 { 1633 struct vcons_data *vd = scr->scr_vd; 1634 struct vcons_screen *oldscr = vd->active; 1635 1636 if (oldscr) { 1637 SCREEN_INVISIBLE(oldscr); 1638 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 1639 } 1640 SCREEN_VISIBLE(scr); 1641 vd->active = scr; 1642 vd->wanted = NULL; 1643 1644 if (vd->show_screen_cb != NULL) 1645 vd->show_screen_cb(scr, vd->show_screen_cookie); 1646 } 1647 1648 #ifdef VCONS_DRAW_INTR 1649 void 1650 vcons_invalidate_cache(struct vcons_data *vd) 1651 { 1652 int i; 1653 1654 for (i = 0; i < vd->cells; i++) { 1655 vd->chars[i] = -1; 1656 vd->attrs[i] = -1; 1657 } 1658 } 1659 #endif 1660