1 /* $NetBSD: wsdisplay_vcons.c,v 1.34 2015/07/19 13:22:42 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.34 2015/07/19 13:22:42 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 static void vcons_dummy_init_screen(void *, struct vcons_screen *, int, 61 long *); 62 63 static int vcons_ioctl(void *, void *, u_long, void *, int, struct lwp *); 64 static int vcons_alloc_screen(void *, const struct wsscreen_descr *, void **, 65 int *, int *, long *); 66 static void vcons_free_screen(void *, void *); 67 static int vcons_show_screen(void *, void *, int, void (*)(void *, int, int), 68 void *); 69 70 #ifdef WSDISPLAY_SCROLLSUPPORT 71 static void vcons_scroll(void *, void *, int); 72 static void vcons_do_scroll(struct vcons_screen *); 73 #endif 74 75 static void vcons_do_switch(void *); 76 77 /* methods that work only on text buffers */ 78 static void vcons_copycols_buffer(void *, int, int, int, int); 79 static void vcons_erasecols_buffer(void *, int, int, int, long); 80 static void vcons_copyrows_buffer(void *, int, int, int); 81 static void vcons_eraserows_buffer(void *, int, int, long); 82 static void vcons_putchar_buffer(void *, int, int, u_int, long); 83 84 /* 85 * actual wrapper methods which call both the _buffer ones above and the 86 * driver supplied ones to do the drawing 87 */ 88 static void vcons_copycols(void *, int, int, int, int); 89 static void vcons_erasecols(void *, int, int, int, long); 90 static void vcons_copyrows(void *, int, int, int); 91 static void vcons_eraserows(void *, int, int, long); 92 static void vcons_putchar(void *, int, int, u_int, long); 93 #ifdef VCONS_DRAW_INTR 94 static void vcons_erasecols_cached(void *, int, int, int, long); 95 static void vcons_eraserows_cached(void *, int, int, long); 96 static void vcons_putchar_cached(void *, int, int, u_int, long); 97 #endif 98 static void vcons_cursor(void *, int, int, int); 99 100 /* 101 * methods that avoid framebuffer reads 102 */ 103 static void vcons_copycols_noread(void *, int, int, int, int); 104 static void vcons_copyrows_noread(void *, int, int, int); 105 106 107 /* support for reading/writing text buffers. For wsmoused */ 108 static int vcons_putwschar(struct vcons_screen *, struct wsdisplay_char *); 109 static int vcons_getwschar(struct vcons_screen *, struct wsdisplay_char *); 110 111 static void vcons_lock(struct vcons_screen *); 112 static void vcons_unlock(struct vcons_screen *); 113 114 #ifdef VCONS_DRAW_INTR 115 static void vcons_intr(void *); 116 static void vcons_softintr(void *); 117 static void vcons_intr_enable(device_t); 118 #endif 119 120 int 121 vcons_init(struct vcons_data *vd, void *cookie, struct wsscreen_descr *def, 122 struct wsdisplay_accessops *ao) 123 { 124 125 /* zero out everything so we can rely on untouched fields being 0 */ 126 memset(vd, 0, sizeof(struct vcons_data)); 127 128 vd->cookie = cookie; 129 130 vd->init_screen = vcons_dummy_init_screen; 131 vd->show_screen_cb = NULL; 132 133 /* keep a copy of the accessops that we replace below with our 134 * own wrappers */ 135 vd->ioctl = ao->ioctl; 136 137 /* configure the accessops */ 138 ao->ioctl = vcons_ioctl; 139 ao->alloc_screen = vcons_alloc_screen; 140 ao->free_screen = vcons_free_screen; 141 ao->show_screen = vcons_show_screen; 142 #ifdef WSDISPLAY_SCROLLSUPPORT 143 ao->scroll = vcons_scroll; 144 #endif 145 146 LIST_INIT(&vd->screens); 147 vd->active = NULL; 148 vd->wanted = NULL; 149 vd->currenttype = def; 150 callout_init(&vd->switch_callout, 0); 151 callout_setfunc(&vd->switch_callout, vcons_do_switch, vd); 152 #ifdef VCONS_DRAW_INTR 153 vd->cells = 0; 154 vd->attrs = NULL; 155 vd->chars = NULL; 156 vd->cursor_offset = -1; 157 #endif 158 159 /* 160 * a lock to serialize access to the framebuffer. 161 * when switching screens we need to make sure there's no rasops 162 * operation in progress 163 */ 164 #ifdef DIAGNOSTIC 165 vd->switch_poll_count = 0; 166 #endif 167 #ifdef VCONS_DRAW_INTR 168 vd->intr_softint = softint_establish(SOFTINT_SERIAL, 169 vcons_softintr, vd); 170 callout_init(&vd->intr, 0); 171 callout_setfunc(&vd->intr, vcons_intr, vd); 172 vd->intr_valid = 1; 173 174 /* XXX assume that the 'dev' arg is never dereferenced */ 175 config_interrupts((device_t)vd, vcons_intr_enable); 176 #endif 177 return 0; 178 } 179 180 static void 181 vcons_lock(struct vcons_screen *scr) 182 { 183 #ifdef VCONS_PARANOIA 184 int s; 185 186 s = splhigh(); 187 #endif 188 SCREEN_BUSY(scr); 189 #ifdef VCONS_PARANOIA 190 splx(s); 191 #endif 192 } 193 194 static void 195 vcons_unlock(struct vcons_screen *scr) 196 { 197 #ifdef VCONS_PARANOIA 198 int s; 199 200 s = splhigh(); 201 #endif 202 SCREEN_IDLE(scr); 203 #ifdef VCONS_PARANOIA 204 splx(s); 205 #endif 206 } 207 208 static void 209 vcons_dummy_init_screen(void *cookie, 210 struct vcons_screen *scr, int exists, 211 long *defattr) 212 { 213 214 /* 215 * default init_screen() method. 216 * Needs to be overwritten so we bitch and whine in case anyone ends 217 * up in here. 218 */ 219 printf("vcons_init_screen: dummy function called. Your driver is " 220 "supposed to supply a replacement for proper operation\n"); 221 } 222 223 int 224 vcons_init_screen(struct vcons_data *vd, struct vcons_screen *scr, 225 int existing, long *defattr) 226 { 227 struct rasops_info *ri = &scr->scr_ri; 228 int cnt, i; 229 #ifdef VCONS_DRAW_INTR 230 int size; 231 #endif 232 233 scr->scr_cookie = vd->cookie; 234 scr->scr_vd = scr->scr_origvd = vd; 235 scr->scr_busy = 0; 236 237 /* 238 * call the driver-supplied init_screen function which is expected 239 * to set up rasops_info, override cursor() and probably others 240 */ 241 vd->init_screen(vd->cookie, scr, existing, defattr); 242 243 /* 244 * save the non virtual console aware rasops and replace them with 245 * our wrappers 246 */ 247 vd->eraserows = ri->ri_ops.eraserows; 248 vd->erasecols = ri->ri_ops.erasecols; 249 vd->putchar = ri->ri_ops.putchar; 250 vd->cursor = ri->ri_ops.cursor; 251 252 if (scr->scr_flags & VCONS_NO_COPYCOLS) { 253 vd->copycols = vcons_copycols_noread; 254 } else { 255 vd->copycols = ri->ri_ops.copycols; 256 } 257 258 if (scr->scr_flags & VCONS_NO_COPYROWS) { 259 vd->copyrows = vcons_copyrows_noread; 260 } else { 261 vd->copyrows = ri->ri_ops.copyrows; 262 } 263 264 ri->ri_ops.eraserows = vcons_eraserows; 265 ri->ri_ops.erasecols = vcons_erasecols; 266 ri->ri_ops.putchar = vcons_putchar; 267 ri->ri_ops.cursor = vcons_cursor; 268 ri->ri_ops.copycols = vcons_copycols; 269 ri->ri_ops.copyrows = vcons_copyrows; 270 271 272 ri->ri_hw = scr; 273 274 /* 275 * we allocate both chars and attributes in one chunk, attributes first 276 * because they have the (potentially) bigger alignment 277 */ 278 #ifdef WSDISPLAY_SCROLLSUPPORT 279 cnt = (ri->ri_rows + WSDISPLAY_SCROLLBACK_LINES) * ri->ri_cols; 280 scr->scr_lines_in_buffer = WSDISPLAY_SCROLLBACK_LINES; 281 scr->scr_current_line = 0; 282 scr->scr_line_wanted = 0; 283 scr->scr_offset_to_zero = ri->ri_cols * WSDISPLAY_SCROLLBACK_LINES; 284 scr->scr_current_offset = scr->scr_offset_to_zero; 285 #else 286 cnt = ri->ri_rows * ri->ri_cols; 287 #endif 288 scr->scr_attrs = (long *)malloc(cnt * (sizeof(long) + 289 sizeof(uint32_t)), M_DEVBUF, M_WAITOK); 290 if (scr->scr_attrs == NULL) 291 return ENOMEM; 292 293 scr->scr_chars = (uint32_t *)&scr->scr_attrs[cnt]; 294 295 ri->ri_ops.allocattr(ri, WS_DEFAULT_FG, WS_DEFAULT_BG, 0, defattr); 296 scr->scr_defattr = *defattr; 297 298 /* 299 * fill the attribute buffer with *defattr, chars with 0x20 300 * since we don't know if the driver tries to mimic firmware output or 301 * reset everything we do nothing to VRAM here, any driver that feels 302 * the need to clear screen or something will have to do it on its own 303 * Additional screens will start out in the background anyway so 304 * cleaning or not only really affects the initial console screen 305 */ 306 for (i = 0; i < cnt; i++) { 307 scr->scr_attrs[i] = *defattr; 308 scr->scr_chars[i] = 0x20; 309 } 310 311 #ifdef VCONS_DRAW_INTR 312 size = ri->ri_cols * ri->ri_rows; 313 if (size > vd->cells) { 314 if (vd->chars != NULL) free(vd->chars, M_DEVBUF); 315 if (vd->attrs != NULL) free(vd->attrs, M_DEVBUF); 316 vd->cells = size; 317 vd->chars = malloc(size * sizeof(uint32_t), M_DEVBUF, 318 M_WAITOK|M_ZERO); 319 vd->attrs = malloc(size * sizeof(long), M_DEVBUF, 320 M_WAITOK|M_ZERO); 321 vcons_invalidate_cache(vd); 322 } 323 #endif 324 325 if(vd->active == NULL) { 326 vd->active = scr; 327 SCREEN_VISIBLE(scr); 328 } 329 330 if (existing) { 331 SCREEN_VISIBLE(scr); 332 vd->active = scr; 333 } else { 334 SCREEN_INVISIBLE(scr); 335 } 336 337 LIST_INSERT_HEAD(&vd->screens, scr, next); 338 return 0; 339 } 340 341 static void 342 vcons_do_switch(void *arg) 343 { 344 struct vcons_data *vd = arg; 345 struct vcons_screen *scr, *oldscr; 346 347 scr = vd->wanted; 348 if (!scr) { 349 printf("vcons_switch_screen: disappeared\n"); 350 vd->switch_cb(vd->switch_cb_arg, EIO, 0); 351 return; 352 } 353 oldscr = vd->active; /* can be NULL! */ 354 355 /* 356 * if there's an old, visible screen we mark it invisible and wait 357 * until it's not busy so we can safely switch 358 */ 359 if (oldscr != NULL) { 360 SCREEN_INVISIBLE(oldscr); 361 if (SCREEN_IS_BUSY(oldscr)) { 362 callout_schedule(&vd->switch_callout, 1); 363 #ifdef DIAGNOSTIC 364 /* bitch if we wait too long */ 365 vd->switch_poll_count++; 366 if (vd->switch_poll_count > 100) { 367 panic("vcons: screen still busy"); 368 } 369 #endif 370 return; 371 } 372 /* invisible screen -> no visible cursor image */ 373 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 374 #ifdef DIAGNOSTIC 375 vd->switch_poll_count = 0; 376 #endif 377 } 378 379 if (scr == oldscr) 380 return; 381 382 #ifdef DIAGNOSTIC 383 if (SCREEN_IS_VISIBLE(scr)) 384 printf("vcons_switch_screen: already active"); 385 #endif 386 387 #ifdef notyet 388 if (vd->currenttype != type) { 389 vcons_set_screentype(vd, type); 390 vd->currenttype = type; 391 } 392 #endif 393 394 SCREEN_VISIBLE(scr); 395 vd->active = scr; 396 vd->wanted = NULL; 397 398 if (vd->show_screen_cb != NULL) 399 vd->show_screen_cb(scr); 400 401 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 402 vcons_redraw_screen(scr); 403 404 if (vd->switch_cb) 405 vd->switch_cb(vd->switch_cb_arg, 0, 0); 406 } 407 408 void 409 vcons_redraw_screen(struct vcons_screen *scr) 410 { 411 uint32_t *charptr = scr->scr_chars, c; 412 long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp; 413 struct rasops_info *ri = &scr->scr_ri; 414 struct vcons_data *vd = scr->scr_vd; 415 int i, j, offset, boffset = 0, start = -1; 416 417 mask = 0x00ff00ff; /* background and flags */ 418 cmp = -1; /* never match anything */ 419 vcons_lock(scr); 420 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 421 422 /* 423 * only clear the screen when RI_FULLCLEAR is set since we're 424 * going to overwrite every single character cell anyway 425 */ 426 if (ri->ri_flg & RI_FULLCLEAR) { 427 vd->eraserows(ri, 0, ri->ri_rows, 428 scr->scr_defattr); 429 cmp = scr->scr_defattr & mask; 430 } 431 432 /* redraw the screen */ 433 #ifdef WSDISPLAY_SCROLLSUPPORT 434 offset = scr->scr_current_offset; 435 #else 436 offset = 0; 437 #endif 438 for (i = 0; i < ri->ri_rows; i++) { 439 start = -1; 440 for (j = 0; j < ri->ri_cols; j++) { 441 /* 442 * no need to use the wrapper function - we 443 * don't change any characters or attributes 444 * and we already made sure the screen we're 445 * working on is visible 446 */ 447 c = charptr[offset]; 448 a = attrptr[offset]; 449 acmp = a & mask; 450 if (c == ' ') { 451 /* 452 * if we already erased the background 453 * and this blank uses the same colour 454 * and flags we don't need to do 455 * anything here 456 */ 457 if (acmp == cmp) 458 goto next; 459 /* 460 * see if we can optimize things a 461 * little bit by drawing stretches of 462 * blanks using erasecols 463 */ 464 465 if (start == -1) { 466 start = j; 467 last_a = acmp; 468 } else if (acmp != last_a) { 469 /* 470 * different attr, need to 471 * flush 472 */ 473 vd->erasecols(ri, i, start, 474 j - start, last_a); 475 start = -1; 476 } 477 } else { 478 if (start != -1) { 479 vd->erasecols(ri, i, start, 480 j - start, last_a); 481 start = -1; 482 } 483 484 vd->putchar(ri, i, j, c, a); 485 } 486 next: 487 #ifdef VCONS_DRAW_INTR 488 vd->chars[boffset] = charptr[offset]; 489 vd->attrs[boffset] = attrptr[offset]; 490 #endif 491 offset++; 492 boffset++; 493 } 494 /* end of the line - draw all defered blanks, if any */ 495 if (start != -1) { 496 vd->erasecols(ri, i, start, j - start, last_a); 497 } 498 } 499 ri->ri_flg &= ~RI_CURSOR; 500 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 501 #ifdef VCONS_DRAW_INTR 502 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 503 #endif 504 } 505 vcons_unlock(scr); 506 } 507 508 #ifdef VCONS_DRAW_INTR 509 void 510 vcons_update_screen(struct vcons_screen *scr) 511 { 512 uint32_t *charptr = scr->scr_chars; 513 long *attrptr = scr->scr_attrs; 514 struct rasops_info *ri = &scr->scr_ri; 515 struct vcons_data *vd = scr->scr_vd; 516 int i, j, offset, boffset = 0; 517 518 vcons_lock(scr); 519 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 520 521 /* redraw the screen */ 522 #ifdef WSDISPLAY_SCROLLSUPPORT 523 offset = scr->scr_current_offset; 524 #else 525 offset = 0; 526 #endif 527 /* 528 * we mark the character cell occupied by the cursor as dirty 529 * so we don't have to deal with it 530 * notice that this isn't necessarily the position where rasops 531 * thinks it is, just where we drew it the last time 532 */ 533 if (vd->cursor_offset >= 0) 534 vd->attrs[vd->cursor_offset] = 0xffffffff; 535 536 for (i = 0; i < ri->ri_rows; i++) { 537 for (j = 0; j < ri->ri_cols; j++) { 538 /* 539 * no need to use the wrapper function - we 540 * don't change any characters or attributes 541 * and we already made sure the screen we're 542 * working on is visible 543 */ 544 if ((vd->chars[boffset] != charptr[offset]) || 545 (vd->attrs[boffset] != attrptr[offset])) { 546 vd->putchar(ri, i, j, 547 charptr[offset], attrptr[offset]); 548 vd->chars[boffset] = charptr[offset]; 549 vd->attrs[boffset] = attrptr[offset]; 550 } 551 offset++; 552 boffset++; 553 } 554 } 555 ri->ri_flg &= ~RI_CURSOR; 556 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 557 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 558 } 559 vcons_unlock(scr); 560 } 561 #endif 562 563 static int 564 vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 565 struct lwp *l) 566 { 567 struct vcons_data *vd = v; 568 int error = 0; 569 570 571 switch (cmd) { 572 case WSDISPLAYIO_GETWSCHAR: 573 error = vcons_getwschar((struct vcons_screen *)vs, 574 (struct wsdisplay_char *)data); 575 break; 576 577 case WSDISPLAYIO_PUTWSCHAR: 578 error = vcons_putwschar((struct vcons_screen *)vs, 579 (struct wsdisplay_char *)data); 580 break; 581 582 case WSDISPLAYIO_SET_POLLING: { 583 int poll = *(int *)data; 584 585 /* first call the driver's ioctl handler */ 586 if (vd->ioctl != NULL) 587 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 588 if (poll) { 589 vcons_enable_polling(vd); 590 vcons_hard_switch(LIST_FIRST(&vd->screens)); 591 } else 592 vcons_disable_polling(vd); 593 } 594 break; 595 596 default: 597 if (vd->ioctl != NULL) 598 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 599 else 600 error = EPASSTHROUGH; 601 } 602 603 return error; 604 } 605 606 static int 607 vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 608 int *curxp, int *curyp, long *defattrp) 609 { 610 struct vcons_data *vd = v; 611 struct vcons_screen *scr; 612 int ret; 613 614 scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO); 615 if (scr == NULL) 616 return ENOMEM; 617 618 scr->scr_flags = 0; 619 scr->scr_status = 0; 620 scr->scr_busy = 0; 621 scr->scr_type = type; 622 623 ret = vcons_init_screen(vd, scr, 0, defattrp); 624 if (ret != 0) { 625 free(scr, M_DEVBUF); 626 return ret; 627 } 628 629 if (vd->active == NULL) { 630 SCREEN_VISIBLE(scr); 631 vd->active = scr; 632 vd->currenttype = type; 633 } 634 635 *cookiep = scr; 636 *curxp = scr->scr_ri.ri_ccol; 637 *curyp = scr->scr_ri.ri_crow; 638 return 0; 639 } 640 641 static void 642 vcons_free_screen(void *v, void *cookie) 643 { 644 struct vcons_data *vd = v; 645 struct vcons_screen *scr = cookie; 646 647 vcons_lock(scr); 648 /* there should be no rasops activity here */ 649 650 LIST_REMOVE(scr, next); 651 652 if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) { 653 free(scr->scr_attrs, M_DEVBUF); 654 free(scr, M_DEVBUF); 655 } else { 656 /* 657 * maybe we should just restore the old rasops_info methods 658 * and free the character/attribute buffer here? 659 */ 660 #ifdef VCONS_DEBUG 661 panic("vcons_free_screen: console"); 662 #else 663 printf("vcons_free_screen: console\n"); 664 #endif 665 } 666 667 if (vd->active == scr) 668 vd->active = NULL; 669 } 670 671 static int 672 vcons_show_screen(void *v, void *cookie, int waitok, 673 void (*cb)(void *, int, int), void *cb_arg) 674 { 675 struct vcons_data *vd = v; 676 struct vcons_screen *scr; 677 678 scr = cookie; 679 if (scr == vd->active) 680 return 0; 681 682 vd->wanted = scr; 683 vd->switch_cb = cb; 684 vd->switch_cb_arg = cb_arg; 685 if (cb) { 686 callout_schedule(&vd->switch_callout, 0); 687 return EAGAIN; 688 } 689 690 vcons_do_switch(vd); 691 return 0; 692 } 693 694 /* wrappers for rasops_info methods */ 695 696 static void 697 vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols) 698 { 699 struct rasops_info *ri = cookie; 700 struct vcons_screen *scr = ri->ri_hw; 701 int from = srccol + row * ri->ri_cols; 702 int to = dstcol + row * ri->ri_cols; 703 704 #ifdef WSDISPLAY_SCROLLSUPPORT 705 int offset; 706 offset = scr->scr_offset_to_zero; 707 708 memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from], 709 ncols * sizeof(long)); 710 memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from], 711 ncols * sizeof(uint32_t)); 712 #else 713 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 714 ncols * sizeof(long)); 715 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 716 ncols * sizeof(uint32_t)); 717 #endif 718 719 #ifdef VCONS_DRAW_INTR 720 atomic_inc_uint(&scr->scr_dirty); 721 #endif 722 } 723 724 static void 725 vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 726 { 727 struct rasops_info *ri = cookie; 728 struct vcons_screen *scr = ri->ri_hw; 729 730 vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols); 731 732 #if defined(VCONS_DRAW_INTR) 733 if (scr->scr_vd->use_intr) 734 return; 735 #endif 736 737 vcons_lock(scr); 738 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 739 #if defined(VCONS_DRAW_INTR) 740 vcons_update_screen(scr); 741 #else 742 scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols); 743 #endif 744 } 745 vcons_unlock(scr); 746 } 747 748 static void 749 vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols) 750 { 751 struct rasops_info *ri = cookie; 752 struct vcons_screen *scr = ri->ri_hw; 753 struct vcons_data *vd = scr->scr_vd; 754 755 vcons_lock(scr); 756 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 757 int pos, c, offset, ppos; 758 759 #ifdef WSDISPLAY_SCROLLSUPPORT 760 offset = scr->scr_current_offset; 761 #else 762 offset = 0; 763 #endif 764 ppos = ri->ri_cols * row + dstcol; 765 pos = ppos + offset; 766 for (c = dstcol; c < (dstcol + ncols); c++) { 767 #ifdef VCONS_DRAW_INTR 768 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 769 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 770 vd->putchar(cookie, row, c, 771 scr->scr_chars[pos], scr->scr_attrs[pos]); 772 vd->chars[ppos] = scr->scr_chars[pos]; 773 vd->attrs[ppos] = scr->scr_attrs[pos]; 774 } 775 #else 776 vd->putchar(cookie, row, c, scr->scr_chars[pos], 777 scr->scr_attrs[pos]); 778 #endif 779 pos++; 780 ppos++; 781 } 782 } 783 vcons_unlock(scr); 784 } 785 786 static void 787 vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr) 788 { 789 struct rasops_info *ri = cookie; 790 struct vcons_screen *scr = ri->ri_hw; 791 int start = startcol + row * ri->ri_cols; 792 int end = start + ncols, i; 793 794 #ifdef WSDISPLAY_SCROLLSUPPORT 795 int offset; 796 offset = scr->scr_offset_to_zero; 797 798 for (i = start; i < end; i++) { 799 scr->scr_attrs[offset + i] = fillattr; 800 scr->scr_chars[offset + i] = 0x20; 801 } 802 #else 803 for (i = start; i < end; i++) { 804 scr->scr_attrs[i] = fillattr; 805 scr->scr_chars[i] = 0x20; 806 } 807 #endif 808 809 #ifdef VCONS_DRAW_INTR 810 atomic_inc_uint(&scr->scr_dirty); 811 #endif 812 } 813 814 #ifdef VCONS_DRAW_INTR 815 static void 816 vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr) 817 { 818 struct rasops_info *ri = cookie; 819 struct vcons_screen *scr = ri->ri_hw; 820 struct vcons_data *vd = scr->scr_vd; 821 int i, pos = row * ri->ri_cols + startcol; 822 823 for (i = pos; i < ncols; i++) { 824 vd->chars[i] = 0x20; 825 vd->attrs[i] = fillattr; 826 } 827 vd->erasecols(cookie, row, startcol, ncols, fillattr); 828 } 829 #endif 830 831 static void 832 vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 833 { 834 struct rasops_info *ri = cookie; 835 struct vcons_screen *scr = ri->ri_hw; 836 837 vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr); 838 839 #if defined(VCONS_DRAW_INTR) 840 if (scr->scr_vd->use_intr) 841 return; 842 #endif 843 844 vcons_lock(scr); 845 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 846 #ifdef VCONS_DRAW_INTR 847 vcons_erasecols_cached(cookie, row, startcol, ncols, 848 fillattr); 849 #else 850 scr->scr_vd->erasecols(cookie, row, startcol, ncols, fillattr); 851 #endif 852 } 853 vcons_unlock(scr); 854 } 855 856 static void 857 vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows) 858 { 859 struct rasops_info *ri = cookie; 860 struct vcons_screen *scr = ri->ri_hw; 861 int from, to, len; 862 863 #ifdef WSDISPLAY_SCROLLSUPPORT 864 int offset; 865 offset = scr->scr_offset_to_zero; 866 867 /* do we need to scroll the back buffer? */ 868 if (dstrow == 0) { 869 from = ri->ri_cols * srcrow; 870 to = ri->ri_cols * dstrow; 871 872 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 873 scr->scr_offset_to_zero * sizeof(long)); 874 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 875 scr->scr_offset_to_zero * sizeof(uint32_t)); 876 } 877 from = ri->ri_cols * srcrow + offset; 878 to = ri->ri_cols * dstrow + offset; 879 len = ri->ri_cols * nrows; 880 881 #else 882 from = ri->ri_cols * srcrow; 883 to = ri->ri_cols * dstrow; 884 len = ri->ri_cols * nrows; 885 #endif 886 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 887 len * sizeof(long)); 888 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 889 len * sizeof(uint32_t)); 890 891 #ifdef VCONS_DRAW_INTR 892 atomic_inc_uint(&scr->scr_dirty); 893 #endif 894 } 895 896 static void 897 vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 898 { 899 struct rasops_info *ri = cookie; 900 struct vcons_screen *scr = ri->ri_hw; 901 902 vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows); 903 904 #if defined(VCONS_DRAW_INTR) 905 if (scr->scr_vd->use_intr) 906 return; 907 #endif 908 909 vcons_lock(scr); 910 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 911 #if defined(VCONS_DRAW_INTR) 912 vcons_update_screen(scr); 913 #else 914 scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows); 915 #endif 916 } 917 vcons_unlock(scr); 918 } 919 920 static void 921 vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows) 922 { 923 struct rasops_info *ri = cookie; 924 struct vcons_screen *scr = ri->ri_hw; 925 struct vcons_data *vd = scr->scr_vd; 926 927 vcons_lock(scr); 928 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 929 int pos, l, c, offset, ppos; 930 931 #ifdef WSDISPLAY_SCROLLSUPPORT 932 offset = scr->scr_current_offset; 933 #else 934 offset = 0; 935 #endif 936 ppos = ri->ri_cols * dstrow; 937 pos = ppos + offset; 938 for (l = dstrow; l < (dstrow + nrows); l++) { 939 for (c = 0; c < ri->ri_cols; c++) { 940 #ifdef VCONS_DRAW_INTR 941 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 942 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 943 vd->putchar(cookie, l, c, 944 scr->scr_chars[pos], scr->scr_attrs[pos]); 945 vd->chars[ppos] = scr->scr_chars[pos]; 946 vd->attrs[ppos] = scr->scr_attrs[pos]; 947 } 948 #else 949 vd->putchar(cookie, l, c, scr->scr_chars[pos], 950 scr->scr_attrs[pos]); 951 #endif 952 pos++; 953 ppos++; 954 } 955 } 956 } 957 vcons_unlock(scr); 958 } 959 960 static void 961 vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr) 962 { 963 struct rasops_info *ri = cookie; 964 struct vcons_screen *scr = ri->ri_hw; 965 int start, end, i; 966 967 #ifdef WSDISPLAY_SCROLLSUPPORT 968 int offset; 969 offset = scr->scr_offset_to_zero; 970 971 start = ri->ri_cols * row + offset; 972 end = ri->ri_cols * (row + nrows) + offset; 973 #else 974 start = ri->ri_cols * row; 975 end = ri->ri_cols * (row + nrows); 976 #endif 977 978 for (i = start; i < end; i++) { 979 scr->scr_attrs[i] = fillattr; 980 scr->scr_chars[i] = 0x20; 981 } 982 983 #ifdef VCONS_DRAW_INTR 984 atomic_inc_uint(&scr->scr_dirty); 985 #endif 986 } 987 988 #ifdef VCONS_DRAW_INTR 989 static void 990 vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr) 991 { 992 struct rasops_info *ri = cookie; 993 struct vcons_screen *scr = ri->ri_hw; 994 struct vcons_data *vd = scr->scr_vd; 995 int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols; 996 997 for (i = pos; i < end; i++) { 998 vd->chars[i] = 0x20; 999 vd->attrs[i] = fillattr; 1000 } 1001 vd->eraserows(cookie, row, nrows, fillattr); 1002 } 1003 #endif 1004 1005 static void 1006 vcons_eraserows(void *cookie, int row, int nrows, long fillattr) 1007 { 1008 struct rasops_info *ri = cookie; 1009 struct vcons_screen *scr = ri->ri_hw; 1010 1011 vcons_eraserows_buffer(cookie, row, nrows, fillattr); 1012 1013 #if defined(VCONS_DRAW_INTR) 1014 if (scr->scr_vd->use_intr) 1015 return; 1016 #endif 1017 1018 vcons_lock(scr); 1019 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1020 #ifdef VCONS_DRAW_INTR 1021 vcons_eraserows_cached(cookie, row, nrows, fillattr); 1022 #else 1023 scr->scr_vd->eraserows(cookie, row, nrows, fillattr); 1024 #endif 1025 } 1026 vcons_unlock(scr); 1027 } 1028 1029 static void 1030 vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr) 1031 { 1032 struct rasops_info *ri = cookie; 1033 struct vcons_screen *scr = ri->ri_hw; 1034 int pos; 1035 1036 #ifdef WSDISPLAY_SCROLLSUPPORT 1037 int offset; 1038 offset = scr->scr_offset_to_zero; 1039 1040 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1041 (col < ri->ri_cols)) { 1042 pos = col + row * ri->ri_cols; 1043 scr->scr_attrs[pos + offset] = attr; 1044 scr->scr_chars[pos + offset] = c; 1045 } 1046 #else 1047 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1048 (col < ri->ri_cols)) { 1049 pos = col + row * ri->ri_cols; 1050 scr->scr_attrs[pos] = attr; 1051 scr->scr_chars[pos] = c; 1052 } 1053 #endif 1054 1055 #ifdef VCONS_DRAW_INTR 1056 atomic_inc_uint(&scr->scr_dirty); 1057 #endif 1058 } 1059 1060 #ifdef VCONS_DRAW_INTR 1061 static void 1062 vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr) 1063 { 1064 struct rasops_info *ri = cookie; 1065 struct vcons_screen *scr = ri->ri_hw; 1066 struct vcons_data *vd = scr->scr_vd; 1067 int pos = row * ri->ri_cols + col; 1068 1069 if ((vd->chars == NULL) || (vd->attrs == NULL)) { 1070 vd->putchar(cookie, row, col, c, attr); 1071 return; 1072 } 1073 if ((vd->chars[pos] != c) || (vd->attrs[pos] != attr)) { 1074 vd->attrs[pos] = attr; 1075 vd->chars[pos] = c; 1076 vd->putchar(cookie, row, col, c, attr); 1077 } 1078 } 1079 #endif 1080 1081 static void 1082 vcons_putchar(void *cookie, int row, int col, u_int c, long attr) 1083 { 1084 struct rasops_info *ri = cookie; 1085 struct vcons_screen *scr = ri->ri_hw; 1086 1087 vcons_putchar_buffer(cookie, row, col, c, attr); 1088 1089 #if defined(VCONS_DRAW_INTR) 1090 if (scr->scr_vd->use_intr) 1091 return; 1092 #endif 1093 1094 vcons_lock(scr); 1095 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1096 #ifdef VCONS_DRAW_INTR 1097 vcons_putchar_cached(cookie, row, col, c, attr); 1098 #else 1099 scr->scr_vd->putchar(cookie, row, col, c, attr); 1100 #endif 1101 } 1102 vcons_unlock(scr); 1103 } 1104 1105 static void 1106 vcons_cursor(void *cookie, int on, int row, int col) 1107 { 1108 struct rasops_info *ri = cookie; 1109 struct vcons_screen *scr = ri->ri_hw; 1110 1111 1112 #if defined(VCONS_DRAW_INTR) 1113 if (scr->scr_vd->use_intr) { 1114 vcons_lock(scr); 1115 if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) { 1116 scr->scr_ri.ri_crow = row; 1117 scr->scr_ri.ri_ccol = col; 1118 atomic_inc_uint(&scr->scr_dirty); 1119 } 1120 vcons_unlock(scr); 1121 return; 1122 } 1123 #endif 1124 1125 vcons_lock(scr); 1126 1127 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1128 scr->scr_vd->cursor(cookie, on, row, col); 1129 } else { 1130 scr->scr_ri.ri_crow = row; 1131 scr->scr_ri.ri_ccol = col; 1132 } 1133 vcons_unlock(scr); 1134 } 1135 1136 /* methods to read/write characters via ioctl() */ 1137 1138 static int 1139 vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1140 { 1141 long attr; 1142 struct rasops_info *ri; 1143 1144 KASSERT(scr != NULL && wsc != NULL); 1145 1146 ri = &scr->scr_ri; 1147 1148 if (__predict_false((unsigned int)wsc->col > ri->ri_cols || 1149 (unsigned int)wsc->row > ri->ri_rows)) 1150 return (EINVAL); 1151 1152 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1153 (wsc->col < ri->ri_cols)) { 1154 1155 ri->ri_ops.allocattr(ri, wsc->foreground, wsc->background, 1156 wsc->flags, &attr); 1157 vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr); 1158 #ifdef VCONS_DEBUG 1159 printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col, 1160 wsc->letter, attr); 1161 #endif 1162 return 0; 1163 } else 1164 return EINVAL; 1165 } 1166 1167 static int 1168 vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1169 { 1170 int offset; 1171 long attr; 1172 struct rasops_info *ri; 1173 1174 KASSERT(scr != NULL && wsc != NULL); 1175 1176 ri = &scr->scr_ri; 1177 1178 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1179 (wsc->col < ri->ri_cols)) { 1180 1181 offset = ri->ri_cols * wsc->row + wsc->col; 1182 #ifdef WSDISPLAY_SCROLLSUPPORT 1183 offset += scr->scr_offset_to_zero; 1184 #endif 1185 wsc->letter = scr->scr_chars[offset]; 1186 attr = scr->scr_attrs[offset]; 1187 1188 /* 1189 * this is ugly. We need to break up an attribute into colours and 1190 * flags but there's no rasops method to do that so we must rely on 1191 * the 'canonical' encoding. 1192 */ 1193 #ifdef VCONS_DEBUG 1194 printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row, 1195 wsc->col, wsc->letter, attr); 1196 #endif 1197 wsc->foreground = (attr >> 24) & 0xff; 1198 wsc->background = (attr >> 16) & 0xff; 1199 wsc->flags = attr & 0xff; 1200 return 0; 1201 } else 1202 return EINVAL; 1203 } 1204 1205 #ifdef WSDISPLAY_SCROLLSUPPORT 1206 1207 static void 1208 vcons_scroll(void *cookie, void *vs, int where) 1209 { 1210 struct vcons_screen *scr = vs; 1211 1212 if (where == 0) { 1213 scr->scr_line_wanted = 0; 1214 } else { 1215 scr->scr_line_wanted = scr->scr_line_wanted - where; 1216 if (scr->scr_line_wanted < 0) 1217 scr->scr_line_wanted = 0; 1218 if (scr->scr_line_wanted > scr->scr_lines_in_buffer) 1219 scr->scr_line_wanted = scr->scr_lines_in_buffer; 1220 } 1221 1222 if (scr->scr_line_wanted != scr->scr_current_line) { 1223 1224 vcons_do_scroll(scr); 1225 } 1226 } 1227 1228 static void 1229 vcons_do_scroll(struct vcons_screen *scr) 1230 { 1231 int dist, from, to, num; 1232 int r_offset, r_start; 1233 int i, j; 1234 1235 if (scr->scr_line_wanted == scr->scr_current_line) 1236 return; 1237 dist = scr->scr_line_wanted - scr->scr_current_line; 1238 scr->scr_current_line = scr->scr_line_wanted; 1239 scr->scr_current_offset = scr->scr_ri.ri_cols * 1240 (scr->scr_lines_in_buffer - scr->scr_current_line); 1241 if (abs(dist) >= scr->scr_ri.ri_rows) { 1242 vcons_redraw_screen(scr); 1243 return; 1244 } 1245 /* scroll and redraw only what we really have to */ 1246 if (dist > 0) { 1247 /* we scroll down */ 1248 from = 0; 1249 to = dist; 1250 num = scr->scr_ri.ri_rows - dist; 1251 /* now the redraw parameters */ 1252 r_offset = scr->scr_current_offset; 1253 r_start = 0; 1254 } else { 1255 /* scrolling up */ 1256 to = 0; 1257 from = -dist; 1258 num = scr->scr_ri.ri_rows + dist; 1259 r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols; 1260 r_start = num; 1261 } 1262 scr->scr_vd->copyrows(scr, from, to, num); 1263 for (i = 0; i < abs(dist); i++) { 1264 for (j = 0; j < scr->scr_ri.ri_cols; j++) { 1265 #ifdef VCONS_DRAW_INTR 1266 vcons_putchar_cached(scr, i + r_start, j, 1267 scr->scr_chars[r_offset], 1268 scr->scr_attrs[r_offset]); 1269 #else 1270 scr->scr_vd->putchar(scr, i + r_start, j, 1271 scr->scr_chars[r_offset], 1272 scr->scr_attrs[r_offset]); 1273 #endif 1274 r_offset++; 1275 } 1276 } 1277 1278 if (scr->scr_line_wanted == 0) { 1279 /* this was a reset - need to draw the cursor */ 1280 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1281 scr->scr_vd->cursor(scr, 1, scr->scr_ri.ri_crow, 1282 scr->scr_ri.ri_ccol); 1283 } 1284 } 1285 1286 #endif /* WSDISPLAY_SCROLLSUPPORT */ 1287 1288 #ifdef VCONS_DRAW_INTR 1289 static void 1290 vcons_intr(void *cookie) 1291 { 1292 struct vcons_data *vd = cookie; 1293 1294 softint_schedule(vd->intr_softint); 1295 } 1296 1297 static void 1298 vcons_softintr(void *cookie) 1299 { 1300 struct vcons_data *vd = cookie; 1301 struct vcons_screen *scr = vd->active; 1302 unsigned int dirty; 1303 1304 if (scr && vd->use_intr) { 1305 if (!SCREEN_IS_BUSY(scr)) { 1306 dirty = atomic_swap_uint(&scr->scr_dirty, 0); 1307 if (vd->use_intr == 2) { 1308 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) { 1309 vd->use_intr = 1; 1310 vcons_redraw_screen(scr); 1311 } 1312 } else if (dirty > 0) { 1313 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1314 vcons_update_screen(scr); 1315 } 1316 } 1317 } 1318 1319 callout_schedule(&vd->intr, mstohz(33)); 1320 } 1321 1322 static void 1323 vcons_intr_enable(device_t dev) 1324 { 1325 /* the 'dev' arg we pass to config_interrupts isn't a device_t */ 1326 struct vcons_data *vd = (struct vcons_data *)dev; 1327 vd->use_intr = 2; 1328 callout_schedule(&vd->intr, mstohz(33)); 1329 } 1330 #endif /* VCONS_DRAW_INTR */ 1331 1332 void 1333 vcons_enable_polling(struct vcons_data *vd) 1334 { 1335 struct vcons_screen *scr = vd->active; 1336 1337 #ifdef VCONS_DRAW_INTR 1338 vd->use_intr = 0; 1339 #endif 1340 1341 if (scr && !SCREEN_IS_BUSY(scr)) { 1342 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1343 vcons_redraw_screen(scr); 1344 } 1345 } 1346 1347 void 1348 vcons_disable_polling(struct vcons_data *vd) 1349 { 1350 #ifdef VCONS_DRAW_INTR 1351 struct vcons_screen *scr = vd->active; 1352 1353 if (!vd->intr_valid) 1354 return; 1355 1356 vd->use_intr = 2; 1357 if (scr) 1358 atomic_inc_uint(&scr->scr_dirty); 1359 #endif 1360 } 1361 1362 void 1363 vcons_hard_switch(struct vcons_screen *scr) 1364 { 1365 struct vcons_data *vd = scr->scr_vd; 1366 struct vcons_screen *oldscr = vd->active; 1367 1368 if (oldscr) { 1369 SCREEN_INVISIBLE(oldscr); 1370 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 1371 } 1372 SCREEN_VISIBLE(scr); 1373 vd->active = scr; 1374 vd->wanted = NULL; 1375 1376 if (vd->show_screen_cb != NULL) 1377 vd->show_screen_cb(scr); 1378 } 1379 1380 #ifdef VCONS_DRAW_INTR 1381 void 1382 vcons_invalidate_cache(struct vcons_data *vd) 1383 { 1384 int i; 1385 1386 if (vd->cells == 0) 1387 return; 1388 1389 for (i = 0; i > vd->cells; i++) { 1390 vd->chars[i] = -1; 1391 vd->attrs[i] = -1; 1392 } 1393 } 1394 #endif 1395