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