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