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