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