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