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