1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2016 Joyent, Inc. 29 */ 30 31 /* 32 * Polled I/O safe ANSI terminal emulator module; 33 * Supporting TERM types 'sun' and 'sun-color, parsing 34 * ANSI x3.64 escape sequences, and the like. (See wscons(7d) 35 * for more information). 36 * 37 * IMPORTANT: 38 * 39 * The functions in this file *must* be able to function in 40 * standalone mode, ie. on a quiesced system. In that state, 41 * access is single threaded, only one CPU is running. 42 * System services are NOT available. 43 * 44 * The following restrictions pertain to every function 45 * in this file: 46 * 47 * - CANNOT use the DDI or LDI interfaces 48 * - CANNOT call system services 49 * - CANNOT use mutexes 50 * - CANNOT wait for interrupts 51 * - CANNOT allocate memory 52 * 53 * All non-static functions in this file which: 54 * - Operates on tems and tem_vt_state 55 * - Not only called from standalone mode, i.e. has 56 * a "calledfrom" argument 57 * should assert this at the beginning: 58 * 59 * ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 60 * called_from == CALLED_FROM_STANDALONE); 61 */ 62 63 #include <sys/types.h> 64 #include <sys/ascii.h> 65 #include <sys/visual_io.h> 66 #include <sys/font.h> 67 #include <sys/tem.h> 68 #include <sys/tem_impl.h> 69 #include <sys/ksynch.h> 70 #include <sys/sysmacros.h> 71 #include <sys/mutex.h> 72 #include <sys/note.h> 73 #include <sys/t_lock.h> 74 75 tem_safe_callbacks_t tem_safe_text_callbacks = { 76 &tem_safe_text_display, 77 &tem_safe_text_copy, 78 &tem_safe_text_cursor, 79 NULL, 80 &tem_safe_text_cls 81 }; 82 tem_safe_callbacks_t tem_safe_pix_callbacks = { 83 &tem_safe_pix_display, 84 &tem_safe_pix_copy, 85 &tem_safe_pix_cursor, 86 &tem_safe_pix_bit2pix, 87 &tem_safe_pix_cls 88 }; 89 90 static void tem_safe_control(struct tem_vt_state *, tem_char_t, 91 cred_t *, enum called_from); 92 static void tem_safe_setparam(struct tem_vt_state *, int, int); 93 static void tem_safe_selgraph(struct tem_vt_state *); 94 static void tem_safe_chkparam(struct tem_vt_state *, tem_char_t, 95 cred_t *, enum called_from); 96 static void tem_safe_getparams(struct tem_vt_state *, tem_char_t, 97 cred_t *, enum called_from); 98 static void tem_safe_outch(struct tem_vt_state *, tem_char_t, 99 cred_t *, enum called_from); 100 static void tem_safe_parse(struct tem_vt_state *, tem_char_t, 101 cred_t *, enum called_from); 102 103 static void tem_safe_new_line(struct tem_vt_state *, 104 cred_t *, enum called_from); 105 static void tem_safe_cr(struct tem_vt_state *); 106 static void tem_safe_lf(struct tem_vt_state *, 107 cred_t *, enum called_from); 108 static void tem_safe_send_data(struct tem_vt_state *, cred_t *, 109 enum called_from); 110 static void tem_safe_cls(struct tem_vt_state *, 111 cred_t *, enum called_from); 112 static void tem_safe_tab(struct tem_vt_state *, 113 cred_t *, enum called_from); 114 static void tem_safe_back_tab(struct tem_vt_state *, 115 cred_t *, enum called_from); 116 static void tem_safe_clear_tabs(struct tem_vt_state *, int); 117 static void tem_safe_set_tab(struct tem_vt_state *); 118 static void tem_safe_mv_cursor(struct tem_vt_state *, int, int, 119 cred_t *, enum called_from); 120 static void tem_safe_shift(struct tem_vt_state *, int, int, 121 cred_t *, enum called_from); 122 static void tem_safe_scroll(struct tem_vt_state *, int, int, 123 int, int, cred_t *, enum called_from); 124 static void tem_safe_clear_chars(struct tem_vt_state *tem, 125 int count, screen_pos_t row, screen_pos_t col, 126 cred_t *credp, enum called_from called_from); 127 static void tem_safe_copy_area(struct tem_vt_state *tem, 128 screen_pos_t s_col, screen_pos_t s_row, 129 screen_pos_t e_col, screen_pos_t e_row, 130 screen_pos_t t_col, screen_pos_t t_row, 131 cred_t *credp, enum called_from called_from); 132 #if 0 133 /* Currently unused */ 134 static void tem_safe_image_display(struct tem_vt_state *, uchar_t *, 135 int, int, screen_pos_t, screen_pos_t, 136 cred_t *, enum called_from); 137 #endif 138 static void tem_safe_bell(struct tem_vt_state *tem, 139 enum called_from called_from); 140 static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, 141 cred_t *credp, enum called_from called_from); 142 static void tem_safe_get_color(text_color_t *, text_color_t *, term_char_t); 143 144 static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t, 145 screen_pos_t); 146 static void tem_safe_virtual_display(struct tem_vt_state *, 147 term_char_t *, int, screen_pos_t, screen_pos_t); 148 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t, 149 screen_pos_t, screen_pos_t, screen_pos_t, 150 screen_pos_t, screen_pos_t); 151 static void tem_safe_align_cursor(struct tem_vt_state *tem); 152 static void bit_to_pix4(struct tem_vt_state *tem, tem_char_t c, 153 text_color_t fg_color, text_color_t bg_color); 154 static void bit_to_pix8(struct tem_vt_state *tem, tem_char_t c, 155 text_color_t fg_color, text_color_t bg_color); 156 static void bit_to_pix16(struct tem_vt_state *tem, tem_char_t c, 157 text_color_t fg_color, text_color_t bg_color); 158 static void bit_to_pix24(struct tem_vt_state *tem, tem_char_t c, 159 text_color_t fg_color, text_color_t bg_color); 160 static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, 161 text_color_t fg_color, text_color_t bg_color); 162 163 #define PIX4TO32(pix4) (uint32_t)( \ 164 cmap4_to_24.red[pix4] << 16 | \ 165 cmap4_to_24.green[pix4] << 8 | \ 166 cmap4_to_24.blue[pix4]) 167 168 #define INVERSE(ch) (ch ^ 0xff) 169 170 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display) 171 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy) 172 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor) 173 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls) 174 #define tem_safe_callback_bit2pix(tem, c) { \ 175 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \ 176 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c));\ 177 } 178 179 void 180 tem_safe_check_first_time( 181 struct tem_vt_state *tem, 182 cred_t *credp, 183 enum called_from called_from) 184 { 185 static int first_time = 1; 186 187 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 188 called_from == CALLED_FROM_STANDALONE); 189 190 /* 191 * Realign the console cursor. We did this in tem_init(). 192 * However, drivers in the console stream may emit additional 193 * messages before we are ready. This causes text overwrite 194 * on the screen. This is a workaround. 195 */ 196 if (!first_time) 197 return; 198 199 first_time = 0; 200 if (tems.ts_display_mode == VIS_TEXT) 201 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from); 202 else 203 tem_safe_pix_cursor(tem, VIS_GET_CURSOR, credp, called_from); 204 tem_safe_align_cursor(tem); 205 } 206 207 /* 208 * This entry point handles output requests from restricted contexts like 209 * kmdb, where services like mutexes are not available. This function 210 * is entered when OBP or when a kernel debugger (such as kmdb) 211 * are generating console output. In those cases, power management 212 * concerns are handled by the abort sequence initiation (ie. when 213 * the user hits L1+A or the equivalent to enter OBP or the debugger.). 214 * It is also entered when the kernel is panicing. 215 */ 216 void 217 tem_safe_polled_write( 218 tem_vt_state_t tem_arg, 219 uchar_t *buf, 220 int len) 221 { 222 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; 223 224 #ifdef __lock_lint 225 _NOTE(NO_COMPETING_THREADS_NOW) 226 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT) 227 #endif 228 229 if (!tem->tvs_initialized) { 230 return; 231 } 232 233 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE); 234 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE); 235 } 236 237 /* Process partial UTF-8 sequence. */ 238 static void 239 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp, 240 enum called_from called_from) 241 { 242 unsigned i; 243 uint8_t c; 244 245 if (tem->tvs_utf8_left == 0) 246 return; 247 248 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) { 249 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff; 250 if (c != 0) { 251 tem_safe_parse(tem, c, credp, called_from); 252 } 253 } 254 tem->tvs_utf8_left = 0; 255 tem->tvs_utf8_partial = 0; 256 } 257 258 /* 259 * Handle UTF-8 sequences. 260 */ 261 static void 262 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp, 263 enum called_from called_from) 264 { 265 /* 266 * Check for UTF-8 code points. In case of error fall back to 267 * 8-bit code. As we only have 8859-1 fonts for console, this will set 268 * the limits on what chars we actually can display, therefore we 269 * have to return to this code once we have solved the font issue. 270 */ 271 if ((c & 0x80) == 0x00) { 272 /* One-byte sequence. */ 273 tem_safe_input_partial(tem, credp, called_from); 274 tem_safe_parse(tem, c, credp, called_from); 275 return; 276 } 277 if ((c & 0xe0) == 0xc0) { 278 /* Two-byte sequence. */ 279 tem_safe_input_partial(tem, credp, called_from); 280 tem->tvs_utf8_left = 1; 281 tem->tvs_utf8_partial = c; 282 return; 283 } 284 if ((c & 0xf0) == 0xe0) { 285 /* Three-byte sequence. */ 286 tem_safe_input_partial(tem, credp, called_from); 287 tem->tvs_utf8_left = 2; 288 tem->tvs_utf8_partial = c; 289 return; 290 } 291 if ((c & 0xf8) == 0xf0) { 292 /* Four-byte sequence. */ 293 tem_safe_input_partial(tem, credp, called_from); 294 tem->tvs_utf8_left = 3; 295 tem->tvs_utf8_partial = c; 296 return; 297 } 298 if ((c & 0xc0) == 0x80) { 299 /* Invalid state? */ 300 if (tem->tvs_utf8_left == 0) { 301 tem_safe_parse(tem, c, credp, called_from); 302 return; 303 } 304 tem->tvs_utf8_left--; 305 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c; 306 if (tem->tvs_utf8_left == 0) { 307 tem_char_t v, u; 308 uint8_t b; 309 310 /* 311 * Transform the sequence of 2 to 4 bytes to 312 * unicode number. 313 */ 314 v = 0; 315 u = tem->tvs_utf8_partial; 316 b = (u >> 24) & 0xff; 317 if (b != 0) { /* Four-byte sequence */ 318 v = b & 0x07; 319 b = (u >> 16) & 0xff; 320 v = (v << 6) | (b & 0x3f); 321 b = (u >> 8) & 0xff; 322 v = (v << 6) | (b & 0x3f); 323 b = u & 0xff; 324 v = (v << 6) | (b & 0x3f); 325 } else if ((b = (u >> 16) & 0xff) != 0) { 326 v = b & 0x0f; /* Three-byte sequence */ 327 b = (u >> 8) & 0xff; 328 v = (v << 6) | (b & 0x3f); 329 b = u & 0xff; 330 v = (v << 6) | (b & 0x3f); 331 } else if ((b = (u >> 8) & 0xff) != 0) { 332 v = b & 0x1f; /* Two-byte sequence */ 333 b = u & 0xff; 334 v = (v << 6) | (b & 0x3f); 335 } 336 337 tem_safe_parse(tem, v, credp, called_from); 338 tem->tvs_utf8_partial = 0; 339 } 340 return; 341 } 342 /* Anything left is illegal in UTF-8 sequence. */ 343 tem_safe_input_partial(tem, credp, called_from); 344 tem_safe_parse(tem, c, credp, called_from); 345 } 346 347 /* 348 * This is the main entry point into the terminal emulator. 349 * 350 * For each data message coming downstream, ANSI assumes that it is composed 351 * of ASCII characters, which are treated as a byte-stream input to the 352 * parsing state machine. All data is parsed immediately -- there is 353 * no enqueing. 354 */ 355 void 356 tem_safe_terminal_emulate( 357 struct tem_vt_state *tem, 358 uchar_t *buf, 359 int len, 360 cred_t *credp, 361 enum called_from called_from) 362 { 363 364 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 365 called_from == CALLED_FROM_STANDALONE); 366 367 if (tem->tvs_isactive) 368 tem_safe_callback_cursor(tem, 369 VIS_HIDE_CURSOR, credp, called_from); 370 371 for (; len > 0; len--, buf++) 372 tem_safe_input_byte(tem, *buf, credp, called_from); 373 374 /* 375 * Send the data we just got to the framebuffer. 376 */ 377 tem_safe_send_data(tem, credp, called_from); 378 379 if (tem->tvs_isactive) 380 tem_safe_callback_cursor(tem, 381 VIS_DISPLAY_CURSOR, credp, called_from); 382 } 383 384 /* 385 * Display an rectangular image on the frame buffer using the 386 * mechanism appropriate for the system state being called 387 * from quiesced or normal (ie. use polled I/O vs. layered ioctls) 388 */ 389 static void 390 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp, 391 enum called_from called_from) 392 { 393 if (called_from == CALLED_FROM_STANDALONE) 394 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda); 395 else 396 tems_display_layered(pda, credp); 397 } 398 399 /* 400 * Copy a rectangle from one location to another on the frame buffer 401 * using the mechanism appropriate for the system state being called 402 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls) 403 */ 404 void 405 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp, 406 enum called_from called_from) 407 { 408 if (called_from == CALLED_FROM_STANDALONE) 409 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca); 410 else 411 tems_copy_layered(pca, credp); 412 } 413 414 /* 415 * Display or hide a rectangular block text cursor of a specificsize 416 * at a specific location on frame buffer* using the mechanism 417 * appropriate for the system state being called from, quisced or 418 * normal (ie. use polled I/O vs. layered ioctls). 419 */ 420 static void 421 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp, 422 enum called_from called_from) 423 { 424 if (called_from == CALLED_FROM_STANDALONE) 425 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca); 426 else 427 tems_cursor_layered(pca, credp); 428 } 429 430 /* 431 * send the appropriate control message or set state based on the 432 * value of the control character ch 433 */ 434 435 static void 436 tem_safe_control(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp, 437 enum called_from called_from) 438 { 439 tem->tvs_state = A_STATE_START; 440 switch (ch) { 441 case A_BEL: 442 tem_safe_bell(tem, called_from); 443 break; 444 445 case A_BS: 446 tem_safe_mv_cursor(tem, 447 tem->tvs_c_cursor.row, 448 tem->tvs_c_cursor.col - 1, 449 credp, called_from); 450 break; 451 452 case A_HT: 453 tem_safe_tab(tem, credp, called_from); 454 break; 455 456 case A_NL: 457 /* 458 * tem_safe_send_data(tem, credp, called_from); 459 * tem_safe_new_line(tem, credp, called_from); 460 * break; 461 */ 462 463 case A_VT: 464 tem_safe_send_data(tem, credp, called_from); 465 tem_safe_lf(tem, credp, called_from); 466 break; 467 468 case A_FF: 469 tem_safe_send_data(tem, credp, called_from); 470 tem_safe_cls(tem, credp, called_from); 471 break; 472 473 case A_CR: 474 tem_safe_send_data(tem, credp, called_from); 475 tem_safe_cr(tem); 476 break; 477 478 case A_ESC: 479 tem->tvs_state = A_STATE_ESC; 480 break; 481 482 case A_CSI: 483 { 484 int i; 485 tem->tvs_curparam = 0; 486 tem->tvs_paramval = 0; 487 tem->tvs_gotparam = B_FALSE; 488 /* clear the parameters */ 489 for (i = 0; i < TEM_MAXPARAMS; i++) 490 tem->tvs_params[i] = -1; 491 tem->tvs_state = A_STATE_CSI; 492 } 493 break; 494 495 case A_GS: 496 tem_safe_back_tab(tem, credp, called_from); 497 break; 498 499 default: 500 break; 501 } 502 } 503 504 505 /* 506 * if parameters [0..count - 1] are not set, set them to the value 507 * of newparam. 508 */ 509 510 static void 511 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam) 512 { 513 int i; 514 515 for (i = 0; i < count; i++) { 516 if (tem->tvs_params[i] == -1) 517 tem->tvs_params[i] = newparam; 518 } 519 } 520 521 522 static void 523 tem_select_color(struct tem_vt_state *tem, text_color_t color, boolean_t fg) 524 { 525 if (tems.ts_pdepth >= 24 || 526 (color < 8 && tems.ts_pdepth < 24)) { 527 if (fg == B_TRUE) { 528 tem->tvs_fg_color = color; 529 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 530 } else { 531 tem->tvs_bg_color = color; 532 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 533 } 534 return; 535 } 536 537 if (color > 15) 538 return; 539 540 /* Bright color and depth < 24 */ 541 color -= 8; 542 if (fg == B_TRUE) { 543 tem->tvs_fg_color = color; 544 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 545 } else { 546 tem->tvs_bg_color = color; 547 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 548 } 549 } 550 551 /* 552 * select graphics mode based on the param vals stored in a_params 553 */ 554 static void 555 tem_safe_selgraph(struct tem_vt_state *tem) 556 { 557 int curparam; 558 int count = 0; 559 int param; 560 561 tem->tvs_state = A_STATE_START; 562 563 curparam = tem->tvs_curparam; 564 do { 565 param = tem->tvs_params[count]; 566 567 switch (param) { 568 case -1: 569 case 0: 570 /* reset to initial normal settings */ 571 tem->tvs_fg_color = tems.ts_init_color.fg_color; 572 tem->tvs_bg_color = tems.ts_init_color.bg_color; 573 tem->tvs_flags = tems.ts_init_color.a_flags; 574 break; 575 576 case 1: /* Bold Intense */ 577 tem->tvs_flags |= TEM_ATTR_BOLD; 578 break; 579 580 case 2: /* Faint Intense */ 581 tem->tvs_flags &= ~TEM_ATTR_BOLD; 582 break; 583 584 case 4: /* Underline */ 585 tem->tvs_flags |= TEM_ATTR_UNDERLINE; 586 break; 587 case 5: /* Blink */ 588 tem->tvs_flags |= TEM_ATTR_BLINK; 589 break; 590 591 case 7: /* Reverse video */ 592 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 593 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 594 } else { 595 tem->tvs_flags |= TEM_ATTR_REVERSE; 596 } 597 break; 598 599 case 22: /* Remove Bold */ 600 tem->tvs_flags &= ~TEM_ATTR_BOLD; 601 break; 602 603 case 24: /* Remove Underline */ 604 tem->tvs_flags &= ~TEM_ATTR_UNDERLINE; 605 break; 606 607 case 25: /* Remove Blink */ 608 tem->tvs_flags &= ~TEM_ATTR_BLINK; 609 break; 610 611 case 27: /* Remove Reverse */ 612 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 613 tem->tvs_flags |= TEM_ATTR_REVERSE; 614 } else { 615 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 616 } 617 break; 618 619 case 30: /* black (grey) foreground */ 620 case 31: /* red (light red) foreground */ 621 case 32: /* green (light green) foreground */ 622 case 33: /* brown (yellow) foreground */ 623 case 34: /* blue (light blue) foreground */ 624 case 35: /* magenta (light magenta) foreground */ 625 case 36: /* cyan (light cyan) foreground */ 626 case 37: /* white (bright white) foreground */ 627 tem->tvs_fg_color = param - 30; 628 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 629 break; 630 631 case 38: 632 /* We should have at least 3 parameters */ 633 if (curparam < 3) 634 break; 635 636 /* 637 * 256 and truecolor needs depth at least 24, but 638 * we still need to process the sequence. 639 */ 640 count++; 641 curparam--; 642 param = tem->tvs_params[count]; 643 switch (param) { 644 case 5: /* 256 colors */ 645 count++; 646 curparam--; 647 tem_select_color(tem, tem->tvs_params[count], 648 B_TRUE); 649 break; 650 default: 651 break; 652 } 653 break; 654 655 case 39: 656 /* 657 * Reset the foreground colour and brightness. 658 */ 659 tem->tvs_fg_color = tems.ts_init_color.fg_color; 660 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG) 661 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 662 else 663 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 664 break; 665 666 case 40: /* black (grey) background */ 667 case 41: /* red (light red) background */ 668 case 42: /* green (light green) background */ 669 case 43: /* brown (yellow) background */ 670 case 44: /* blue (light blue) background */ 671 case 45: /* magenta (light magenta) background */ 672 case 46: /* cyan (light cyan) background */ 673 case 47: /* white (bright white) background */ 674 tem->tvs_bg_color = param - 40; 675 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 676 break; 677 678 case 48: 679 /* We should have at least 3 parameters */ 680 if (curparam < 3) 681 break; 682 683 /* 684 * 256 and truecolor needs depth at least 24, but 685 * we still need to process the sequence. 686 */ 687 count++; 688 curparam--; 689 param = tem->tvs_params[count]; 690 switch (param) { 691 case 5: /* 256 colors */ 692 count++; 693 curparam--; 694 tem_select_color(tem, tem->tvs_params[count], 695 B_FALSE); 696 break; 697 default: 698 break; 699 } 700 break; 701 702 case 49: 703 /* 704 * Reset the background colour and brightness. 705 */ 706 tem->tvs_bg_color = tems.ts_init_color.bg_color; 707 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG) 708 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 709 else 710 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 711 break; 712 713 case 90: /* black (grey) foreground */ 714 case 91: /* red (light red) foreground */ 715 case 92: /* green (light green) foreground */ 716 case 93: /* brown (yellow) foreground */ 717 case 94: /* blue (light blue) foreground */ 718 case 95: /* magenta (light magenta) foreground */ 719 case 96: /* cyan (light cyan) foreground */ 720 case 97: /* white (bright white) foreground */ 721 tem->tvs_fg_color = param - 90; 722 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 723 break; 724 725 case 100: /* black (grey) background */ 726 case 101: /* red (light red) background */ 727 case 102: /* green (light green) background */ 728 case 103: /* brown (yellow) background */ 729 case 104: /* blue (light blue) background */ 730 case 105: /* magenta (light magenta) background */ 731 case 106: /* cyan (light cyan) background */ 732 case 107: /* white (bright white) background */ 733 tem->tvs_bg_color = param - 100; 734 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 735 break; 736 737 default: 738 break; 739 } 740 count++; 741 curparam--; 742 743 } while (curparam > 0); 744 } 745 746 /* 747 * perform the appropriate action for the escape sequence 748 * 749 * General rule: This code does not validate the arguments passed. 750 * It assumes that the next lower level will do so. 751 */ 752 static void 753 tem_safe_chkparam(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp, 754 enum called_from called_from) 755 { 756 int i; 757 int row; 758 int col; 759 760 ASSERT((called_from == CALLED_FROM_STANDALONE) || 761 MUTEX_HELD(&tem->tvs_lock)); 762 763 row = tem->tvs_c_cursor.row; 764 col = tem->tvs_c_cursor.col; 765 766 switch (ch) { 767 768 case 'm': /* select terminal graphics mode */ 769 tem_safe_send_data(tem, credp, called_from); 770 tem_safe_selgraph(tem); 771 break; 772 773 case '@': /* insert char */ 774 tem_safe_setparam(tem, 1, 1); 775 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT, 776 credp, called_from); 777 break; 778 779 case 'A': /* cursor up */ 780 tem_safe_setparam(tem, 1, 1); 781 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col, 782 credp, called_from); 783 break; 784 785 case 'd': /* VPA - vertical position absolute */ 786 tem_safe_setparam(tem, 1, 1); 787 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col, 788 credp, called_from); 789 break; 790 791 case 'e': /* VPR - vertical position relative */ 792 case 'B': /* cursor down */ 793 tem_safe_setparam(tem, 1, 1); 794 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col, 795 credp, called_from); 796 break; 797 798 case 'a': /* HPR - horizontal position relative */ 799 case 'C': /* cursor right */ 800 tem_safe_setparam(tem, 1, 1); 801 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0], 802 credp, called_from); 803 break; 804 805 case '`': /* HPA - horizontal position absolute */ 806 tem_safe_setparam(tem, 1, 1); 807 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1, 808 credp, called_from); 809 break; 810 811 case 'D': /* cursor left */ 812 tem_safe_setparam(tem, 1, 1); 813 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0], 814 credp, called_from); 815 break; 816 817 case 'E': /* CNL cursor next line */ 818 tem_safe_setparam(tem, 1, 1); 819 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0, 820 credp, called_from); 821 break; 822 823 case 'F': /* CPL cursor previous line */ 824 tem_safe_setparam(tem, 1, 1); 825 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0, 826 credp, called_from); 827 break; 828 829 case 'G': /* cursor horizontal position */ 830 tem_safe_setparam(tem, 1, 1); 831 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1, 832 credp, called_from); 833 break; 834 835 case 'g': /* clear tabs */ 836 tem_safe_setparam(tem, 1, 0); 837 tem_safe_clear_tabs(tem, tem->tvs_params[0]); 838 break; 839 840 case 'f': /* HVP Horizontal and Vertical Position */ 841 case 'H': /* CUP position cursor */ 842 tem_safe_setparam(tem, 2, 1); 843 tem_safe_mv_cursor(tem, 844 tem->tvs_params[0] - 1, 845 tem->tvs_params[1] - 1, 846 credp, called_from); 847 break; 848 849 case 'I': /* CHT - Cursor Horizontal Tab */ 850 /* Not implemented */ 851 break; 852 853 case 'J': /* ED - Erase in Display */ 854 tem_safe_send_data(tem, credp, called_from); 855 tem_safe_setparam(tem, 1, 0); 856 switch (tem->tvs_params[0]) { 857 case 0: 858 /* erase cursor to end of screen */ 859 /* FIRST erase cursor to end of line */ 860 tem_safe_clear_chars(tem, 861 tems.ts_c_dimension.width - 862 tem->tvs_c_cursor.col, 863 tem->tvs_c_cursor.row, 864 tem->tvs_c_cursor.col, credp, called_from); 865 866 /* THEN erase lines below the cursor */ 867 for (row = tem->tvs_c_cursor.row + 1; 868 row < tems.ts_c_dimension.height; 869 row++) { 870 tem_safe_clear_chars(tem, 871 tems.ts_c_dimension.width, 872 row, 0, credp, called_from); 873 } 874 break; 875 876 case 1: 877 /* erase beginning of screen to cursor */ 878 /* FIRST erase lines above the cursor */ 879 for (row = 0; 880 row < tem->tvs_c_cursor.row; 881 row++) { 882 tem_safe_clear_chars(tem, 883 tems.ts_c_dimension.width, 884 row, 0, credp, called_from); 885 } 886 /* THEN erase beginning of line to cursor */ 887 tem_safe_clear_chars(tem, 888 tem->tvs_c_cursor.col + 1, 889 tem->tvs_c_cursor.row, 890 0, credp, called_from); 891 break; 892 893 case 2: 894 /* erase whole screen */ 895 for (row = 0; 896 row < tems.ts_c_dimension.height; 897 row++) { 898 tem_safe_clear_chars(tem, 899 tems.ts_c_dimension.width, 900 row, 0, credp, called_from); 901 } 902 break; 903 } 904 break; 905 906 case 'K': /* EL - Erase in Line */ 907 tem_safe_send_data(tem, credp, called_from); 908 tem_safe_setparam(tem, 1, 0); 909 switch (tem->tvs_params[0]) { 910 case 0: 911 /* erase cursor to end of line */ 912 tem_safe_clear_chars(tem, 913 (tems.ts_c_dimension.width - 914 tem->tvs_c_cursor.col), 915 tem->tvs_c_cursor.row, 916 tem->tvs_c_cursor.col, 917 credp, called_from); 918 break; 919 920 case 1: 921 /* erase beginning of line to cursor */ 922 tem_safe_clear_chars(tem, 923 tem->tvs_c_cursor.col + 1, 924 tem->tvs_c_cursor.row, 925 0, credp, called_from); 926 break; 927 928 case 2: 929 /* erase whole line */ 930 tem_safe_clear_chars(tem, 931 tems.ts_c_dimension.width, 932 tem->tvs_c_cursor.row, 933 0, credp, called_from); 934 break; 935 } 936 break; 937 938 case 'L': /* insert line */ 939 tem_safe_send_data(tem, credp, called_from); 940 tem_safe_setparam(tem, 1, 1); 941 tem_safe_scroll(tem, 942 tem->tvs_c_cursor.row, 943 tems.ts_c_dimension.height - 1, 944 tem->tvs_params[0], TEM_SCROLL_DOWN, 945 credp, called_from); 946 break; 947 948 case 'M': /* delete line */ 949 tem_safe_send_data(tem, credp, called_from); 950 tem_safe_setparam(tem, 1, 1); 951 tem_safe_scroll(tem, 952 tem->tvs_c_cursor.row, 953 tems.ts_c_dimension.height - 1, 954 tem->tvs_params[0], TEM_SCROLL_UP, 955 credp, called_from); 956 break; 957 958 case 'P': /* DCH - delete char */ 959 tem_safe_setparam(tem, 1, 1); 960 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT, 961 credp, called_from); 962 break; 963 964 case 'S': /* scroll up */ 965 tem_safe_send_data(tem, credp, called_from); 966 tem_safe_setparam(tem, 1, 1); 967 tem_safe_scroll(tem, 0, 968 tems.ts_c_dimension.height - 1, 969 tem->tvs_params[0], TEM_SCROLL_UP, 970 credp, called_from); 971 break; 972 973 case 'T': /* scroll down */ 974 tem_safe_send_data(tem, credp, called_from); 975 tem_safe_setparam(tem, 1, 1); 976 tem_safe_scroll(tem, 0, 977 tems.ts_c_dimension.height - 1, 978 tem->tvs_params[0], TEM_SCROLL_DOWN, 979 credp, called_from); 980 break; 981 982 case 'X': /* erase char */ 983 tem_safe_setparam(tem, 1, 1); 984 tem_safe_clear_chars(tem, 985 tem->tvs_params[0], 986 tem->tvs_c_cursor.row, 987 tem->tvs_c_cursor.col, 988 credp, called_from); 989 break; 990 991 case 'Z': /* cursor backward tabulation */ 992 tem_safe_setparam(tem, 1, 1); 993 994 /* 995 * Rule exception - We do sanity checking here. 996 * 997 * Restrict the count to a sane value to keep from 998 * looping for a long time. There can't be more than one 999 * tab stop per column, so use that as a limit. 1000 */ 1001 if (tem->tvs_params[0] > tems.ts_c_dimension.width) 1002 tem->tvs_params[0] = tems.ts_c_dimension.width; 1003 1004 for (i = 0; i < tem->tvs_params[0]; i++) 1005 tem_safe_back_tab(tem, credp, called_from); 1006 break; 1007 } 1008 tem->tvs_state = A_STATE_START; 1009 } 1010 1011 1012 /* 1013 * Gather the parameters of an ANSI escape sequence 1014 */ 1015 static void 1016 tem_safe_getparams(struct tem_vt_state *tem, tem_char_t ch, 1017 cred_t *credp, enum called_from called_from) 1018 { 1019 ASSERT((called_from == CALLED_FROM_STANDALONE) || 1020 MUTEX_HELD(&tem->tvs_lock)); 1021 1022 if (ch >= '0' && ch <= '9') { 1023 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0')); 1024 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */ 1025 return; /* Return immediately */ 1026 } else if (tem->tvs_state == A_STATE_CSI_EQUAL || 1027 tem->tvs_state == A_STATE_CSI_QMARK) { 1028 tem->tvs_state = A_STATE_START; 1029 } else { 1030 if (tem->tvs_curparam < TEM_MAXPARAMS) { 1031 if (tem->tvs_gotparam) { 1032 /* get the parameter value */ 1033 tem->tvs_params[tem->tvs_curparam] = 1034 tem->tvs_paramval; 1035 } 1036 tem->tvs_curparam++; 1037 } 1038 1039 if (ch == ';') { 1040 /* Restart parameter search */ 1041 tem->tvs_gotparam = B_FALSE; 1042 tem->tvs_paramval = 0; /* No parame value yet */ 1043 } else { 1044 /* Handle escape sequence */ 1045 tem_safe_chkparam(tem, ch, credp, called_from); 1046 } 1047 } 1048 } 1049 1050 /* 1051 * Add character to internal buffer. 1052 * When its full, send it to the next layer. 1053 */ 1054 1055 static void 1056 tem_safe_outch(struct tem_vt_state *tem, tem_char_t ch, 1057 cred_t *credp, enum called_from called_from) 1058 { 1059 text_color_t fg; 1060 text_color_t bg; 1061 text_attr_t attr; 1062 1063 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1064 called_from == CALLED_FROM_STANDALONE); 1065 1066 /* buffer up the character until later */ 1067 tem_safe_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE); 1068 tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr); 1069 tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg; 1070 tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg; 1071 tem->tvs_outindex++; 1072 tem->tvs_c_cursor.col++; 1073 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) { 1074 tem_safe_send_data(tem, credp, called_from); 1075 tem_safe_new_line(tem, credp, called_from); 1076 } 1077 } 1078 1079 static void 1080 tem_safe_new_line(struct tem_vt_state *tem, 1081 cred_t *credp, enum called_from called_from) 1082 { 1083 tem_safe_cr(tem); 1084 tem_safe_lf(tem, credp, called_from); 1085 } 1086 1087 static void 1088 tem_safe_cr(struct tem_vt_state *tem) 1089 { 1090 tem->tvs_c_cursor.col = 0; 1091 tem_safe_align_cursor(tem); 1092 } 1093 1094 static void 1095 tem_safe_lf(struct tem_vt_state *tem, 1096 cred_t *credp, enum called_from called_from) 1097 { 1098 int row; 1099 1100 ASSERT((called_from == CALLED_FROM_STANDALONE) || 1101 MUTEX_HELD(&tem->tvs_lock)); 1102 1103 /* 1104 * Sanity checking notes: 1105 * . a_nscroll was validated when it was set. 1106 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor 1107 * will prevent anything bad from happening. 1108 */ 1109 row = tem->tvs_c_cursor.row + 1; 1110 1111 if (row >= tems.ts_c_dimension.height) { 1112 if (tem->tvs_nscroll != 0) { 1113 tem_safe_scroll(tem, 0, 1114 tems.ts_c_dimension.height - 1, 1115 tem->tvs_nscroll, TEM_SCROLL_UP, 1116 credp, called_from); 1117 row = tems.ts_c_dimension.height - 1118 tem->tvs_nscroll; 1119 } else { /* no scroll */ 1120 /* 1121 * implement Esc[#r when # is zero. This means no 1122 * scroll but just return cursor to top of screen, 1123 * do not clear screen. 1124 */ 1125 row = 0; 1126 } 1127 } 1128 1129 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col, 1130 credp, called_from); 1131 1132 if (tem->tvs_nscroll == 0) { 1133 /* erase rest of cursor line */ 1134 tem_safe_clear_chars(tem, 1135 tems.ts_c_dimension.width - 1136 tem->tvs_c_cursor.col, 1137 tem->tvs_c_cursor.row, 1138 tem->tvs_c_cursor.col, 1139 credp, called_from); 1140 1141 } 1142 1143 tem_safe_align_cursor(tem); 1144 } 1145 1146 static void 1147 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp, 1148 enum called_from called_from) 1149 { 1150 ASSERT((called_from == CALLED_FROM_STANDALONE) || 1151 MUTEX_HELD(&tem->tvs_lock)); 1152 1153 if (tem->tvs_outindex == 0) { 1154 tem_safe_align_cursor(tem); 1155 return; 1156 } 1157 1158 tem_safe_virtual_display(tem, 1159 tem->tvs_outbuf, tem->tvs_outindex, 1160 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); 1161 1162 if (tem->tvs_isactive) { 1163 /* 1164 * Call the primitive to render this data. 1165 */ 1166 tem_safe_callback_display(tem, 1167 tem->tvs_outbuf, tem->tvs_outindex, 1168 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col, 1169 credp, called_from); 1170 } 1171 1172 tem->tvs_outindex = 0; 1173 1174 tem_safe_align_cursor(tem); 1175 } 1176 1177 1178 /* 1179 * We have just done something to the current output point. Reset the start 1180 * point for the buffered data in a_outbuf. There shouldn't be any data 1181 * buffered yet. 1182 */ 1183 static void 1184 tem_safe_align_cursor(struct tem_vt_state *tem) 1185 { 1186 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row; 1187 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col; 1188 } 1189 1190 /* 1191 * State machine parser based on the current state and character input 1192 * major terminations are to control character or normal character 1193 */ 1194 1195 static void 1196 tem_safe_parse(struct tem_vt_state *tem, tem_char_t ch, 1197 cred_t *credp, enum called_from called_from) 1198 { 1199 int i; 1200 1201 ASSERT((called_from == CALLED_FROM_STANDALONE) || 1202 MUTEX_HELD(&tem->tvs_lock)); 1203 1204 if (tem->tvs_state == A_STATE_START) { /* Normal state? */ 1205 if (ch == A_CSI || ch == A_ESC || ch < ' ') { 1206 /* Control */ 1207 tem_safe_control(tem, ch, credp, called_from); 1208 } else { 1209 /* Display */ 1210 tem_safe_outch(tem, ch, credp, called_from); 1211 } 1212 return; 1213 } 1214 1215 /* In <ESC> sequence */ 1216 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */ 1217 if (tem->tvs_state != A_STATE_CSI) { 1218 tem_safe_getparams(tem, ch, credp, called_from); 1219 return; 1220 } 1221 1222 switch (ch) { 1223 case '?': 1224 tem->tvs_state = A_STATE_CSI_QMARK; 1225 return; 1226 case '=': 1227 tem->tvs_state = A_STATE_CSI_EQUAL; 1228 return; 1229 case 's': 1230 /* 1231 * As defined below, this sequence 1232 * saves the cursor. However, Sun 1233 * defines ESC[s as reset. We resolved 1234 * the conflict by selecting reset as it 1235 * is exported in the termcap file for 1236 * sun-mon, while the "save cursor" 1237 * definition does not exist anywhere in 1238 * /etc/termcap. 1239 * However, having no coherent 1240 * definition of reset, we have not 1241 * implemented it. 1242 */ 1243 1244 /* 1245 * Original code 1246 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; 1247 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; 1248 * tem->tvs_state = A_STATE_START; 1249 */ 1250 1251 tem->tvs_state = A_STATE_START; 1252 return; 1253 case 'u': 1254 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row, 1255 tem->tvs_r_cursor.col, credp, called_from); 1256 tem->tvs_state = A_STATE_START; 1257 return; 1258 case 'p': /* sunbow */ 1259 tem_safe_send_data(tem, credp, called_from); 1260 /* 1261 * Don't set anything if we are 1262 * already as we want to be. 1263 */ 1264 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 1265 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE; 1266 /* 1267 * If we have switched the characters to be the 1268 * inverse from the screen, then switch them as 1269 * well to keep them the inverse of the screen. 1270 */ 1271 if (tem->tvs_flags & TEM_ATTR_REVERSE) 1272 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1273 else 1274 tem->tvs_flags |= TEM_ATTR_REVERSE; 1275 } 1276 tem_safe_cls(tem, credp, called_from); 1277 tem->tvs_state = A_STATE_START; 1278 return; 1279 case 'q': /* sunwob */ 1280 tem_safe_send_data(tem, credp, called_from); 1281 /* 1282 * Don't set anything if we are 1283 * already where as we want to be. 1284 */ 1285 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) { 1286 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE; 1287 /* 1288 * If we have switched the characters to be the 1289 * inverse from the screen, then switch them as 1290 * well to keep them the inverse of the screen. 1291 */ 1292 if (!(tem->tvs_flags & TEM_ATTR_REVERSE)) 1293 tem->tvs_flags |= TEM_ATTR_REVERSE; 1294 else 1295 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1296 } 1297 1298 tem_safe_cls(tem, credp, called_from); 1299 tem->tvs_state = A_STATE_START; 1300 return; 1301 case 'r': /* sunscrl */ 1302 /* 1303 * Rule exception: check for validity here. 1304 */ 1305 tem->tvs_nscroll = tem->tvs_paramval; 1306 if (tem->tvs_nscroll > tems.ts_c_dimension.height) 1307 tem->tvs_nscroll = tems.ts_c_dimension.height; 1308 if (tem->tvs_nscroll < 0) 1309 tem->tvs_nscroll = 1; 1310 tem->tvs_state = A_STATE_START; 1311 return; 1312 default: 1313 tem_safe_getparams(tem, ch, credp, called_from); 1314 return; 1315 } 1316 } 1317 1318 /* Previous char was <ESC> */ 1319 if (ch == '[') { 1320 tem->tvs_curparam = 0; 1321 tem->tvs_paramval = 0; 1322 tem->tvs_gotparam = B_FALSE; 1323 /* clear the parameters */ 1324 for (i = 0; i < TEM_MAXPARAMS; i++) 1325 tem->tvs_params[i] = -1; 1326 tem->tvs_state = A_STATE_CSI; 1327 } else if (ch == 'Q') { /* <ESC>Q ? */ 1328 tem->tvs_state = A_STATE_START; 1329 } else if (ch == 'C') { /* <ESC>C ? */ 1330 tem->tvs_state = A_STATE_START; 1331 } else { 1332 tem->tvs_state = A_STATE_START; 1333 if (ch == 'c') { 1334 /* ESC c resets display */ 1335 tem_safe_reset_display(tem, credp, called_from, 1336 B_TRUE, B_TRUE); 1337 } else if (ch == 'H') { 1338 /* ESC H sets a tab */ 1339 tem_safe_set_tab(tem); 1340 } else if (ch == '7') { 1341 /* ESC 7 Save Cursor position */ 1342 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; 1343 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; 1344 } else if (ch == '8') { 1345 /* ESC 8 Restore Cursor position */ 1346 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row, 1347 tem->tvs_r_cursor.col, credp, called_from); 1348 /* check for control chars */ 1349 } else if (ch < ' ') { 1350 tem_safe_control(tem, ch, credp, called_from); 1351 } else { 1352 tem_safe_outch(tem, ch, credp, called_from); 1353 } 1354 } 1355 } 1356 1357 /* ARGSUSED */ 1358 static void 1359 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from) 1360 { 1361 if (called_from == CALLED_FROM_STANDALONE) 1362 (void) beep_polled(BEEP_CONSOLE); 1363 else 1364 (void) beep(BEEP_CONSOLE); 1365 } 1366 1367 1368 static void 1369 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count, 1370 int direction, cred_t *credp, enum called_from called_from) 1371 { 1372 int row; 1373 int lines_affected; 1374 1375 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1376 called_from == CALLED_FROM_STANDALONE); 1377 1378 lines_affected = end - start + 1; 1379 if (count > lines_affected) 1380 count = lines_affected; 1381 if (count <= 0) 1382 return; 1383 1384 switch (direction) { 1385 case TEM_SCROLL_UP: 1386 if (count < lines_affected) { 1387 tem_safe_copy_area(tem, 0, start + count, 1388 tems.ts_c_dimension.width - 1, end, 1389 0, start, credp, called_from); 1390 } 1391 for (row = (end - count) + 1; row <= end; row++) { 1392 tem_safe_clear_chars(tem, tems.ts_c_dimension.width, 1393 row, 0, credp, called_from); 1394 } 1395 break; 1396 1397 case TEM_SCROLL_DOWN: 1398 if (count < lines_affected) { 1399 tem_safe_copy_area(tem, 0, start, 1400 tems.ts_c_dimension.width - 1, 1401 end - count, 0, start + count, 1402 credp, called_from); 1403 } 1404 for (row = start; row < start + count; row++) { 1405 tem_safe_clear_chars(tem, tems.ts_c_dimension.width, 1406 row, 0, credp, called_from); 1407 } 1408 break; 1409 } 1410 } 1411 1412 static int 1413 tem_copy_width(term_char_t *src, term_char_t *dst, int cols) 1414 { 1415 int width = cols - 1; 1416 1417 while (width >= 0) { 1418 /* We can't compare images. */ 1419 if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE || 1420 TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE) 1421 break; 1422 1423 /* 1424 * Find difference on line, compare char with its attributes 1425 * and colors. 1426 */ 1427 if (src[width].tc_char != dst[width].tc_char || 1428 src[width].tc_fg_color != dst[width].tc_fg_color || 1429 src[width].tc_bg_color != dst[width].tc_bg_color) { 1430 break; 1431 } 1432 width--; 1433 } 1434 return (width + 1); 1435 } 1436 1437 static void 1438 tem_safe_copy_area(struct tem_vt_state *tem, 1439 screen_pos_t s_col, screen_pos_t s_row, 1440 screen_pos_t e_col, screen_pos_t e_row, 1441 screen_pos_t t_col, screen_pos_t t_row, 1442 cred_t *credp, enum called_from called_from) 1443 { 1444 size_t soffset, toffset; 1445 term_char_t *src, *dst; 1446 int rows; 1447 int cols; 1448 1449 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1450 called_from == CALLED_FROM_STANDALONE); 1451 1452 if (s_col < 0 || s_row < 0 || 1453 e_col < 0 || e_row < 0 || 1454 t_col < 0 || t_row < 0 || 1455 s_col >= tems.ts_c_dimension.width || 1456 e_col >= tems.ts_c_dimension.width || 1457 t_col >= tems.ts_c_dimension.width || 1458 s_row >= tems.ts_c_dimension.height || 1459 e_row >= tems.ts_c_dimension.height || 1460 t_row >= tems.ts_c_dimension.height) 1461 return; 1462 1463 if (s_row > e_row || s_col > e_col) 1464 return; 1465 1466 rows = e_row - s_row + 1; 1467 cols = e_col - s_col + 1; 1468 if (t_row + rows > tems.ts_c_dimension.height || 1469 t_col + cols > tems.ts_c_dimension.width) 1470 return; 1471 1472 soffset = s_col + s_row * tems.ts_c_dimension.width; 1473 toffset = t_col + t_row * tems.ts_c_dimension.width; 1474 src = tem->tvs_screen_buf + soffset; 1475 dst = tem->tvs_screen_buf + toffset; 1476 1477 /* 1478 * Copy line by line. We determine the length by comparing the 1479 * screen content from cached text in tvs_screen_buf. 1480 */ 1481 if (toffset <= soffset) { 1482 for (int i = 0; i < rows; i++) { 1483 int increment = i * tems.ts_c_dimension.width; 1484 int width; 1485 1486 width = tem_copy_width(src + increment, 1487 dst + increment, cols); 1488 1489 tem_safe_virtual_copy(tem, s_col, s_row + i, 1490 e_col - cols + width, s_row + i, 1491 t_col, t_row + i); 1492 1493 if (tem->tvs_isactive) { 1494 tem_safe_callback_copy(tem, s_col, s_row + i, 1495 e_col - cols + width, s_row + i, 1496 t_col, t_row + i, credp, called_from); 1497 } 1498 } 1499 } else { 1500 for (int i = rows - 1; i >= 0; i--) { 1501 int increment = i * tems.ts_c_dimension.width; 1502 int width; 1503 1504 width = tem_copy_width(src + increment, 1505 dst + increment, cols); 1506 1507 tem_safe_virtual_copy(tem, s_col, s_row + i, 1508 e_col - cols + width, s_row + i, 1509 t_col, t_row + i); 1510 1511 if (tem->tvs_isactive) { 1512 tem_safe_callback_copy(tem, s_col, s_row + i, 1513 e_col - cols + width, s_row + i, 1514 t_col, t_row + i, credp, called_from); 1515 } 1516 } 1517 } 1518 } 1519 1520 static void 1521 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row, 1522 screen_pos_t col, cred_t *credp, enum called_from called_from) 1523 { 1524 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1525 called_from == CALLED_FROM_STANDALONE); 1526 1527 if (row < 0 || row >= tems.ts_c_dimension.height || 1528 col < 0 || col >= tems.ts_c_dimension.width || 1529 count < 0) 1530 return; 1531 1532 /* 1533 * Note that very large values of "count" could cause col+count 1534 * to overflow, so we check "count" independently. 1535 */ 1536 if (count > tems.ts_c_dimension.width || 1537 col + count > tems.ts_c_dimension.width) 1538 count = tems.ts_c_dimension.width - col; 1539 1540 tem_safe_virtual_cls(tem, count, row, col); 1541 1542 if (!tem->tvs_isactive) 1543 return; 1544 1545 tem_safe_callback_cls(tem, count, row, col, credp, called_from); 1546 } 1547 1548 /*ARGSUSED*/ 1549 void 1550 tem_safe_text_display(struct tem_vt_state *tem, term_char_t *string, 1551 int count, screen_pos_t row, screen_pos_t col, 1552 cred_t *credp, enum called_from called_from) 1553 { 1554 struct vis_consdisplay da; 1555 int i; 1556 tem_char_t c; 1557 1558 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1559 called_from == CALLED_FROM_STANDALONE); 1560 1561 da.data = (uint8_t *)&c; 1562 da.width = 1; 1563 da.row = row; 1564 da.col = col; 1565 1566 for (i = 0; i < count; i++) { 1567 tem_safe_get_color(&da.fg_color, &da.bg_color, string[i]); 1568 c = TEM_CHAR(string[i].tc_char); 1569 tems_safe_display(&da, credp, called_from); 1570 da.col++; 1571 } 1572 } 1573 1574 #if 0 1575 /* 1576 * This function is used to blit a rectangular color image, 1577 * unperturbed on the underlying framebuffer, to render 1578 * icons and pictures. The data is a pixel pattern that 1579 * fills a rectangle bounded to the width and height parameters. 1580 * The color pixel data must to be pre-adjusted by the caller 1581 * for the current video depth. 1582 * 1583 * This function is unused now. 1584 */ 1585 /*ARGSUSED*/ 1586 static void 1587 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image, 1588 int height, int width, screen_pos_t row, screen_pos_t col, 1589 cred_t *credp, enum called_from called_from) 1590 { 1591 struct vis_consdisplay da; 1592 1593 mutex_enter(&tems.ts_lock); 1594 mutex_enter(&tem->tvs_lock); 1595 1596 da.data = image; 1597 da.width = (screen_size_t)width; 1598 da.height = (screen_size_t)height; 1599 da.row = row; 1600 da.col = col; 1601 1602 tems_safe_display(&da, credp, called_from); 1603 1604 mutex_exit(&tem->tvs_lock); 1605 mutex_exit(&tems.ts_lock); 1606 } 1607 #endif 1608 1609 /*ARGSUSED*/ 1610 void 1611 tem_safe_text_copy(struct tem_vt_state *tem, 1612 screen_pos_t s_col, screen_pos_t s_row, 1613 screen_pos_t e_col, screen_pos_t e_row, 1614 screen_pos_t t_col, screen_pos_t t_row, 1615 cred_t *credp, enum called_from called_from) 1616 { 1617 struct vis_conscopy da; 1618 1619 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1620 called_from == CALLED_FROM_STANDALONE); 1621 1622 da.s_row = s_row; 1623 da.s_col = s_col; 1624 da.e_row = e_row; 1625 da.e_col = e_col; 1626 da.t_row = t_row; 1627 da.t_col = t_col; 1628 1629 tems_safe_copy(&da, credp, called_from); 1630 } 1631 1632 void 1633 tem_safe_text_cls(struct tem_vt_state *tem, 1634 int count, screen_pos_t row, screen_pos_t col, cred_t *credp, 1635 enum called_from called_from) 1636 { 1637 text_attr_t attr; 1638 term_char_t c; 1639 int i; 1640 1641 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1642 called_from == CALLED_FROM_STANDALONE); 1643 1644 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 1645 TEM_ATTR_SCREEN_REVERSE); 1646 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; 1647 1648 if (count > tems.ts_c_dimension.width || 1649 col + count > tems.ts_c_dimension.width) 1650 count = tems.ts_c_dimension.width - col; 1651 1652 for (i = 0; i < count; i++) 1653 tems.ts_blank_line[i] = c; 1654 1655 tem_safe_text_display(tem, tems.ts_blank_line, count, row, col, 1656 credp, called_from); 1657 } 1658 1659 void 1660 tem_safe_pix_display(struct tem_vt_state *tem, 1661 term_char_t *string, int count, 1662 screen_pos_t row, screen_pos_t col, 1663 cred_t *credp, enum called_from called_from) 1664 { 1665 struct vis_consdisplay da; 1666 int i; 1667 1668 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1669 called_from == CALLED_FROM_STANDALONE); 1670 1671 da.data = (uchar_t *)tem->tvs_pix_data; 1672 da.width = (screen_size_t)tems.ts_font.vf_width; 1673 da.height = (screen_size_t)tems.ts_font.vf_height; 1674 da.row = (row * da.height) + tems.ts_p_offset.y; 1675 da.col = (col * da.width) + tems.ts_p_offset.x; 1676 1677 for (i = 0; i < count; i++) { 1678 /* Do not display image area */ 1679 if (!TEM_ATTR_ISSET(string[i].tc_char, TEM_ATTR_IMAGE)) { 1680 tem_safe_callback_bit2pix(tem, string[i]); 1681 tems_safe_display(&da, credp, called_from); 1682 } 1683 da.col += da.width; 1684 } 1685 } 1686 1687 void 1688 tem_safe_pix_copy(struct tem_vt_state *tem, 1689 screen_pos_t s_col, screen_pos_t s_row, 1690 screen_pos_t e_col, screen_pos_t e_row, 1691 screen_pos_t t_col, screen_pos_t t_row, 1692 cred_t *credp, 1693 enum called_from called_from) 1694 { 1695 struct vis_conscopy ma; 1696 static boolean_t need_clear = B_TRUE; 1697 1698 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1699 called_from == CALLED_FROM_STANDALONE); 1700 1701 if (need_clear && tem->tvs_first_line > 0) { 1702 /* 1703 * Clear OBP output above our kernel console term 1704 * when our kernel console term begins to scroll up, 1705 * we hope it is user friendly. 1706 * (Also see comments on tem_safe_pix_clear_prom_output) 1707 * 1708 * This is only one time call. 1709 */ 1710 tem_safe_pix_clear_prom_output(tem, credp, called_from); 1711 } 1712 need_clear = B_FALSE; 1713 1714 ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y; 1715 ma.e_row = (e_row + 1) * tems.ts_font.vf_height + 1716 tems.ts_p_offset.y - 1; 1717 ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y; 1718 1719 /* 1720 * Check if we're in process of clearing OBP's columns area, 1721 * which only happens when term scrolls up a whole line. 1722 */ 1723 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 && 1724 e_col == tems.ts_c_dimension.width - 1) { 1725 /* 1726 * We need to clear OBP's columns area outside our kernel 1727 * console term. So that we set ma.e_col to entire row here. 1728 */ 1729 ma.s_col = s_col * tems.ts_font.vf_width; 1730 ma.e_col = tems.ts_p_dimension.width - 1; 1731 1732 ma.t_col = t_col * tems.ts_font.vf_width; 1733 } else { 1734 ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x; 1735 ma.e_col = (e_col + 1) * tems.ts_font.vf_width + 1736 tems.ts_p_offset.x - 1; 1737 ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x; 1738 } 1739 1740 tems_safe_copy(&ma, credp, called_from); 1741 1742 if (tem->tvs_first_line > 0 && t_row < s_row) { 1743 /* We have scrolled up (s_row - t_row) rows. */ 1744 tem->tvs_first_line -= (s_row - t_row); 1745 if (tem->tvs_first_line <= 0) { 1746 /* All OBP rows have been cleared. */ 1747 tem->tvs_first_line = 0; 1748 } 1749 } 1750 1751 } 1752 1753 void 1754 tem_safe_pix_bit2pix(struct tem_vt_state *tem, term_char_t c) 1755 { 1756 text_color_t fg, bg; 1757 void (*fp)(struct tem_vt_state *, tem_char_t, 1758 unsigned char, unsigned char); 1759 1760 tem_safe_get_color(&fg, &bg, c); 1761 switch (tems.ts_pdepth) { 1762 case 4: 1763 fp = bit_to_pix4; 1764 break; 1765 case 8: 1766 fp = bit_to_pix8; 1767 break; 1768 case 15: 1769 case 16: 1770 fp = bit_to_pix16; 1771 break; 1772 case 24: 1773 fp = bit_to_pix24; 1774 break; 1775 case 32: 1776 fp = bit_to_pix32; 1777 break; 1778 default: 1779 return; 1780 } 1781 1782 fp(tem, c.tc_char, fg, bg); 1783 } 1784 1785 1786 /* 1787 * This function only clears count of columns in one row 1788 */ 1789 void 1790 tem_safe_pix_cls(struct tem_vt_state *tem, int count, 1791 screen_pos_t row, screen_pos_t col, cred_t *credp, 1792 enum called_from called_from) 1793 { 1794 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1795 called_from == CALLED_FROM_STANDALONE); 1796 1797 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y, 1798 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from); 1799 } 1800 1801 /* 1802 * This function clears OBP output above our kernel console term area 1803 * because OBP's term may have a bigger terminal window than that of 1804 * our kernel console term. So we need to clear OBP output garbage outside 1805 * of our kernel console term at a proper time, which is when the first 1806 * row output of our kernel console term scrolls at the first screen line. 1807 * 1808 * _________________________________ 1809 * | _____________________ | ---> OBP's bigger term window 1810 * | | | | 1811 * |___| | | 1812 * | | | | | 1813 * | | | | | 1814 * |_|_|___________________|_______| 1815 * | | | ---> first line 1816 * | |___________________|---> our kernel console term window 1817 * | 1818 * |---> columns area to be cleared 1819 * 1820 * This function only takes care of the output above our kernel console term, 1821 * and tem_prom_scroll_up takes care of columns area outside of our kernel 1822 * console term. 1823 */ 1824 static void 1825 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp, 1826 enum called_from called_from) 1827 { 1828 int nrows, ncols, width, height, offset; 1829 1830 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1831 called_from == CALLED_FROM_STANDALONE); 1832 1833 width = tems.ts_font.vf_width; 1834 height = tems.ts_font.vf_height; 1835 offset = tems.ts_p_offset.y % height; 1836 1837 nrows = tems.ts_p_offset.y / height; 1838 ncols = (tems.ts_p_dimension.width + (width - 1))/ width; 1839 1840 if (nrows > 0) 1841 tem_safe_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0, 1842 B_FALSE, credp, called_from); 1843 } 1844 1845 /* 1846 * clear the whole screen for pixel mode, just clear the 1847 * physical screen. 1848 */ 1849 void 1850 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp, 1851 enum called_from called_from) 1852 { 1853 struct vis_consclear cl; 1854 text_color_t fg_color; 1855 text_color_t bg_color; 1856 text_attr_t attr; 1857 term_char_t c; 1858 int nrows, ncols, width, height; 1859 1860 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1861 called_from == CALLED_FROM_STANDALONE); 1862 1863 /* call driver first, if error, clear terminal area */ 1864 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 1865 TEM_ATTR_SCREEN_REVERSE); 1866 c.tc_char = TEM_ATTR(attr); 1867 1868 tem_safe_get_color(&fg_color, &bg_color, c); 1869 cl.bg_color = bg_color; 1870 if (tems_cls_layered(&cl, credp) == 0) 1871 return; 1872 1873 width = tems.ts_font.vf_width; 1874 height = tems.ts_font.vf_height; 1875 1876 nrows = (tems.ts_p_dimension.height + (height - 1))/ height; 1877 ncols = (tems.ts_p_dimension.width + (width - 1))/ width; 1878 1879 tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, 0, ncols, 1880 tems.ts_p_offset.x, B_FALSE, credp, called_from); 1881 1882 /* 1883 * Since the whole screen is cleared, we don't need 1884 * to clear OBP output later. 1885 */ 1886 if (tem->tvs_first_line > 0) 1887 tem->tvs_first_line = 0; 1888 } 1889 1890 /* 1891 * clear the whole screen, including the virtual screen buffer, 1892 * and reset the cursor to start point. 1893 */ 1894 static void 1895 tem_safe_cls(struct tem_vt_state *tem, 1896 cred_t *credp, enum called_from called_from) 1897 { 1898 int row; 1899 1900 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1901 called_from == CALLED_FROM_STANDALONE); 1902 1903 if (tems.ts_display_mode == VIS_TEXT) { 1904 for (row = 0; row < tems.ts_c_dimension.height; row++) { 1905 tem_safe_clear_chars(tem, tems.ts_c_dimension.width, 1906 row, 0, credp, called_from); 1907 } 1908 tem->tvs_c_cursor.row = 0; 1909 tem->tvs_c_cursor.col = 0; 1910 tem_safe_align_cursor(tem); 1911 return; 1912 } 1913 1914 ASSERT(tems.ts_display_mode == VIS_PIXEL); 1915 1916 for (row = 0; row < tems.ts_c_dimension.height; row++) { 1917 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0); 1918 } 1919 tem->tvs_c_cursor.row = 0; 1920 tem->tvs_c_cursor.col = 0; 1921 tem_safe_align_cursor(tem); 1922 1923 if (!tem->tvs_isactive) 1924 return; 1925 1926 tem_safe_pix_clear_entire_screen(tem, credp, called_from); 1927 } 1928 1929 static void 1930 tem_safe_back_tab(struct tem_vt_state *tem, 1931 cred_t *credp, enum called_from called_from) 1932 { 1933 int i; 1934 screen_pos_t tabstop; 1935 1936 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1937 called_from == CALLED_FROM_STANDALONE); 1938 1939 tabstop = 0; 1940 1941 for (i = tem->tvs_ntabs - 1; i >= 0; i--) { 1942 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) { 1943 tabstop = tem->tvs_tabs[i]; 1944 break; 1945 } 1946 } 1947 1948 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row, 1949 tabstop, credp, called_from); 1950 } 1951 1952 static void 1953 tem_safe_tab(struct tem_vt_state *tem, 1954 cred_t *credp, enum called_from called_from) 1955 { 1956 int i; 1957 screen_pos_t tabstop; 1958 1959 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 1960 called_from == CALLED_FROM_STANDALONE); 1961 1962 tabstop = tems.ts_c_dimension.width - 1; 1963 1964 for (i = 0; i < tem->tvs_ntabs; i++) { 1965 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { 1966 tabstop = tem->tvs_tabs[i]; 1967 break; 1968 } 1969 } 1970 1971 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row, 1972 tabstop, credp, called_from); 1973 } 1974 1975 static void 1976 tem_safe_set_tab(struct tem_vt_state *tem) 1977 { 1978 int i; 1979 int j; 1980 1981 if (tem->tvs_ntabs == TEM_MAXTAB) 1982 return; 1983 if (tem->tvs_ntabs == 0 || 1984 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) { 1985 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col; 1986 return; 1987 } 1988 for (i = 0; i < tem->tvs_ntabs; i++) { 1989 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) 1990 return; 1991 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { 1992 for (j = tem->tvs_ntabs - 1; j >= i; j--) 1993 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j]; 1994 tem->tvs_tabs[i] = tem->tvs_c_cursor.col; 1995 tem->tvs_ntabs++; 1996 return; 1997 } 1998 } 1999 } 2000 2001 static void 2002 tem_safe_clear_tabs(struct tem_vt_state *tem, int action) 2003 { 2004 int i; 2005 int j; 2006 2007 switch (action) { 2008 case 3: /* clear all tabs */ 2009 tem->tvs_ntabs = 0; 2010 break; 2011 case 0: /* clr tab at cursor */ 2012 2013 for (i = 0; i < tem->tvs_ntabs; i++) { 2014 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) { 2015 tem->tvs_ntabs--; 2016 for (j = i; j < tem->tvs_ntabs; j++) 2017 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1]; 2018 return; 2019 } 2020 } 2021 break; 2022 } 2023 } 2024 2025 static void 2026 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col, 2027 cred_t *credp, enum called_from called_from) 2028 { 2029 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2030 called_from == CALLED_FROM_STANDALONE); 2031 2032 /* 2033 * Sanity check and bounds enforcement. Out of bounds requests are 2034 * clipped to the screen boundaries. This seems to be what SPARC 2035 * does. 2036 */ 2037 if (row < 0) 2038 row = 0; 2039 if (row >= tems.ts_c_dimension.height) 2040 row = tems.ts_c_dimension.height - 1; 2041 if (col < 0) 2042 col = 0; 2043 if (col >= tems.ts_c_dimension.width) 2044 col = tems.ts_c_dimension.width - 1; 2045 2046 tem_safe_send_data(tem, credp, called_from); 2047 tem->tvs_c_cursor.row = (screen_pos_t)row; 2048 tem->tvs_c_cursor.col = (screen_pos_t)col; 2049 tem_safe_align_cursor(tem); 2050 } 2051 2052 /* ARGSUSED */ 2053 void 2054 tem_safe_reset_emulator(struct tem_vt_state *tem, 2055 cred_t *credp, enum called_from called_from, 2056 boolean_t init_color) 2057 { 2058 int j; 2059 2060 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2061 called_from == CALLED_FROM_STANDALONE); 2062 2063 tem->tvs_c_cursor.row = 0; 2064 tem->tvs_c_cursor.col = 0; 2065 tem->tvs_r_cursor.row = 0; 2066 tem->tvs_r_cursor.col = 0; 2067 tem->tvs_s_cursor.row = 0; 2068 tem->tvs_s_cursor.col = 0; 2069 tem->tvs_outindex = 0; 2070 tem->tvs_state = A_STATE_START; 2071 tem->tvs_gotparam = B_FALSE; 2072 tem->tvs_curparam = 0; 2073 tem->tvs_paramval = 0; 2074 tem->tvs_nscroll = 1; 2075 2076 if (init_color) { 2077 /* use initial settings */ 2078 tem->tvs_fg_color = tems.ts_init_color.fg_color; 2079 tem->tvs_bg_color = tems.ts_init_color.bg_color; 2080 tem->tvs_flags = tems.ts_init_color.a_flags; 2081 } 2082 2083 /* 2084 * set up the initial tab stops 2085 */ 2086 tem->tvs_ntabs = 0; 2087 for (j = 8; j < tems.ts_c_dimension.width; j += 8) 2088 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j; 2089 2090 for (j = 0; j < TEM_MAXPARAMS; j++) 2091 tem->tvs_params[j] = 0; 2092 } 2093 2094 void 2095 tem_safe_reset_display(struct tem_vt_state *tem, 2096 cred_t *credp, enum called_from called_from, 2097 boolean_t clear_txt, boolean_t init_color) 2098 { 2099 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2100 called_from == CALLED_FROM_STANDALONE); 2101 2102 tem_safe_reset_emulator(tem, credp, called_from, init_color); 2103 2104 if (clear_txt) { 2105 if (tem->tvs_isactive) 2106 tem_safe_callback_cursor(tem, 2107 VIS_HIDE_CURSOR, credp, called_from); 2108 2109 tem_safe_cls(tem, credp, called_from); 2110 2111 if (tem->tvs_isactive) 2112 tem_safe_callback_cursor(tem, 2113 VIS_DISPLAY_CURSOR, credp, called_from); 2114 } 2115 } 2116 2117 static void 2118 tem_safe_shift( 2119 struct tem_vt_state *tem, 2120 int count, 2121 int direction, 2122 cred_t *credp, 2123 enum called_from called_from) 2124 { 2125 int rest_of_line; 2126 2127 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2128 called_from == CALLED_FROM_STANDALONE); 2129 2130 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col; 2131 if (count > rest_of_line) 2132 count = rest_of_line; 2133 2134 if (count <= 0) 2135 return; 2136 2137 switch (direction) { 2138 case TEM_SHIFT_LEFT: 2139 if (count < rest_of_line) { 2140 tem_safe_copy_area(tem, 2141 tem->tvs_c_cursor.col + count, 2142 tem->tvs_c_cursor.row, 2143 tems.ts_c_dimension.width - 1, 2144 tem->tvs_c_cursor.row, 2145 tem->tvs_c_cursor.col, 2146 tem->tvs_c_cursor.row, 2147 credp, called_from); 2148 } 2149 2150 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row, 2151 (tems.ts_c_dimension.width - count), credp, 2152 called_from); 2153 break; 2154 case TEM_SHIFT_RIGHT: 2155 if (count < rest_of_line) { 2156 tem_safe_copy_area(tem, 2157 tem->tvs_c_cursor.col, 2158 tem->tvs_c_cursor.row, 2159 tems.ts_c_dimension.width - count - 1, 2160 tem->tvs_c_cursor.row, 2161 tem->tvs_c_cursor.col + count, 2162 tem->tvs_c_cursor.row, 2163 credp, called_from); 2164 } 2165 2166 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row, 2167 tem->tvs_c_cursor.col, credp, called_from); 2168 break; 2169 } 2170 } 2171 2172 void 2173 tem_safe_text_cursor(struct tem_vt_state *tem, short action, 2174 cred_t *credp, enum called_from called_from) 2175 { 2176 struct vis_conscursor ca; 2177 2178 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2179 called_from == CALLED_FROM_STANDALONE); 2180 2181 ca.row = tem->tvs_c_cursor.row; 2182 ca.col = tem->tvs_c_cursor.col; 2183 ca.action = action; 2184 2185 tems_safe_cursor(&ca, credp, called_from); 2186 2187 if (action == VIS_GET_CURSOR) { 2188 tem->tvs_c_cursor.row = ca.row; 2189 tem->tvs_c_cursor.col = ca.col; 2190 } 2191 } 2192 2193 void 2194 tem_safe_pix_cursor(struct tem_vt_state *tem, short action, 2195 cred_t *credp, enum called_from called_from) 2196 { 2197 struct vis_conscursor ca; 2198 uint32_t color; 2199 text_color_t fg, bg; 2200 term_char_t c; 2201 text_attr_t attr; 2202 2203 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2204 called_from == CALLED_FROM_STANDALONE); 2205 2206 ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height + 2207 tems.ts_p_offset.y; 2208 ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width + 2209 tems.ts_p_offset.x; 2210 ca.width = (screen_size_t)tems.ts_font.vf_width; 2211 ca.height = (screen_size_t)tems.ts_font.vf_height; 2212 2213 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2214 TEM_ATTR_REVERSE); 2215 c.tc_char = TEM_ATTR(attr); 2216 2217 tem_safe_get_color(&fg, &bg, c); 2218 2219 switch (tems.ts_pdepth) { 2220 case 4: 2221 ca.fg_color.mono = fg; 2222 ca.bg_color.mono = bg; 2223 break; 2224 case 8: 2225 #ifdef _HAVE_TEM_FIRMWARE 2226 ca.fg_color.mono = fg; 2227 ca.bg_color.mono = bg; 2228 #else 2229 ca.fg_color.mono = tems.ts_color_map(fg); 2230 ca.bg_color.mono = tems.ts_color_map(bg); 2231 #endif 2232 break; 2233 case 15: 2234 case 16: 2235 color = tems.ts_color_map(fg); 2236 ca.fg_color.sixteen[0] = (color >> 8) & 0xFF; 2237 ca.fg_color.sixteen[1] = color & 0xFF; 2238 color = tems.ts_color_map(bg); 2239 ca.bg_color.sixteen[0] = (color >> 8) & 0xFF; 2240 ca.bg_color.sixteen[1] = color & 0xFF; 2241 break; 2242 case 24: 2243 case 32: 2244 #ifdef _HAVE_TEM_FIRMWARE 2245 /* Keeping this block to support old binary only drivers */ 2246 if (tem->tvs_flags & TEM_ATTR_REVERSE) { 2247 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED; 2248 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN; 2249 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE; 2250 2251 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED; 2252 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN; 2253 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE; 2254 } else { 2255 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED; 2256 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN; 2257 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE; 2258 2259 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED; 2260 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN; 2261 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE; 2262 } 2263 #else 2264 color = tems.ts_color_map(fg); 2265 ca.fg_color.twentyfour[0] = (color >> 16) & 0xFF; 2266 ca.fg_color.twentyfour[1] = (color >> 8) & 0xFF; 2267 ca.fg_color.twentyfour[2] = color & 0xFF; 2268 color = tems.ts_color_map(bg); 2269 ca.bg_color.twentyfour[0] = (color >> 16) & 0xFF; 2270 ca.bg_color.twentyfour[1] = (color >> 8) & 0xFF; 2271 ca.bg_color.twentyfour[2] = color & 0xFF; 2272 #endif 2273 break; 2274 } 2275 2276 ca.action = action; 2277 2278 tems_safe_cursor(&ca, credp, called_from); 2279 2280 if (action == VIS_GET_CURSOR) { 2281 tem->tvs_c_cursor.row = 0; 2282 tem->tvs_c_cursor.col = 0; 2283 2284 if (ca.row != 0) { 2285 tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) / 2286 tems.ts_font.vf_height; 2287 } 2288 if (ca.col != 0) { 2289 tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) / 2290 tems.ts_font.vf_width; 2291 } 2292 } 2293 } 2294 2295 static void 2296 bit_to_pix4(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color, 2297 text_color_t bg_color) 2298 { 2299 uint8_t *dest = (uint8_t *)tem->tvs_pix_data; 2300 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color); 2301 } 2302 2303 static void 2304 bit_to_pix8(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color, 2305 text_color_t bg_color) 2306 { 2307 uint8_t *dest = (uint8_t *)tem->tvs_pix_data; 2308 2309 #ifndef _HAVE_TEM_FIRMWARE 2310 fg_color = (text_color_t)tems.ts_color_map(fg_color); 2311 bg_color = (text_color_t)tems.ts_color_map(bg_color); 2312 #endif 2313 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color); 2314 } 2315 2316 static void 2317 bit_to_pix16(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4, 2318 text_color_t bg_color4) 2319 { 2320 uint16_t fg_color16, bg_color16; 2321 uint16_t *dest; 2322 2323 ASSERT(fg_color4 < 16 && bg_color4 < 16); 2324 2325 fg_color16 = (uint16_t)tems.ts_color_map(fg_color4); 2326 bg_color16 = (uint16_t)tems.ts_color_map(bg_color4); 2327 2328 dest = (uint16_t *)tem->tvs_pix_data; 2329 font_bit_to_pix16(&tems.ts_font, dest, c, fg_color16, bg_color16); 2330 } 2331 2332 static void 2333 bit_to_pix24(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4, 2334 text_color_t bg_color4) 2335 { 2336 uint32_t fg_color32, bg_color32; 2337 uint8_t *dest; 2338 2339 #ifdef _HAVE_TEM_FIRMWARE 2340 fg_color32 = PIX4TO32(fg_color4); 2341 bg_color32 = PIX4TO32(bg_color4); 2342 #else 2343 fg_color32 = tems.ts_color_map(fg_color4); 2344 bg_color32 = tems.ts_color_map(bg_color4); 2345 #endif 2346 2347 dest = (uint8_t *)tem->tvs_pix_data; 2348 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32); 2349 } 2350 2351 static void 2352 bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4, 2353 text_color_t bg_color4) 2354 { 2355 uint32_t fg_color32, bg_color32, *dest; 2356 2357 #ifdef _HAVE_TEM_FIRMWARE 2358 fg_color32 = PIX4TO32(fg_color4); 2359 bg_color32 = PIX4TO32(bg_color4); 2360 #else 2361 fg_color32 = ((uint32_t)0xFF << 24) | tems.ts_color_map(fg_color4); 2362 bg_color32 = ((uint32_t)0xFF << 24) | tems.ts_color_map(bg_color4); 2363 #endif 2364 2365 dest = (uint32_t *)tem->tvs_pix_data; 2366 font_bit_to_pix32(&tems.ts_font, dest, c, fg_color32, bg_color32); 2367 } 2368 2369 /* 2370 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE 2371 */ 2372 void 2373 tem_safe_get_attr(struct tem_vt_state *tem, text_color_t *fg, 2374 text_color_t *bg, text_attr_t *attr, uint8_t flag) 2375 { 2376 if (tem->tvs_flags & flag) { 2377 *fg = tem->tvs_bg_color; 2378 *bg = tem->tvs_fg_color; 2379 } else { 2380 *fg = tem->tvs_fg_color; 2381 *bg = tem->tvs_bg_color; 2382 } 2383 2384 if (attr == NULL) 2385 return; 2386 2387 *attr = tem->tvs_flags; 2388 } 2389 2390 static void 2391 tem_safe_get_color(text_color_t *fg, text_color_t *bg, term_char_t c) 2392 { 2393 boolean_t bold_font; 2394 2395 *fg = c.tc_fg_color; 2396 *bg = c.tc_bg_color; 2397 2398 bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0; 2399 2400 /* 2401 * If we have both normal and bold font components, 2402 * we use bold font for TEM_ATTR_BOLD. 2403 * The bright color is traditionally used with TEM_ATTR_BOLD, 2404 * in case there is no bold font. 2405 */ 2406 if (c.tc_fg_color < XLATE_NCOLORS) { 2407 if (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BRIGHT_FG) || 2408 (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BOLD) && !bold_font)) 2409 *fg = brt_xlate[c.tc_fg_color]; 2410 else 2411 *fg = dim_xlate[c.tc_fg_color]; 2412 } 2413 2414 if (c.tc_bg_color < XLATE_NCOLORS) { 2415 if (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BRIGHT_BG)) 2416 *bg = brt_xlate[c.tc_bg_color]; 2417 else 2418 *bg = dim_xlate[c.tc_bg_color]; 2419 } 2420 } 2421 2422 /* 2423 * Clear a rectangle of screen for pixel mode. 2424 * 2425 * arguments: 2426 * row: start row# 2427 * nrows: the number of rows to clear 2428 * offset_y: the offset of height in pixels to begin clear 2429 * col: start col# 2430 * ncols: the number of cols to clear 2431 * offset_x: the offset of width in pixels to begin clear 2432 * scroll_up: whether this function is called during sroll up, 2433 * which is called only once. 2434 */ 2435 void 2436 tem_safe_pix_cls_range(struct tem_vt_state *tem, 2437 screen_pos_t row, int nrows, int offset_y, 2438 screen_pos_t col, int ncols, int offset_x, 2439 boolean_t sroll_up, cred_t *credp, 2440 enum called_from called_from) 2441 { 2442 struct vis_consdisplay da; 2443 int i, j; 2444 int row_add = 0; 2445 term_char_t c; 2446 text_attr_t attr; 2447 2448 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2449 called_from == CALLED_FROM_STANDALONE); 2450 2451 if (sroll_up) 2452 row_add = tems.ts_c_dimension.height - 1; 2453 2454 da.width = (screen_size_t)tems.ts_font.vf_width; 2455 da.height = (screen_size_t)tems.ts_font.vf_height; 2456 2457 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2458 TEM_ATTR_SCREEN_REVERSE); 2459 /* Make sure we will not draw underlines */ 2460 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; 2461 2462 tem_safe_callback_bit2pix(tem, c); 2463 da.data = (uchar_t *)tem->tvs_pix_data; 2464 2465 for (i = 0; i < nrows; i++, row++) { 2466 da.row = (row + row_add) * da.height + offset_y; 2467 da.col = col * da.width + offset_x; 2468 for (j = 0; j < ncols; j++) { 2469 tems_safe_display(&da, credp, called_from); 2470 da.col += da.width; 2471 } 2472 } 2473 } 2474 2475 /* 2476 * virtual screen operations 2477 */ 2478 static void 2479 tem_safe_virtual_display(struct tem_vt_state *tem, term_char_t *string, 2480 int count, screen_pos_t row, screen_pos_t col) 2481 { 2482 int i, width; 2483 term_char_t *addr; 2484 2485 if (row < 0 || row >= tems.ts_c_dimension.height || 2486 col < 0 || col >= tems.ts_c_dimension.width || 2487 col + count > tems.ts_c_dimension.width) 2488 return; 2489 2490 width = tems.ts_c_dimension.width; 2491 addr = tem->tvs_screen_buf + (row * width + col); 2492 for (i = 0; i < count; i++) { 2493 *addr++ = string[i]; 2494 } 2495 } 2496 2497 static void 2498 i_virtual_copy_tem_chars(term_char_t *base, 2499 screen_pos_t s_col, screen_pos_t s_row, 2500 screen_pos_t e_col, screen_pos_t e_row, 2501 screen_pos_t t_col, screen_pos_t t_row) 2502 { 2503 term_char_t *from; 2504 term_char_t *to; 2505 int cnt; 2506 screen_size_t chars_per_row; 2507 term_char_t *to_row_start; 2508 term_char_t *from_row_start; 2509 screen_size_t rows_to_move; 2510 int cols = tems.ts_c_dimension.width; 2511 2512 chars_per_row = e_col - s_col + 1; 2513 rows_to_move = e_row - s_row + 1; 2514 2515 to_row_start = base + ((t_row * cols) + t_col); 2516 from_row_start = base + ((s_row * cols) + s_col); 2517 2518 if (to_row_start < from_row_start) { 2519 while (rows_to_move-- > 0) { 2520 to = to_row_start; 2521 from = from_row_start; 2522 to_row_start += cols; 2523 from_row_start += cols; 2524 for (cnt = chars_per_row; cnt-- > 0; ) 2525 *to++ = *from++; 2526 } 2527 } else { 2528 /* 2529 * Offset to the end of the region and copy backwards. 2530 */ 2531 cnt = rows_to_move * cols + chars_per_row; 2532 to_row_start += cnt; 2533 from_row_start += cnt; 2534 2535 while (rows_to_move-- > 0) { 2536 to_row_start -= cols; 2537 from_row_start -= cols; 2538 to = to_row_start; 2539 from = from_row_start; 2540 for (cnt = chars_per_row; cnt-- > 0; ) 2541 *--to = *--from; 2542 } 2543 } 2544 } 2545 2546 static void 2547 tem_safe_virtual_copy(struct tem_vt_state *tem, 2548 screen_pos_t s_col, screen_pos_t s_row, 2549 screen_pos_t e_col, screen_pos_t e_row, 2550 screen_pos_t t_col, screen_pos_t t_row) 2551 { 2552 screen_size_t chars_per_row; 2553 screen_size_t rows_to_move; 2554 int rows = tems.ts_c_dimension.height; 2555 int cols = tems.ts_c_dimension.width; 2556 2557 if (s_col < 0 || s_col >= cols || 2558 s_row < 0 || s_row >= rows || 2559 e_col < 0 || e_col >= cols || 2560 e_row < 0 || e_row >= rows || 2561 t_col < 0 || t_col >= cols || 2562 t_row < 0 || t_row >= rows || 2563 s_col > e_col || 2564 s_row > e_row) 2565 return; 2566 2567 chars_per_row = e_col - s_col + 1; 2568 rows_to_move = e_row - s_row + 1; 2569 2570 /* More sanity checks. */ 2571 if (t_row + rows_to_move > rows || 2572 t_col + chars_per_row > cols) 2573 return; 2574 2575 i_virtual_copy_tem_chars(tem->tvs_screen_buf, s_col, s_row, 2576 e_col, e_row, t_col, t_row); 2577 } 2578 2579 static void 2580 tem_safe_virtual_cls(struct tem_vt_state *tem, 2581 int count, screen_pos_t row, screen_pos_t col) 2582 { 2583 int i; 2584 text_attr_t attr; 2585 term_char_t c; 2586 2587 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2588 TEM_ATTR_SCREEN_REVERSE); 2589 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; 2590 2591 for (i = 0; i < tems.ts_c_dimension.width; i++) 2592 tems.ts_blank_line[i] = c; 2593 2594 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col); 2595 } 2596 2597 /* 2598 * only blank screen, not clear our screen buffer 2599 */ 2600 void 2601 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp, 2602 enum called_from called_from) 2603 { 2604 int row; 2605 2606 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2607 called_from == CALLED_FROM_STANDALONE); 2608 2609 if (tems.ts_display_mode == VIS_PIXEL) { 2610 tem_safe_pix_clear_entire_screen(tem, credp, called_from); 2611 return; 2612 } 2613 2614 for (row = 0; row < tems.ts_c_dimension.height; row++) { 2615 tem_safe_callback_cls(tem, 2616 tems.ts_c_dimension.width, 2617 row, 0, credp, called_from); 2618 } 2619 } 2620 2621 /* 2622 * unblank screen with associated tem from its screen buffer 2623 */ 2624 void 2625 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp, 2626 enum called_from called_from) 2627 { 2628 int row; 2629 2630 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) || 2631 called_from == CALLED_FROM_STANDALONE); 2632 2633 if (tems.ts_display_mode == VIS_PIXEL) 2634 tem_safe_pix_clear_entire_screen(tem, credp, called_from); 2635 2636 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from); 2637 2638 /* 2639 * Display data in tvs_screen_buf to the actual framebuffer in a 2640 * row by row way. 2641 * When dealing with one row, output data with the same foreground 2642 * and background color all together. 2643 */ 2644 for (row = 0; row < tems.ts_c_dimension.height; row++) { 2645 tem_safe_callback_display(tem, tem->tvs_screen_rows[row], 2646 tems.ts_c_dimension.width, row, 0, credp, called_from); 2647 } 2648 2649 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from); 2650 } 2651