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