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