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