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