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