1 /* $NetBSD: wsdisplay_vcons.c,v 1.32 2014/03/18 18:20:42 riastradh 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.32 2014/03/18 18:20:42 riastradh 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, M_WAITOK); 318 vd->attrs = malloc(size * sizeof(long), M_DEVBUF, M_WAITOK); 319 vcons_invalidate_cache(vd); 320 } 321 #endif 322 323 if(vd->active == NULL) { 324 vd->active = scr; 325 SCREEN_VISIBLE(scr); 326 } 327 328 if (existing) { 329 SCREEN_VISIBLE(scr); 330 vd->active = scr; 331 } else { 332 SCREEN_INVISIBLE(scr); 333 } 334 335 LIST_INSERT_HEAD(&vd->screens, scr, next); 336 return 0; 337 } 338 339 static void 340 vcons_do_switch(void *arg) 341 { 342 struct vcons_data *vd = arg; 343 struct vcons_screen *scr, *oldscr; 344 345 scr = vd->wanted; 346 if (!scr) { 347 printf("vcons_switch_screen: disappeared\n"); 348 vd->switch_cb(vd->switch_cb_arg, EIO, 0); 349 return; 350 } 351 oldscr = vd->active; /* can be NULL! */ 352 353 /* 354 * if there's an old, visible screen we mark it invisible and wait 355 * until it's not busy so we can safely switch 356 */ 357 if (oldscr != NULL) { 358 SCREEN_INVISIBLE(oldscr); 359 if (SCREEN_IS_BUSY(oldscr)) { 360 callout_schedule(&vd->switch_callout, 1); 361 #ifdef DIAGNOSTIC 362 /* bitch if we wait too long */ 363 vd->switch_poll_count++; 364 if (vd->switch_poll_count > 100) { 365 panic("vcons: screen still busy"); 366 } 367 #endif 368 return; 369 } 370 /* invisible screen -> no visible cursor image */ 371 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 372 #ifdef DIAGNOSTIC 373 vd->switch_poll_count = 0; 374 #endif 375 } 376 377 if (scr == oldscr) 378 return; 379 380 #ifdef DIAGNOSTIC 381 if (SCREEN_IS_VISIBLE(scr)) 382 printf("vcons_switch_screen: already active"); 383 #endif 384 385 #ifdef notyet 386 if (vd->currenttype != type) { 387 vcons_set_screentype(vd, type); 388 vd->currenttype = type; 389 } 390 #endif 391 392 SCREEN_VISIBLE(scr); 393 vd->active = scr; 394 vd->wanted = NULL; 395 396 if (vd->show_screen_cb != NULL) 397 vd->show_screen_cb(scr); 398 399 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 400 vcons_redraw_screen(scr); 401 402 if (vd->switch_cb) 403 vd->switch_cb(vd->switch_cb_arg, 0, 0); 404 } 405 406 void 407 vcons_redraw_screen(struct vcons_screen *scr) 408 { 409 uint32_t *charptr = scr->scr_chars, c; 410 long *attrptr = scr->scr_attrs, a, last_a = 0, mask, cmp, acmp; 411 struct rasops_info *ri = &scr->scr_ri; 412 struct vcons_data *vd = scr->scr_vd; 413 int i, j, offset, boffset = 0, start = -1; 414 415 mask = 0x00ff00ff; /* background and flags */ 416 cmp = -1; /* never match anything */ 417 vcons_lock(scr); 418 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 419 420 /* 421 * only clear the screen when RI_FULLCLEAR is set since we're 422 * going to overwrite every single character cell anyway 423 */ 424 if (ri->ri_flg & RI_FULLCLEAR) { 425 vd->eraserows(ri, 0, ri->ri_rows, 426 scr->scr_defattr); 427 cmp = scr->scr_defattr & mask; 428 } 429 430 /* redraw the screen */ 431 #ifdef WSDISPLAY_SCROLLSUPPORT 432 offset = scr->scr_current_offset; 433 #else 434 offset = 0; 435 #endif 436 for (i = 0; i < ri->ri_rows; i++) { 437 start = -1; 438 for (j = 0; j < ri->ri_cols; j++) { 439 /* 440 * no need to use the wrapper function - we 441 * don't change any characters or attributes 442 * and we already made sure the screen we're 443 * working on is visible 444 */ 445 c = charptr[offset]; 446 a = attrptr[offset]; 447 acmp = a & mask; 448 if (c == ' ') { 449 /* 450 * if we already erased the background 451 * and this blank uses the same colour 452 * and flags we don't need to do 453 * anything here 454 */ 455 if (acmp == cmp) 456 goto next; 457 /* 458 * see if we can optimize things a 459 * little bit by drawing stretches of 460 * blanks using erasecols 461 */ 462 463 if (start == -1) { 464 start = j; 465 last_a = acmp; 466 } else if (acmp != last_a) { 467 /* 468 * different attr, need to 469 * flush 470 */ 471 vd->erasecols(ri, i, start, 472 j - start, last_a); 473 start = -1; 474 } 475 } else { 476 if (start != -1) { 477 vd->erasecols(ri, i, start, 478 j - start, last_a); 479 start = -1; 480 } 481 482 vd->putchar(ri, i, j, c, a); 483 } 484 next: 485 #ifdef VCONS_DRAW_INTR 486 vd->chars[boffset] = charptr[offset]; 487 vd->attrs[boffset] = attrptr[offset]; 488 #endif 489 offset++; 490 boffset++; 491 } 492 /* end of the line - draw all defered blanks, if any */ 493 if (start != -1) { 494 vd->erasecols(ri, i, start, j - start, last_a); 495 } 496 } 497 ri->ri_flg &= ~RI_CURSOR; 498 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 499 #ifdef VCONS_DRAW_INTR 500 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 501 #endif 502 } 503 vcons_unlock(scr); 504 } 505 506 #ifdef VCONS_DRAW_INTR 507 void 508 vcons_update_screen(struct vcons_screen *scr) 509 { 510 uint32_t *charptr = scr->scr_chars; 511 long *attrptr = scr->scr_attrs; 512 struct rasops_info *ri = &scr->scr_ri; 513 struct vcons_data *vd = scr->scr_vd; 514 int i, j, offset, boffset = 0; 515 516 vcons_lock(scr); 517 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 518 519 /* redraw the screen */ 520 #ifdef WSDISPLAY_SCROLLSUPPORT 521 offset = scr->scr_current_offset; 522 #else 523 offset = 0; 524 #endif 525 /* 526 * we mark the character cell occupied by the cursor as dirty 527 * so we don't have to deal with it 528 * notice that this isn't necessarily the position where rasops 529 * thinks it is, just where we drew it the last time 530 */ 531 if (vd->cursor_offset >= 0) 532 vd->attrs[vd->cursor_offset] = 0xffffffff; 533 534 for (i = 0; i < ri->ri_rows; i++) { 535 for (j = 0; j < ri->ri_cols; j++) { 536 /* 537 * no need to use the wrapper function - we 538 * don't change any characters or attributes 539 * and we already made sure the screen we're 540 * working on is visible 541 */ 542 if ((vd->chars[boffset] != charptr[offset]) || 543 (vd->attrs[boffset] != attrptr[offset])) { 544 vd->putchar(ri, i, j, 545 charptr[offset], attrptr[offset]); 546 vd->chars[boffset] = charptr[offset]; 547 vd->attrs[boffset] = attrptr[offset]; 548 } 549 offset++; 550 boffset++; 551 } 552 } 553 ri->ri_flg &= ~RI_CURSOR; 554 scr->scr_vd->cursor(ri, 1, ri->ri_crow, ri->ri_ccol); 555 vd->cursor_offset = ri->ri_crow * ri->ri_cols + ri->ri_ccol; 556 } 557 vcons_unlock(scr); 558 } 559 #endif 560 561 static int 562 vcons_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 563 struct lwp *l) 564 { 565 struct vcons_data *vd = v; 566 int error = 0; 567 568 569 switch (cmd) { 570 case WSDISPLAYIO_GETWSCHAR: 571 error = vcons_getwschar((struct vcons_screen *)vs, 572 (struct wsdisplay_char *)data); 573 break; 574 575 case WSDISPLAYIO_PUTWSCHAR: 576 error = vcons_putwschar((struct vcons_screen *)vs, 577 (struct wsdisplay_char *)data); 578 break; 579 580 case WSDISPLAYIO_SET_POLLING: { 581 int poll = *(int *)data; 582 583 /* first call the driver's ioctl handler */ 584 if (vd->ioctl != NULL) 585 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 586 if (poll) { 587 vcons_enable_polling(vd); 588 vcons_hard_switch(LIST_FIRST(&vd->screens)); 589 } else 590 vcons_disable_polling(vd); 591 } 592 break; 593 594 default: 595 if (vd->ioctl != NULL) 596 error = (*vd->ioctl)(v, vs, cmd, data, flag, l); 597 else 598 error = EPASSTHROUGH; 599 } 600 601 return error; 602 } 603 604 static int 605 vcons_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 606 int *curxp, int *curyp, long *defattrp) 607 { 608 struct vcons_data *vd = v; 609 struct vcons_screen *scr; 610 int ret; 611 612 scr = malloc(sizeof(struct vcons_screen), M_DEVBUF, M_WAITOK | M_ZERO); 613 if (scr == NULL) 614 return ENOMEM; 615 616 scr->scr_flags = 0; 617 scr->scr_status = 0; 618 scr->scr_busy = 0; 619 scr->scr_type = type; 620 621 ret = vcons_init_screen(vd, scr, 0, defattrp); 622 if (ret != 0) { 623 free(scr, M_DEVBUF); 624 return ret; 625 } 626 627 if (vd->active == NULL) { 628 SCREEN_VISIBLE(scr); 629 vd->active = scr; 630 vd->currenttype = type; 631 } 632 633 *cookiep = scr; 634 *curxp = scr->scr_ri.ri_ccol; 635 *curyp = scr->scr_ri.ri_crow; 636 return 0; 637 } 638 639 static void 640 vcons_free_screen(void *v, void *cookie) 641 { 642 struct vcons_data *vd = v; 643 struct vcons_screen *scr = cookie; 644 645 vcons_lock(scr); 646 /* there should be no rasops activity here */ 647 648 LIST_REMOVE(scr, next); 649 650 if ((scr->scr_flags & VCONS_SCREEN_IS_STATIC) == 0) { 651 free(scr->scr_attrs, M_DEVBUF); 652 free(scr, M_DEVBUF); 653 } else { 654 /* 655 * maybe we should just restore the old rasops_info methods 656 * and free the character/attribute buffer here? 657 */ 658 #ifdef VCONS_DEBUG 659 panic("vcons_free_screen: console"); 660 #else 661 printf("vcons_free_screen: console\n"); 662 #endif 663 } 664 665 if (vd->active == scr) 666 vd->active = NULL; 667 } 668 669 static int 670 vcons_show_screen(void *v, void *cookie, int waitok, 671 void (*cb)(void *, int, int), void *cb_arg) 672 { 673 struct vcons_data *vd = v; 674 struct vcons_screen *scr; 675 676 scr = cookie; 677 if (scr == vd->active) 678 return 0; 679 680 vd->wanted = scr; 681 vd->switch_cb = cb; 682 vd->switch_cb_arg = cb_arg; 683 if (cb) { 684 callout_schedule(&vd->switch_callout, 0); 685 return EAGAIN; 686 } 687 688 vcons_do_switch(vd); 689 return 0; 690 } 691 692 /* wrappers for rasops_info methods */ 693 694 static void 695 vcons_copycols_buffer(void *cookie, int row, int srccol, int dstcol, int ncols) 696 { 697 struct rasops_info *ri = cookie; 698 struct vcons_screen *scr = ri->ri_hw; 699 int from = srccol + row * ri->ri_cols; 700 int to = dstcol + row * ri->ri_cols; 701 702 #ifdef WSDISPLAY_SCROLLSUPPORT 703 int offset; 704 offset = scr->scr_offset_to_zero; 705 706 memmove(&scr->scr_attrs[offset + to], &scr->scr_attrs[offset + from], 707 ncols * sizeof(long)); 708 memmove(&scr->scr_chars[offset + to], &scr->scr_chars[offset + from], 709 ncols * sizeof(uint32_t)); 710 #else 711 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 712 ncols * sizeof(long)); 713 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 714 ncols * sizeof(uint32_t)); 715 #endif 716 717 #ifdef VCONS_DRAW_INTR 718 atomic_inc_uint(&scr->scr_dirty); 719 #endif 720 } 721 722 static void 723 vcons_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 724 { 725 struct rasops_info *ri = cookie; 726 struct vcons_screen *scr = ri->ri_hw; 727 728 vcons_copycols_buffer(cookie, row, srccol, dstcol, ncols); 729 730 #if defined(VCONS_DRAW_INTR) 731 if (scr->scr_vd->use_intr) 732 return; 733 #endif 734 735 vcons_lock(scr); 736 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 737 scr->scr_vd->copycols(cookie, row, srccol, dstcol, ncols); 738 #if defined(VCONS_DRAW_INTR) 739 vcons_invalidate_cache(scr->scr_vd); 740 #endif 741 } 742 vcons_unlock(scr); 743 } 744 745 static void 746 vcons_copycols_noread(void *cookie, int row, int srccol, int dstcol, int ncols) 747 { 748 struct rasops_info *ri = cookie; 749 struct vcons_screen *scr = ri->ri_hw; 750 struct vcons_data *vd = scr->scr_vd; 751 752 vcons_lock(scr); 753 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 754 int pos, c, offset, ppos; 755 756 #ifdef WSDISPLAY_SCROLLSUPPORT 757 offset = scr->scr_current_offset; 758 #else 759 offset = 0; 760 #endif 761 ppos = ri->ri_cols * row + dstcol; 762 pos = ppos + offset; 763 for (c = dstcol; c < (dstcol + ncols); c++) { 764 #ifdef VCONS_DRAW_INTR 765 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 766 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 767 vd->putchar(cookie, row, c, 768 scr->scr_chars[pos], scr->scr_attrs[pos]); 769 vd->chars[ppos] = scr->scr_chars[pos]; 770 vd->attrs[ppos] = scr->scr_attrs[pos]; 771 } 772 #else 773 vd->putchar(cookie, row, c, scr->scr_chars[pos], 774 scr->scr_attrs[pos]); 775 #endif 776 pos++; 777 ppos++; 778 } 779 } 780 vcons_unlock(scr); 781 } 782 783 static void 784 vcons_erasecols_buffer(void *cookie, int row, int startcol, int ncols, long fillattr) 785 { 786 struct rasops_info *ri = cookie; 787 struct vcons_screen *scr = ri->ri_hw; 788 int start = startcol + row * ri->ri_cols; 789 int end = start + ncols, i; 790 791 #ifdef WSDISPLAY_SCROLLSUPPORT 792 int offset; 793 offset = scr->scr_offset_to_zero; 794 795 for (i = start; i < end; i++) { 796 scr->scr_attrs[offset + i] = fillattr; 797 scr->scr_chars[offset + i] = 0x20; 798 } 799 #else 800 for (i = start; i < end; i++) { 801 scr->scr_attrs[i] = fillattr; 802 scr->scr_chars[i] = 0x20; 803 } 804 #endif 805 806 #ifdef VCONS_DRAW_INTR 807 atomic_inc_uint(&scr->scr_dirty); 808 #endif 809 } 810 811 #ifdef VCONS_DRAW_INTR 812 static void 813 vcons_erasecols_cached(void *cookie, int row, int startcol, int ncols, long fillattr) 814 { 815 struct rasops_info *ri = cookie; 816 struct vcons_screen *scr = ri->ri_hw; 817 struct vcons_data *vd = scr->scr_vd; 818 int i, pos = row * ri->ri_cols + startcol; 819 820 for (i = pos; i < ncols; i++) { 821 vd->chars[i] = 0x20; 822 vd->attrs[i] = fillattr; 823 } 824 vd->erasecols(cookie, row, startcol, ncols, fillattr); 825 } 826 #endif 827 828 static void 829 vcons_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 830 { 831 struct rasops_info *ri = cookie; 832 struct vcons_screen *scr = ri->ri_hw; 833 834 vcons_erasecols_buffer(cookie, row, startcol, ncols, fillattr); 835 836 #if defined(VCONS_DRAW_INTR) 837 if (scr->scr_vd->use_intr) 838 return; 839 #endif 840 841 vcons_lock(scr); 842 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 843 #ifdef VCONS_DRAW_INTR 844 vcons_erasecols_cached(cookie, row, startcol, ncols, 845 fillattr); 846 #else 847 scr->scr_vd->erasecols(cookie, row, startcol, ncols, fillattr); 848 #endif 849 } 850 vcons_unlock(scr); 851 } 852 853 static void 854 vcons_copyrows_buffer(void *cookie, int srcrow, int dstrow, int nrows) 855 { 856 struct rasops_info *ri = cookie; 857 struct vcons_screen *scr = ri->ri_hw; 858 int from, to, len; 859 860 #ifdef WSDISPLAY_SCROLLSUPPORT 861 int offset; 862 offset = scr->scr_offset_to_zero; 863 864 /* do we need to scroll the back buffer? */ 865 if (dstrow == 0) { 866 from = ri->ri_cols * srcrow; 867 to = ri->ri_cols * dstrow; 868 869 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 870 scr->scr_offset_to_zero * sizeof(long)); 871 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 872 scr->scr_offset_to_zero * sizeof(uint32_t)); 873 } 874 from = ri->ri_cols * srcrow + offset; 875 to = ri->ri_cols * dstrow + offset; 876 len = ri->ri_cols * nrows; 877 878 #else 879 from = ri->ri_cols * srcrow; 880 to = ri->ri_cols * dstrow; 881 len = ri->ri_cols * nrows; 882 #endif 883 memmove(&scr->scr_attrs[to], &scr->scr_attrs[from], 884 len * sizeof(long)); 885 memmove(&scr->scr_chars[to], &scr->scr_chars[from], 886 len * sizeof(uint32_t)); 887 888 #ifdef VCONS_DRAW_INTR 889 atomic_inc_uint(&scr->scr_dirty); 890 #endif 891 } 892 893 static void 894 vcons_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 895 { 896 struct rasops_info *ri = cookie; 897 struct vcons_screen *scr = ri->ri_hw; 898 899 vcons_copyrows_buffer(cookie, srcrow, dstrow, nrows); 900 901 #if defined(VCONS_DRAW_INTR) 902 if (scr->scr_vd->use_intr) 903 return; 904 #endif 905 906 vcons_lock(scr); 907 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 908 scr->scr_vd->copyrows(cookie, srcrow, dstrow, nrows); 909 #if defined(VCONS_DRAW_INTR) 910 vcons_invalidate_cache(scr->scr_vd); 911 #endif 912 } 913 vcons_unlock(scr); 914 } 915 916 static void 917 vcons_copyrows_noread(void *cookie, int srcrow, int dstrow, int nrows) 918 { 919 struct rasops_info *ri = cookie; 920 struct vcons_screen *scr = ri->ri_hw; 921 struct vcons_data *vd = scr->scr_vd; 922 923 vcons_lock(scr); 924 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 925 int pos, l, c, offset, ppos; 926 927 #ifdef WSDISPLAY_SCROLLSUPPORT 928 offset = scr->scr_current_offset; 929 #else 930 offset = 0; 931 #endif 932 ppos = ri->ri_cols * dstrow; 933 pos = ppos + offset; 934 for (l = dstrow; l < (dstrow + nrows); l++) { 935 for (c = 0; c < ri->ri_cols; c++) { 936 #ifdef VCONS_DRAW_INTR 937 if ((scr->scr_chars[pos] != vd->chars[ppos]) || 938 (scr->scr_attrs[pos] != vd->attrs[ppos])) { 939 vd->putchar(cookie, l, c, 940 scr->scr_chars[pos], scr->scr_attrs[pos]); 941 vd->chars[ppos] = scr->scr_chars[pos]; 942 vd->attrs[ppos] = scr->scr_attrs[pos]; 943 } 944 #else 945 vd->putchar(cookie, l, c, scr->scr_chars[pos], 946 scr->scr_attrs[pos]); 947 #endif 948 pos++; 949 ppos++; 950 } 951 } 952 } 953 vcons_unlock(scr); 954 } 955 956 static void 957 vcons_eraserows_buffer(void *cookie, int row, int nrows, long fillattr) 958 { 959 struct rasops_info *ri = cookie; 960 struct vcons_screen *scr = ri->ri_hw; 961 int start, end, i; 962 963 #ifdef WSDISPLAY_SCROLLSUPPORT 964 int offset; 965 offset = scr->scr_offset_to_zero; 966 967 start = ri->ri_cols * row + offset; 968 end = ri->ri_cols * (row + nrows) + offset; 969 #else 970 start = ri->ri_cols * row; 971 end = ri->ri_cols * (row + nrows); 972 #endif 973 974 for (i = start; i < end; i++) { 975 scr->scr_attrs[i] = fillattr; 976 scr->scr_chars[i] = 0x20; 977 } 978 979 #ifdef VCONS_DRAW_INTR 980 atomic_inc_uint(&scr->scr_dirty); 981 #endif 982 } 983 984 #ifdef VCONS_DRAW_INTR 985 static void 986 vcons_eraserows_cached(void *cookie, int row, int nrows, long fillattr) 987 { 988 struct rasops_info *ri = cookie; 989 struct vcons_screen *scr = ri->ri_hw; 990 struct vcons_data *vd = scr->scr_vd; 991 int i, pos = row * ri->ri_cols, end = (row+nrows) * ri->ri_cols; 992 993 for (i = pos; i < end; i++) { 994 vd->chars[i] = 0x20; 995 vd->attrs[i] = fillattr; 996 } 997 vd->eraserows(cookie, row, nrows, fillattr); 998 } 999 #endif 1000 1001 static void 1002 vcons_eraserows(void *cookie, int row, int nrows, long fillattr) 1003 { 1004 struct rasops_info *ri = cookie; 1005 struct vcons_screen *scr = ri->ri_hw; 1006 1007 vcons_eraserows_buffer(cookie, row, nrows, fillattr); 1008 1009 #if defined(VCONS_DRAW_INTR) 1010 if (scr->scr_vd->use_intr) 1011 return; 1012 #endif 1013 1014 vcons_lock(scr); 1015 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1016 #ifdef VCONS_DRAW_INTR 1017 vcons_eraserows_cached(cookie, row, nrows, fillattr); 1018 #else 1019 scr->scr_vd->eraserows(cookie, row, nrows, fillattr); 1020 #endif 1021 } 1022 vcons_unlock(scr); 1023 } 1024 1025 static void 1026 vcons_putchar_buffer(void *cookie, int row, int col, u_int c, long attr) 1027 { 1028 struct rasops_info *ri = cookie; 1029 struct vcons_screen *scr = ri->ri_hw; 1030 int pos; 1031 1032 #ifdef WSDISPLAY_SCROLLSUPPORT 1033 int offset; 1034 offset = scr->scr_offset_to_zero; 1035 1036 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1037 (col < ri->ri_cols)) { 1038 pos = col + row * ri->ri_cols; 1039 scr->scr_attrs[pos + offset] = attr; 1040 scr->scr_chars[pos + offset] = c; 1041 } 1042 #else 1043 if ((row >= 0) && (row < ri->ri_rows) && (col >= 0) && 1044 (col < ri->ri_cols)) { 1045 pos = col + row * ri->ri_cols; 1046 scr->scr_attrs[pos] = attr; 1047 scr->scr_chars[pos] = c; 1048 } 1049 #endif 1050 1051 #ifdef VCONS_DRAW_INTR 1052 atomic_inc_uint(&scr->scr_dirty); 1053 #endif 1054 } 1055 1056 #ifdef VCONS_DRAW_INTR 1057 static void 1058 vcons_putchar_cached(void *cookie, int row, int col, u_int c, long attr) 1059 { 1060 struct rasops_info *ri = cookie; 1061 struct vcons_screen *scr = ri->ri_hw; 1062 struct vcons_data *vd = scr->scr_vd; 1063 int pos = row * ri->ri_cols + col; 1064 1065 if ((vd->chars == NULL) || (vd->attrs == NULL)) { 1066 vd->putchar(cookie, row, col, c, attr); 1067 return; 1068 } 1069 if ((vd->chars[pos] != c) || (vd->attrs[pos] != attr)) { 1070 vd->attrs[pos] = attr; 1071 vd->chars[pos] = c; 1072 vd->putchar(cookie, row, col, c, attr); 1073 } 1074 } 1075 #endif 1076 1077 static void 1078 vcons_putchar(void *cookie, int row, int col, u_int c, long attr) 1079 { 1080 struct rasops_info *ri = cookie; 1081 struct vcons_screen *scr = ri->ri_hw; 1082 1083 vcons_putchar_buffer(cookie, row, col, c, attr); 1084 1085 #if defined(VCONS_DRAW_INTR) 1086 if (scr->scr_vd->use_intr) 1087 return; 1088 #endif 1089 1090 vcons_lock(scr); 1091 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1092 #ifdef VCONS_DRAW_INTR 1093 vcons_putchar_cached(cookie, row, col, c, attr); 1094 #else 1095 scr->scr_vd->putchar(cookie, row, col, c, attr); 1096 #endif 1097 } 1098 vcons_unlock(scr); 1099 } 1100 1101 static void 1102 vcons_cursor(void *cookie, int on, int row, int col) 1103 { 1104 struct rasops_info *ri = cookie; 1105 struct vcons_screen *scr = ri->ri_hw; 1106 1107 1108 #if defined(VCONS_DRAW_INTR) 1109 if (scr->scr_vd->use_intr) { 1110 vcons_lock(scr); 1111 if (scr->scr_ri.ri_crow != row || scr->scr_ri.ri_ccol != col) { 1112 scr->scr_ri.ri_crow = row; 1113 scr->scr_ri.ri_ccol = col; 1114 atomic_inc_uint(&scr->scr_dirty); 1115 } 1116 vcons_unlock(scr); 1117 return; 1118 } 1119 #endif 1120 1121 vcons_lock(scr); 1122 1123 if (SCREEN_IS_VISIBLE(scr) && SCREEN_CAN_DRAW(scr)) { 1124 scr->scr_vd->cursor(cookie, on, row, col); 1125 } else { 1126 scr->scr_ri.ri_crow = row; 1127 scr->scr_ri.ri_ccol = col; 1128 } 1129 vcons_unlock(scr); 1130 } 1131 1132 /* methods to read/write characters via ioctl() */ 1133 1134 static int 1135 vcons_putwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1136 { 1137 long attr; 1138 struct rasops_info *ri; 1139 1140 KASSERT(scr != NULL && wsc != NULL); 1141 1142 ri = &scr->scr_ri; 1143 1144 if (__predict_false((unsigned int)wsc->col > ri->ri_cols || 1145 (unsigned int)wsc->row > ri->ri_rows)) 1146 return (EINVAL); 1147 1148 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1149 (wsc->col < ri->ri_cols)) { 1150 1151 ri->ri_ops.allocattr(ri, wsc->foreground, wsc->background, 1152 wsc->flags, &attr); 1153 vcons_putchar(ri, wsc->row, wsc->col, wsc->letter, attr); 1154 #ifdef VCONS_DEBUG 1155 printf("vcons_putwschar(%d, %d, %x, %lx\n", wsc->row, wsc->col, 1156 wsc->letter, attr); 1157 #endif 1158 return 0; 1159 } else 1160 return EINVAL; 1161 } 1162 1163 static int 1164 vcons_getwschar(struct vcons_screen *scr, struct wsdisplay_char *wsc) 1165 { 1166 int offset; 1167 long attr; 1168 struct rasops_info *ri; 1169 1170 KASSERT(scr != NULL && wsc != NULL); 1171 1172 ri = &scr->scr_ri; 1173 1174 if ((wsc->row >= 0) && (wsc->row < ri->ri_rows) && (wsc->col >= 0) && 1175 (wsc->col < ri->ri_cols)) { 1176 1177 offset = ri->ri_cols * wsc->row + wsc->col; 1178 #ifdef WSDISPLAY_SCROLLSUPPORT 1179 offset += scr->scr_offset_to_zero; 1180 #endif 1181 wsc->letter = scr->scr_chars[offset]; 1182 attr = scr->scr_attrs[offset]; 1183 1184 /* 1185 * this is ugly. We need to break up an attribute into colours and 1186 * flags but there's no rasops method to do that so we must rely on 1187 * the 'canonical' encoding. 1188 */ 1189 #ifdef VCONS_DEBUG 1190 printf("vcons_getwschar: %d, %d, %x, %lx\n", wsc->row, 1191 wsc->col, wsc->letter, attr); 1192 #endif 1193 wsc->foreground = (attr >> 24) & 0xff; 1194 wsc->background = (attr >> 16) & 0xff; 1195 wsc->flags = attr & 0xff; 1196 return 0; 1197 } else 1198 return EINVAL; 1199 } 1200 1201 #ifdef WSDISPLAY_SCROLLSUPPORT 1202 1203 static void 1204 vcons_scroll(void *cookie, void *vs, int where) 1205 { 1206 struct vcons_screen *scr = vs; 1207 1208 if (where == 0) { 1209 scr->scr_line_wanted = 0; 1210 } else { 1211 scr->scr_line_wanted = scr->scr_line_wanted - where; 1212 if (scr->scr_line_wanted < 0) 1213 scr->scr_line_wanted = 0; 1214 if (scr->scr_line_wanted > scr->scr_lines_in_buffer) 1215 scr->scr_line_wanted = scr->scr_lines_in_buffer; 1216 } 1217 1218 if (scr->scr_line_wanted != scr->scr_current_line) { 1219 1220 vcons_do_scroll(scr); 1221 } 1222 } 1223 1224 static void 1225 vcons_do_scroll(struct vcons_screen *scr) 1226 { 1227 int dist, from, to, num; 1228 int r_offset, r_start; 1229 int i, j; 1230 1231 if (scr->scr_line_wanted == scr->scr_current_line) 1232 return; 1233 dist = scr->scr_line_wanted - scr->scr_current_line; 1234 scr->scr_current_line = scr->scr_line_wanted; 1235 scr->scr_current_offset = scr->scr_ri.ri_cols * 1236 (scr->scr_lines_in_buffer - scr->scr_current_line); 1237 if (abs(dist) >= scr->scr_ri.ri_rows) { 1238 vcons_redraw_screen(scr); 1239 return; 1240 } 1241 /* scroll and redraw only what we really have to */ 1242 if (dist > 0) { 1243 /* we scroll down */ 1244 from = 0; 1245 to = dist; 1246 num = scr->scr_ri.ri_rows - dist; 1247 /* now the redraw parameters */ 1248 r_offset = scr->scr_current_offset; 1249 r_start = 0; 1250 } else { 1251 /* scrolling up */ 1252 to = 0; 1253 from = -dist; 1254 num = scr->scr_ri.ri_rows + dist; 1255 r_offset = scr->scr_current_offset + num * scr->scr_ri.ri_cols; 1256 r_start = num; 1257 } 1258 scr->scr_vd->copyrows(scr, from, to, num); 1259 for (i = 0; i < abs(dist); i++) { 1260 for (j = 0; j < scr->scr_ri.ri_cols; j++) { 1261 #ifdef VCONS_DRAW_INTR 1262 vcons_putchar_cached(scr, i + r_start, j, 1263 scr->scr_chars[r_offset], 1264 scr->scr_attrs[r_offset]); 1265 #else 1266 scr->scr_vd->putchar(scr, i + r_start, j, 1267 scr->scr_chars[r_offset], 1268 scr->scr_attrs[r_offset]); 1269 #endif 1270 r_offset++; 1271 } 1272 } 1273 1274 if (scr->scr_line_wanted == 0) { 1275 /* this was a reset - need to draw the cursor */ 1276 scr->scr_ri.ri_flg &= ~RI_CURSOR; 1277 scr->scr_vd->cursor(scr, 1, scr->scr_ri.ri_crow, 1278 scr->scr_ri.ri_ccol); 1279 } 1280 } 1281 1282 #endif /* WSDISPLAY_SCROLLSUPPORT */ 1283 1284 #ifdef VCONS_DRAW_INTR 1285 static void 1286 vcons_intr(void *cookie) 1287 { 1288 struct vcons_data *vd = cookie; 1289 1290 softint_schedule(vd->intr_softint); 1291 } 1292 1293 static void 1294 vcons_softintr(void *cookie) 1295 { 1296 struct vcons_data *vd = cookie; 1297 struct vcons_screen *scr = vd->active; 1298 unsigned int dirty; 1299 1300 if (scr && vd->use_intr) { 1301 if (!SCREEN_IS_BUSY(scr)) { 1302 dirty = atomic_swap_uint(&scr->scr_dirty, 0); 1303 if (vd->use_intr == 2) { 1304 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) { 1305 vd->use_intr = 1; 1306 vcons_redraw_screen(scr); 1307 } 1308 } else if (dirty > 0) { 1309 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1310 vcons_update_screen(scr); 1311 } 1312 } 1313 } 1314 1315 callout_schedule(&vd->intr, mstohz(33)); 1316 } 1317 1318 static void 1319 vcons_intr_enable(device_t dev) 1320 { 1321 /* the 'dev' arg we pass to config_interrupts isn't a device_t */ 1322 struct vcons_data *vd = (struct vcons_data *)dev; 1323 vd->use_intr = 2; 1324 callout_schedule(&vd->intr, mstohz(33)); 1325 } 1326 #endif /* VCONS_DRAW_INTR */ 1327 1328 void 1329 vcons_enable_polling(struct vcons_data *vd) 1330 { 1331 struct vcons_screen *scr = vd->active; 1332 1333 #ifdef VCONS_DRAW_INTR 1334 vd->use_intr = 0; 1335 #endif 1336 1337 if (scr && !SCREEN_IS_BUSY(scr)) { 1338 if ((scr->scr_flags & VCONS_NO_REDRAW) == 0) 1339 vcons_redraw_screen(scr); 1340 } 1341 } 1342 1343 void 1344 vcons_disable_polling(struct vcons_data *vd) 1345 { 1346 #ifdef VCONS_DRAW_INTR 1347 struct vcons_screen *scr = vd->active; 1348 1349 if (!vd->intr_valid) 1350 return; 1351 1352 vd->use_intr = 2; 1353 if (scr) 1354 atomic_inc_uint(&scr->scr_dirty); 1355 #endif 1356 } 1357 1358 void 1359 vcons_hard_switch(struct vcons_screen *scr) 1360 { 1361 struct vcons_data *vd = scr->scr_vd; 1362 struct vcons_screen *oldscr = vd->active; 1363 1364 if (oldscr) { 1365 SCREEN_INVISIBLE(oldscr); 1366 oldscr->scr_ri.ri_flg &= ~RI_CURSOR; 1367 } 1368 SCREEN_VISIBLE(scr); 1369 vd->active = scr; 1370 vd->wanted = NULL; 1371 1372 if (vd->show_screen_cb != NULL) 1373 vd->show_screen_cb(scr); 1374 } 1375 1376 #ifdef VCONS_DRAW_INTR 1377 void 1378 vcons_invalidate_cache(struct vcons_data *vd) 1379 { 1380 int i; 1381 1382 if (vd->cells == 0) 1383 return; 1384 1385 for (i = 0; i > vd->cells; i++) { 1386 vd->chars[i] = -1; 1387 vd->attrs[i] = -1; 1388 } 1389 } 1390 #endif 1391