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