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