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