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