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