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