1 /* $NetBSD: wsdisplay_vcons.c,v 1.33 2014/11/10 20:52:47 jmcneill 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.33 2014/11/10 20:52:47 jmcneill 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 scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols); 740 #if defined(VCONS_DRAW_INTR) 741 vcons_invalidate_cache(scr->scr_vd); 742 #endif 743 } 744 vcons_unlock(scr); 745 } 746 747 static void 748 vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols) 749 { 750 struct rasops_info *ri = cookie; 751 struct vcons_screen *scr = ri->ri_hw; 752 struct vcons_data *vd = scr->scr_vd; 753 754 vcons_lock(scr); 755 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 756 int pos, c, offset, ppos; 757 758 #ifdef WSDISPLAY_SCROLLSUPPORT 759 offset = scr->scr_current_offset; 760 #else 761 offset = 0; 762 #endif 763 ppos = ri->ri_cols * row + dstcol; 764 pos = ppos + offset; 765 for (c = dstcol; c < (dstcol + ncols); c++) { 766 #ifdef VCONS_DRAW_INTR 767 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 768 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 769 vd->putchar(cookie, row, c, 770 scr->scr_chars[pos], scr->scr_attrs[pos]); 771 vd->chars[ppos] = scr->scr_chars[pos]; 772 vd->attrs[ppos] = scr->scr_attrs[pos]; 773 } 774 #else 775 vd->putchar(cookie, row, c, scr->scr_chars[pos], 776 scr->scr_attrs[pos]); 777 #endif 778 pos++; 779 ppos++; 780 } 781 } 782 vcons_unlock(scr); 783 } 784 785 static void 786 vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr) 787 { 788 struct rasops_info *ri = cookie; 789 struct vcons_screen *scr = ri->ri_hw; 790 int start = startcol + row * ri->ri_cols; 791 int end = start + ncols, i; 792 793 #ifdef WSDISPLAY_SCROLLSUPPORT 794 int offset; 795 offset = scr->scr_offset_to_zero; 796 797 for (i = start; i < end; i++) { 798 scr->scr_attrs[offset + i] = fillattr; 799 scr->scr_chars[offset + i] = 0x20; 800 } 801 #else 802 for (i = start; i < end; i++) { 803 scr->scr_attrs[i] = fillattr; 804 scr->scr_chars[i] = 0x20; 805 } 806 #endif 807 808 #ifdef VCONS_DRAW_INTR 809 atomic_inc_uint(&scr->scr_dirty); 810 #endif 811 } 812 813 #ifdef VCONS_DRAW_INTR 814 static void 815 vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr) 816 { 817 struct rasops_info *ri = cookie; 818 struct vcons_screen *scr = ri->ri_hw; 819 struct vcons_data *vd = scr->scr_vd; 820 int i, pos = row * ri->ri_cols + startcol; 821 822 for (i = pos; i < ncols; i++) { 823 vd->chars[i] = 0x20; 824 vd->attrs[i] = fillattr; 825 } 826 vd->erasecols(cookie, row, startcol, ncols, fillattr); 827 } 828 #endif 829 830 static void 831 vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 832 { 833 struct rasops_info *ri = cookie; 834 struct vcons_screen *scr = ri->ri_hw; 835 836 vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr); 837 838 #if defined(VCONS_DRAW_INTR) 839 if (scr->scr_vd->use_intr) 840 return; 841 #endif 842 843 vcons_lock(scr); 844 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 845 #ifdef VCONS_DRAW_INTR 846 vcons_erasecols_cached(cookie, row, startcol, ncols, 847 fillattr); 848 #else 849 scr->scr_vd->erasecols(cookie, row, startcol, ncols, fillattr); 850 #endif 851 } 852 vcons_unlock(scr); 853 } 854 855 static void 856 vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows) 857 { 858 struct rasops_info *ri = cookie; 859 struct vcons_screen *scr = ri->ri_hw; 860 int from, to, len; 861 862 #ifdef WSDISPLAY_SCROLLSUPPORT 863 int offset; 864 offset = scr->scr_offset_to_zero; 865 866 /* do we need to scroll the back buffer? */ 867 if (dstrow == 0) { 868 from = ri->ri_cols * srcrow; 869 to = ri->ri_cols * dstrow; 870 871 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 872 scr->scr_offset_to_zero * sizeof(long)); 873 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 874 scr->scr_offset_to_zero * sizeof(uint32_t)); 875 } 876 from = ri->ri_cols * srcrow + offset; 877 to = ri->ri_cols * dstrow + offset; 878 len = ri->ri_cols * nrows; 879 880 #else 881 from = ri->ri_cols * srcrow; 882 to = ri->ri_cols * dstrow; 883 len = ri->ri_cols * nrows; 884 #endif 885 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 886 len * sizeof(long)); 887 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 888 len * sizeof(uint32_t)); 889 890 #ifdef VCONS_DRAW_INTR 891 atomic_inc_uint(&scr->scr_dirty); 892 #endif 893 } 894 895 static void 896 vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 897 { 898 struct rasops_info *ri = cookie; 899 struct vcons_screen *scr = ri->ri_hw; 900 901 vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows); 902 903 #if defined(VCONS_DRAW_INTR) 904 if (scr->scr_vd->use_intr) 905 return; 906 #endif 907 908 vcons_lock(scr); 909 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 910 scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows); 911 #if defined(VCONS_DRAW_INTR) 912 vcons_invalidate_cache(scr->scr_vd); 913 #endif 914 } 915 vcons_unlock(scr); 916 } 917 918 static void 919 vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows) 920 { 921 struct rasops_info *ri = cookie; 922 struct vcons_screen *scr = ri->ri_hw; 923 struct vcons_data *vd = scr->scr_vd; 924 925 vcons_lock(scr); 926 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 927 int pos, l, c, offset, ppos; 928 929 #ifdef WSDISPLAY_SCROLLSUPPORT 930 offset = scr->scr_current_offset; 931 #else 932 offset = 0; 933 #endif 934 ppos = ri->ri_cols * dstrow; 935 pos = ppos + offset; 936 for (l = dstrow; l < (dstrow + nrows); l++) { 937 for (c = 0; c < ri->ri_cols; c++) { 938 #ifdef VCONS_DRAW_INTR 939 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 940 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 941 vd->putchar(cookie, l, c, 942 scr->scr_chars[pos], scr->scr_attrs[pos]); 943 vd->chars[ppos] = scr->scr_chars[pos]; 944 vd->attrs[ppos] = scr->scr_attrs[pos]; 945 } 946 #else 947 vd->putchar(cookie, l, c, scr->scr_chars[pos], 948 scr->scr_attrs[pos]); 949 #endif 950 pos++; 951 ppos++; 952 } 953 } 954 } 955 vcons_unlock(scr); 956 } 957 958 static void 959 vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr) 960 { 961 struct rasops_info *ri = cookie; 962 struct vcons_screen *scr = ri->ri_hw; 963 int start, end, i; 964 965 #ifdef WSDISPLAY_SCROLLSUPPORT 966 int offset; 967 offset = scr->scr_offset_to_zero; 968 969 start = ri->ri_cols * row + offset; 970 end = ri->ri_cols * (row + nrows) + offset; 971 #else 972 start = ri->ri_cols * row; 973 end = ri->ri_cols * (row + nrows); 974 #endif 975 976 for (i = start; i < end; i++) { 977 scr->scr_attrs[i] = fillattr; 978 scr->scr_chars[i] = 0x20; 979 } 980 981 #ifdef VCONS_DRAW_INTR 982 atomic_inc_uint(&scr->scr_dirty); 983 #endif 984 } 985 986 #ifdef VCONS_DRAW_INTR 987 static void 988 vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr) 989 { 990 struct rasops_info *ri = cookie; 991 struct vcons_screen *scr = ri->ri_hw; 992 struct vcons_data *vd = scr->scr_vd; 993 int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols; 994 995 for (i = pos; i < end; i++) { 996 vd->chars[i] = 0x20; 997 vd->attrs[i] = fillattr; 998 } 999 vd->eraserows(cookie, row, nrows, fillattr); 1000 } 1001 #endif 1002 1003 static void 1004 vcons_eraserows(void *cookie, int row, int nrows, long fillattr) 1005 { 1006 struct rasops_info *ri = cookie; 1007 struct vcons_screen *scr = ri->ri_hw; 1008 1009 vcons_eraserows_buffer(cookie, row, nrows, fillattr); 1010 1011 #if defined(VCONS_DRAW_INTR) 1012 if (scr->scr_vd->use_intr) 1013 return; 1014 #endif 1015 1016 vcons_lock(scr); 1017 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1018 #ifdef VCONS_DRAW_INTR 1019 vcons_eraserows_cached(cookie, row, nrows, fillattr); 1020 #else 1021 scr->scr_vd->eraserows(cookie, row, nrows, fillattr); 1022 #endif 1023 } 1024 vcons_unlock(scr); 1025 } 1026 1027 static void 1028 vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr) 1029 { 1030 struct rasops_info *ri = cookie; 1031 struct vcons_screen *scr = ri->ri_hw; 1032 int pos; 1033 1034 #ifdef WSDISPLAY_SCROLLSUPPORT 1035 int offset; 1036 offset = scr->scr_offset_to_zero; 1037 1038 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1039 (col < ri->ri_cols)) { 1040 pos = col + row * ri->ri_cols; 1041 scr->scr_attrs[pos + offset] = attr; 1042 scr->scr_chars[pos + offset] = c; 1043 } 1044 #else 1045 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1046 (col < ri->ri_cols)) { 1047 pos = col + row * ri->ri_cols; 1048 scr->scr_attrs[pos] = attr; 1049 scr->scr_chars[pos] = c; 1050 } 1051 #endif 1052 1053 #ifdef VCONS_DRAW_INTR 1054 atomic_inc_uint(&scr->scr_dirty); 1055 #endif 1056 } 1057 1058 #ifdef VCONS_DRAW_INTR 1059 static void 1060 vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr) 1061 { 1062 struct rasops_info *ri = cookie; 1063 struct vcons_screen *scr = ri->ri_hw; 1064 struct vcons_data *vd = scr->scr_vd; 1065 int pos = row * ri->ri_cols + col; 1066 1067 if ((vd->chars == NULL) || (vd->attrs == NULL)) { 1068 vd->putchar(cookie, row, col, c, attr); 1069 return; 1070 } 1071 if ((vd->chars[pos] != c) || (vd->attrs[pos] != attr)) { 1072 vd->attrs[pos] = attr; 1073 vd->chars[pos] = c; 1074 vd->putchar(cookie, row, col, c, attr); 1075 } 1076 } 1077 #endif 1078 1079 static void 1080 vcons_putchar(void *cookie, int row, int col, u_int c, long attr) 1081 { 1082 struct rasops_info *ri = cookie; 1083 struct vcons_screen *scr = ri->ri_hw; 1084 1085 vcons_putchar_buffer(cookie, row, col, c, attr); 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 #ifdef VCONS_DRAW_INTR 1095 vcons_putchar_cached(cookie, row, col, c, attr); 1096 #else 1097 scr->scr_vd->putchar(cookie, row, col, c, attr); 1098 #endif 1099 } 1100 vcons_unlock(scr); 1101 } 1102 1103 static void 1104 vcons_cursor(void *cookie, int on, int row, int col) 1105 { 1106 struct rasops_info *ri = cookie; 1107 struct vcons_screen *scr = ri->ri_hw; 1108 1109 1110 #if defined(VCONS_DRAW_INTR) 1111 if (scr->scr_vd->use_intr) { 1112 vcons_lock(scr); 1113 if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) { 1114 scr->scr_ri.ri_crow = row; 1115 scr->scr_ri.ri_ccol = col; 1116 atomic_inc_uint(&scr->scr_dirty); 1117 } 1118 vcons_unlock(scr); 1119 return; 1120 } 1121 #endif 1122 1123 vcons_lock(scr); 1124 1125 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1126 scr->scr_vd->cursor(cookie, on, row, col); 1127 } else { 1128 scr->scr_ri.ri_crow = row; 1129 scr->scr_ri.ri_ccol = col; 1130 } 1131 vcons_unlock(scr); 1132 } 1133 1134 /* methods to read/write characters via ioctl() */ 1135 1136 static int 1137 vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1138 { 1139 long attr; 1140 struct rasops_info *ri; 1141 1142 KASSERT(scr != NULL && wsc != NULL); 1143 1144 ri = &scr->scr_ri; 1145 1146 if (__predict_false((unsigned int)wsc->col > ri->ri_cols || 1147 (unsigned int)wsc->row > ri->ri_rows)) 1148 return (EINVAL); 1149 1150 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1151 (wsc->col < ri->ri_cols)) { 1152 1153 ri->ri_ops.allocattr(ri, wsc->foreground, wsc->background, 1154 wsc->flags, &attr); 1155 vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr); 1156 #ifdef VCONS_DEBUG 1157 printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col, 1158 wsc->letter, attr); 1159 #endif 1160 return 0; 1161 } else 1162 return EINVAL; 1163 } 1164 1165 static int 1166 vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1167 { 1168 int offset; 1169 long attr; 1170 struct rasops_info *ri; 1171 1172 KASSERT(scr != NULL && wsc != NULL); 1173 1174 ri = &scr->scr_ri; 1175 1176 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1177 (wsc->col < ri->ri_cols)) { 1178 1179 offset = ri->ri_cols * wsc->row + wsc->col; 1180 #ifdef WSDISPLAY_SCROLLSUPPORT 1181 offset += scr->scr_offset_to_zero; 1182 #endif 1183 wsc->letter = scr->scr_chars[offset]; 1184 attr = scr->scr_attrs[offset]; 1185 1186 /* 1187 * this is ugly. We need to break up an attribute into colours and 1188 * flags but there's no rasops method to do that so we must rely on 1189 * the 'canonical' encoding. 1190 */ 1191 #ifdef VCONS_DEBUG 1192 printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row, 1193 wsc->col, wsc->letter, attr); 1194 #endif 1195 wsc->foreground = (attr >> 24) & 0xff; 1196 wsc->background = (attr >> 16) & 0xff; 1197 wsc->flags = attr & 0xff; 1198 return 0; 1199 } else 1200 return EINVAL; 1201 } 1202 1203 #ifdef WSDISPLAY_SCROLLSUPPORT 1204 1205 static void 1206 vcons_scroll(void *cookie, void *vs, int where) 1207 { 1208 struct vcons_screen *scr = vs; 1209 1210 if (where == 0) { 1211 scr->scr_line_wanted = 0; 1212 } else { 1213 scr->scr_line_wanted = scr->scr_line_wanted - where; 1214 if (scr->scr_line_wanted < 0) 1215 scr->scr_line_wanted = 0; 1216 if (scr->scr_line_wanted > scr->scr_lines_in_buffer) 1217 scr->scr_line_wanted = scr->scr_lines_in_buffer; 1218 } 1219 1220 if (scr->scr_line_wanted != scr->scr_current_line) { 1221 1222 vcons_do_scroll(scr); 1223 } 1224 } 1225 1226 static void 1227 vcons_do_scroll(struct vcons_screen *scr) 1228 { 1229 int dist, from, to, num; 1230 int r_offset, r_start; 1231 int i, j; 1232 1233 if (scr->scr_line_wanted == scr->scr_current_line) 1234 return; 1235 dist = scr->scr_line_wanted - scr->scr_current_line; 1236 scr->scr_current_line = scr->scr_line_wanted; 1237 scr->scr_current_offset = scr->scr_ri.ri_cols * 1238 (scr->scr_lines_in_buffer - scr->scr_current_line); 1239 if (abs(dist) >= scr->scr_ri.ri_rows) { 1240 vcons_redraw_screen(scr); 1241 return; 1242 } 1243 /* scroll and redraw only what we really have to */ 1244 if (dist > 0) { 1245 /* we scroll down */ 1246 from = 0; 1247 to = dist; 1248 num = scr->scr_ri.ri_rows - dist; 1249 /* now the redraw parameters */ 1250 r_offset = scr->scr_current_offset; 1251 r_start = 0; 1252 } else { 1253 /* scrolling up */ 1254 to = 0; 1255 from = -dist; 1256 num = scr->scr_ri.ri_rows + dist; 1257 r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols; 1258 r_start = num; 1259 } 1260 scr->scr_vd->copyrows(scr, from, to, num); 1261 for (i = 0; i < abs(dist); i++) { 1262 for (j = 0; j < scr->scr_ri.ri_cols; j++) { 1263 #ifdef VCONS_DRAW_INTR 1264 vcons_putchar_cached(scr, i + r_start, j, 1265 scr->scr_chars[r_offset], 1266 scr->scr_attrs[r_offset]); 1267 #else 1268 scr->scr_vd->putchar(scr, i + r_start, j, 1269 scr->scr_chars[r_offset], 1270 scr->scr_attrs[r_offset]); 1271 #endif 1272 r_offset++; 1273 } 1274 } 1275 1276 if (scr->scr_line_wanted == 0) { 1277 /* this was a reset - need to draw the cursor */ 1278 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1279 scr->scr_vd->cursor(scr, 1, scr->scr_ri.ri_crow, 1280 scr->scr_ri.ri_ccol); 1281 } 1282 } 1283 1284 #endif /* WSDISPLAY_SCROLLSUPPORT */ 1285 1286 #ifdef VCONS_DRAW_INTR 1287 static void 1288 vcons_intr(void *cookie) 1289 { 1290 struct vcons_data *vd = cookie; 1291 1292 softint_schedule(vd->intr_softint); 1293 } 1294 1295 static void 1296 vcons_softintr(void *cookie) 1297 { 1298 struct vcons_data *vd = cookie; 1299 struct vcons_screen *scr = vd->active; 1300 unsigned int dirty; 1301 1302 if (scr && vd->use_intr) { 1303 if (!SCREEN_IS_BUSY(scr)) { 1304 dirty = atomic_swap_uint(&scr->scr_dirty, 0); 1305 if (vd->use_intr == 2) { 1306 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) { 1307 vd->use_intr = 1; 1308 vcons_redraw_screen(scr); 1309 } 1310 } else if (dirty > 0) { 1311 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1312 vcons_update_screen(scr); 1313 } 1314 } 1315 } 1316 1317 callout_schedule(&vd->intr, mstohz(33)); 1318 } 1319 1320 static void 1321 vcons_intr_enable(device_t dev) 1322 { 1323 /* the 'dev' arg we pass to config_interrupts isn't a device_t */ 1324 struct vcons_data *vd = (struct vcons_data *)dev; 1325 vd->use_intr = 2; 1326 callout_schedule(&vd->intr, mstohz(33)); 1327 } 1328 #endif /* VCONS_DRAW_INTR */ 1329 1330 void 1331 vcons_enable_polling(struct vcons_data *vd) 1332 { 1333 struct vcons_screen *scr = vd->active; 1334 1335 #ifdef VCONS_DRAW_INTR 1336 vd->use_intr = 0; 1337 #endif 1338 1339 if (scr && !SCREEN_IS_BUSY(scr)) { 1340 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1341 vcons_redraw_screen(scr); 1342 } 1343 } 1344 1345 void 1346 vcons_disable_polling(struct vcons_data *vd) 1347 { 1348 #ifdef VCONS_DRAW_INTR 1349 struct vcons_screen *scr = vd->active; 1350 1351 if (!vd->intr_valid) 1352 return; 1353 1354 vd->use_intr = 2; 1355 if (scr) 1356 atomic_inc_uint(&scr->scr_dirty); 1357 #endif 1358 } 1359 1360 void 1361 vcons_hard_switch(struct vcons_screen *scr) 1362 { 1363 struct vcons_data *vd = scr->scr_vd; 1364 struct vcons_screen *oldscr = vd->active; 1365 1366 if (oldscr) { 1367 SCREEN_INVISIBLE(oldscr); 1368 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 1369 } 1370 SCREEN_VISIBLE(scr); 1371 vd->active = scr; 1372 vd->wanted = NULL; 1373 1374 if (vd->show_screen_cb != NULL) 1375 vd->show_screen_cb(scr); 1376 } 1377 1378 #ifdef VCONS_DRAW_INTR 1379 void 1380 vcons_invalidate_cache(struct vcons_data *vd) 1381 { 1382 int i; 1383 1384 if (vd->cells == 0) 1385 return; 1386 1387 for (i = 0; i > vd->cells; i++) { 1388 vd->chars[i] = -1; 1389 vd->attrs[i] = -1; 1390 } 1391 } 1392 #endif 1393