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