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 * Copyright 2016 Joyent, Inc. 26 */ 27 28 /* 29 * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and 30 * the like. 31 * 32 * How Virtual Terminal Emulator Works: 33 * 34 * Every virtual terminal is associated with a tem_vt_state structure 35 * and maintains a virtual screen buffer in tvs_screen_buf, which contains 36 * all the characters which should be shown on the physical screen when 37 * the terminal is activated. 38 * 39 * Data written to a virtual terminal is composed of characters which 40 * should be displayed on the screen when this virtual terminal is 41 * activated, fg/bg colors of these characters, and other control 42 * information (escape sequence, etc). 43 * 44 * When data is passed to a virtual terminal it first is parsed for 45 * control information by tem_parse(). Subsequently the character 46 * and color data are written to tvs_screen_buf. 47 * They are saved in buffer in order to refresh the screen when this 48 * terminal is activated. If the terminal is currently active, the data 49 * (characters and colors) are also written to the physical screen by 50 * invoking a callback function, tem_text_callbacks() or tem_pix_callbacks(). 51 * 52 * When rendering data to the framebuffer, if the framebuffer is in 53 * VIS_PIXEL mode, the character data will first be converted to pixel 54 * data using tem_pix_bit2pix(), and then the pixels get displayed 55 * on the physical screen. We only store the character and color data in 56 * tem_vt_state since the bit2pix conversion only happens when actually 57 * rendering to the physical framebuffer. 58 */ 59 60 61 #include <stand.h> 62 #include <sys/ascii.h> 63 #include <sys/errno.h> 64 #include <sys/tem_impl.h> 65 #ifdef _HAVE_TEM_FIRMWARE 66 #include <sys/promif.h> 67 #endif /* _HAVE_TEM_FIRMWARE */ 68 #include <sys/consplat.h> 69 #include <sys/kd.h> 70 #include <stdbool.h> 71 72 /* Terminal emulator internal helper functions */ 73 static void tems_setup_terminal(struct vis_devinit *, size_t, size_t); 74 static void tems_modechange_callback(struct vis_modechg_arg *, 75 struct vis_devinit *); 76 77 static void tems_reset_colormap(void); 78 79 static void tem_free_buf(struct tem_vt_state *); 80 static void tem_internal_init(struct tem_vt_state *, boolean_t, boolean_t); 81 static void tems_get_initial_color(tem_color_t *pcolor); 82 83 static void tem_control(struct tem_vt_state *, uint8_t); 84 static void tem_setparam(struct tem_vt_state *, int, int); 85 static void tem_selgraph(struct tem_vt_state *); 86 static void tem_chkparam(struct tem_vt_state *, uint8_t); 87 static void tem_getparams(struct tem_vt_state *, uint8_t); 88 static void tem_outch(struct tem_vt_state *, tem_char_t); 89 static void tem_parse(struct tem_vt_state *, tem_char_t); 90 91 static void tem_new_line(struct tem_vt_state *); 92 static void tem_cr(struct tem_vt_state *); 93 static void tem_lf(struct tem_vt_state *); 94 static void tem_send_data(struct tem_vt_state *); 95 static void tem_cls(struct tem_vt_state *); 96 static void tem_tab(struct tem_vt_state *); 97 static void tem_back_tab(struct tem_vt_state *); 98 static void tem_clear_tabs(struct tem_vt_state *, int); 99 static void tem_set_tab(struct tem_vt_state *); 100 static void tem_mv_cursor(struct tem_vt_state *, int, int); 101 static void tem_shift(struct tem_vt_state *, int, int); 102 static void tem_scroll(struct tem_vt_state *, int, int, int, int); 103 static void tem_clear_chars(struct tem_vt_state *tem, 104 int count, screen_pos_t row, screen_pos_t col); 105 static void tem_copy_area(struct tem_vt_state *tem, 106 screen_pos_t s_col, screen_pos_t s_row, 107 screen_pos_t e_col, screen_pos_t e_row, 108 screen_pos_t t_col, screen_pos_t t_row); 109 static void tem_bell(struct tem_vt_state *tem); 110 static void tem_pix_clear_prom_output(struct tem_vt_state *tem); 111 112 static void tem_virtual_cls(struct tem_vt_state *, size_t, screen_pos_t, 113 screen_pos_t); 114 static void tem_virtual_display(struct tem_vt_state *, term_char_t *, 115 size_t, screen_pos_t, screen_pos_t); 116 static void tem_align_cursor(struct tem_vt_state *tem); 117 118 static void tem_check_first_time(struct tem_vt_state *tem); 119 static void tem_reset_display(struct tem_vt_state *, boolean_t, boolean_t); 120 static void tem_terminal_emulate(struct tem_vt_state *, uint8_t *, int); 121 static void tem_text_cursor(struct tem_vt_state *, short); 122 static void tem_text_cls(struct tem_vt_state *, 123 int count, screen_pos_t row, screen_pos_t col); 124 static void tem_pix_display(struct tem_vt_state *, term_char_t *, 125 int, screen_pos_t, screen_pos_t); 126 static void tem_pix_copy(struct tem_vt_state *, 127 screen_pos_t, screen_pos_t, 128 screen_pos_t, screen_pos_t, 129 screen_pos_t, screen_pos_t); 130 static void tem_pix_cursor(struct tem_vt_state *, short); 131 static void tem_get_attr(struct tem_vt_state *, text_color_t *, 132 text_color_t *, text_attr_t *, uint8_t); 133 static void tem_get_color(text_color_t *, text_color_t *, term_char_t); 134 static void tem_pix_align(struct tem_vt_state *); 135 static void tem_text_display(struct tem_vt_state *, term_char_t *, int, 136 screen_pos_t, screen_pos_t); 137 static void tem_text_copy(struct tem_vt_state *, 138 screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t, 139 screen_pos_t, screen_pos_t); 140 static void tem_pix_bit2pix(struct tem_vt_state *, term_char_t); 141 static void tem_pix_cls_range(struct tem_vt_state *, screen_pos_t, int, 142 int, screen_pos_t, int, int, boolean_t); 143 static void tem_pix_cls(struct tem_vt_state *, int, 144 screen_pos_t, screen_pos_t); 145 146 static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, 147 text_color_t fg_color, text_color_t bg_color); 148 149 /* 150 * Globals 151 */ 152 tem_state_t tems; /* common term info */ 153 154 tem_callbacks_t tem_text_callbacks = { 155 .tsc_display = &tem_text_display, 156 .tsc_copy = &tem_text_copy, 157 .tsc_cursor = &tem_text_cursor, 158 .tsc_bit2pix = NULL, 159 .tsc_cls = &tem_text_cls 160 }; 161 tem_callbacks_t tem_pix_callbacks = { 162 .tsc_display = &tem_pix_display, 163 .tsc_copy = &tem_pix_copy, 164 .tsc_cursor = &tem_pix_cursor, 165 .tsc_bit2pix = &tem_pix_bit2pix, 166 .tsc_cls = &tem_pix_cls 167 }; 168 169 #define tem_callback_display (*tems.ts_callbacks->tsc_display) 170 #define tem_callback_copy (*tems.ts_callbacks->tsc_copy) 171 #define tem_callback_cursor (*tems.ts_callbacks->tsc_cursor) 172 #define tem_callback_cls (*tems.ts_callbacks->tsc_cls) 173 #define tem_callback_bit2pix (*tems.ts_callbacks->tsc_bit2pix) 174 175 static void 176 tem_add(struct tem_vt_state *tem) 177 { 178 list_insert_head(&tems.ts_list, tem); 179 } 180 181 /* 182 * This is the main entry point to the module. It handles output requests 183 * during normal system operation, when (e.g.) mutexes are available. 184 */ 185 void 186 tem_write(tem_vt_state_t tem_arg, uint8_t *buf, ssize_t len) 187 { 188 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; 189 190 if (tems.ts_initialized == 0 || tem->tvs_initialized == 0) { 191 return; 192 } 193 194 tem_check_first_time(tem); 195 tem_terminal_emulate(tem, buf, len); 196 } 197 198 static void 199 tem_internal_init(struct tem_vt_state *ptem, 200 boolean_t init_color, boolean_t clear_screen) 201 { 202 size_t size, width, height; 203 204 if (tems.ts_display_mode == VIS_PIXEL) { 205 ptem->tvs_pix_data_size = tems.ts_pix_data_size; 206 ptem->tvs_pix_data = malloc(ptem->tvs_pix_data_size); 207 } 208 209 width = tems.ts_c_dimension.width; 210 height = tems.ts_c_dimension.height; 211 212 size = width * sizeof (tem_char_t); 213 ptem->tvs_outbuf = malloc(size); 214 if (ptem->tvs_outbuf == NULL) 215 panic("out of memory in tem_internal_init()\n"); 216 217 ptem->tvs_maxtab = width / 8; 218 ptem->tvs_tabs = calloc(ptem->tvs_maxtab, sizeof (*ptem->tvs_tabs)); 219 if (ptem->tvs_tabs == NULL) 220 panic("out of memory in tem_internal_init()\n"); 221 222 tem_reset_display(ptem, clear_screen, init_color); 223 224 ptem->tvs_utf8_left = 0; 225 ptem->tvs_utf8_partial = 0; 226 227 ptem->tvs_initialized = true; 228 229 /* 230 * Out of memory is not fatal there, without the screen history, 231 * we can not optimize the screen copy. 232 */ 233 size = width * height * sizeof (term_char_t); 234 ptem->tvs_screen_buf = malloc(size); 235 tem_virtual_cls(ptem, width * height, 0, 0); 236 } 237 238 int 239 tem_initialized(tem_vt_state_t tem_arg) 240 { 241 struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg; 242 243 return (ptem->tvs_initialized); 244 } 245 246 tem_vt_state_t 247 tem_init(void) 248 { 249 struct tem_vt_state *ptem; 250 251 ptem = calloc(1, sizeof (struct tem_vt_state)); 252 if (ptem == NULL) 253 return ((tem_vt_state_t)ptem); 254 255 ptem->tvs_isactive = false; 256 ptem->tvs_fbmode = KD_TEXT; 257 258 /* 259 * A tem is regarded as initialized only after tem_internal_init(), 260 * will be set at the end of tem_internal_init(). 261 */ 262 ptem->tvs_initialized = 0; 263 264 if (!tems.ts_initialized) { 265 /* 266 * Only happens during early console configuration. 267 */ 268 tem_add(ptem); 269 return ((tem_vt_state_t)ptem); 270 } 271 272 tem_internal_init(ptem, B_TRUE, B_FALSE); 273 tem_add(ptem); 274 275 return ((tem_vt_state_t)ptem); 276 } 277 278 /* 279 * re-init the tem after video mode has changed and tems_info has 280 * been re-inited. 281 */ 282 static void 283 tem_reinit(struct tem_vt_state *tem, boolean_t reset_display) 284 { 285 tem_free_buf(tem); /* only free virtual buffers */ 286 287 /* reserve color */ 288 tem_internal_init(tem, B_FALSE, reset_display); 289 } 290 291 static void 292 tem_free_buf(struct tem_vt_state *tem) 293 { 294 free(tem->tvs_outbuf); 295 tem->tvs_outbuf = NULL; 296 297 free(tem->tvs_pix_data); 298 tem->tvs_pix_data = NULL; 299 300 free(tem->tvs_screen_buf); 301 tem->tvs_screen_buf = NULL; 302 303 free(tem->tvs_tabs); 304 tem->tvs_tabs = NULL; 305 } 306 307 static int 308 tems_failed(boolean_t finish_ioctl) 309 { 310 if (finish_ioctl && tems.ts_hdl != NULL) 311 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_DEVFINI, NULL); 312 313 tems.ts_hdl = NULL; 314 return (ENXIO); 315 } 316 317 /* 318 * Only called once during boot 319 */ 320 int 321 tem_info_init(struct console *cp) 322 { 323 int ret; 324 struct vis_devinit temargs; 325 size_t height = 0; 326 size_t width = 0; 327 struct tem_vt_state *p; 328 329 if (tems.ts_initialized) { 330 return (0); 331 } 332 333 list_create(&tems.ts_list, sizeof (struct tem_vt_state), 334 __offsetof(struct tem_vt_state, tvs_list_node)); 335 tems.ts_active = NULL; 336 337 tems.ts_hdl = cp; 338 bzero(&temargs, sizeof (temargs)); 339 temargs.modechg_cb = (vis_modechg_cb_t)tems_modechange_callback; 340 temargs.modechg_arg = NULL; 341 342 /* 343 * Initialize the console and get the device parameters 344 */ 345 if (cp->c_ioctl(cp, VIS_DEVINIT, &temargs) != 0) { 346 printf("terminal emulator: Compatible fb not found\n"); 347 ret = tems_failed(B_FALSE); 348 return (ret); 349 } 350 351 /* Make sure the fb driver and terminal emulator versions match */ 352 if (temargs.version != VIS_CONS_REV) { 353 printf( 354 "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) " 355 "of console fb driver not supported\n", temargs.version); 356 ret = tems_failed(B_TRUE); 357 return (ret); 358 } 359 360 /* other sanity checks */ 361 if (!((temargs.depth == 4) || (temargs.depth == 8) || 362 (temargs.depth == 15) || (temargs.depth == 16) || 363 (temargs.depth == 24) || (temargs.depth == 32))) { 364 printf("terminal emulator: unsupported depth\n"); 365 ret = tems_failed(B_TRUE); 366 return (ret); 367 } 368 369 if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) { 370 printf("terminal emulator: unsupported mode\n"); 371 ret = tems_failed(B_TRUE); 372 return (ret); 373 } 374 375 plat_tem_get_prom_size(&height, &width); 376 377 /* 378 * Initialize the common terminal emulator info 379 */ 380 tems_setup_terminal(&temargs, height, width); 381 382 tems_reset_colormap(); 383 tems_get_initial_color(&tems.ts_init_color); 384 385 tems.ts_initialized = 1; /* initialization flag */ 386 387 for (p = list_head(&tems.ts_list); p != NULL; 388 p = list_next(&tems.ts_list, p)) { 389 tem_internal_init(p, B_TRUE, B_FALSE); 390 if (temargs.mode == VIS_PIXEL) 391 tem_pix_align(p); 392 } 393 394 return (0); 395 } 396 397 #define TEMS_DEPTH_DIFF 0x01 398 #define TEMS_DIMENSION_DIFF 0x02 399 400 static uint8_t 401 tems_check_videomode(struct vis_devinit *tp) 402 { 403 uint8_t result = 0; 404 405 if (tems.ts_pdepth != tp->depth) 406 result |= TEMS_DEPTH_DIFF; 407 408 if (tp->mode == VIS_TEXT) { 409 if (tems.ts_c_dimension.width != tp->width || 410 tems.ts_c_dimension.height != tp->height) 411 result |= TEMS_DIMENSION_DIFF; 412 } else { 413 if (tems.ts_p_dimension.width != tp->width || 414 tems.ts_p_dimension.height != tp->height) 415 result |= TEMS_DIMENSION_DIFF; 416 } 417 if (tems.update_font == true) 418 result |= TEMS_DIMENSION_DIFF; 419 420 return (result); 421 } 422 423 static int 424 env_screen_nounset(struct env_var *ev __unused) 425 { 426 if (tems.ts_p_dimension.width == 0 && 427 tems.ts_p_dimension.height == 0) 428 return (0); 429 return (EPERM); 430 } 431 432 static void 433 tems_setup_font(screen_size_t height, screen_size_t width) 434 { 435 bitmap_data_t *font_data; 436 437 /* 438 * set_font() will select an appropriate sized font for 439 * the number of rows and columns selected. If we don't 440 * have a font that will fit, then it will use the 441 * default builtin font and adjust the rows and columns 442 * to fit on the screen. 443 */ 444 font_data = set_font(&tems.ts_c_dimension.height, 445 &tems.ts_c_dimension.width, height, width); 446 447 if (font_data == NULL) 448 panic("out of memory"); 449 450 /* 451 * To use loaded font, we assign the loaded font data to tems.ts_font. 452 * In case of next load, the previously loaded data is freed 453 * when loading the new font. 454 */ 455 for (int i = 0; i < VFNT_MAPS; i++) { 456 tems.ts_font.vf_map[i] = 457 font_data->font->vf_map[i]; 458 tems.ts_font.vf_map_count[i] = 459 font_data->font->vf_map_count[i]; 460 } 461 462 tems.ts_font.vf_bytes = font_data->font->vf_bytes; 463 tems.ts_font.vf_width = font_data->font->vf_width; 464 tems.ts_font.vf_height = font_data->font->vf_height; 465 } 466 467 static void 468 tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width) 469 { 470 char env[8]; 471 472 tems.ts_pdepth = tp->depth; 473 tems.ts_linebytes = tp->linebytes; 474 tems.ts_display_mode = tp->mode; 475 tems.ts_color_map = tp->color_map; 476 477 switch (tp->mode) { 478 case VIS_TEXT: 479 /* Set fake pixel dimensions to assist set_font() */ 480 tems.ts_p_dimension.width = 0; 481 tems.ts_p_dimension.height = 0; 482 tems.ts_c_dimension.width = tp->width; 483 tems.ts_c_dimension.height = tp->height; 484 tems.ts_callbacks = &tem_text_callbacks; 485 486 tems_setup_font(16 * tp->height + BORDER_PIXELS, 487 8 * tp->width + BORDER_PIXELS); 488 489 /* ensure the following are not set for text mode */ 490 unsetenv("screen-height"); 491 unsetenv("screen-width"); 492 break; 493 494 case VIS_PIXEL: 495 /* 496 * First check to see if the user has specified a screen size. 497 * If so, use those values. Else use 34x80 as the default. 498 */ 499 if (width == 0) { 500 width = TEM_DEFAULT_COLS; 501 height = TEM_DEFAULT_ROWS; 502 } 503 tems.ts_c_dimension.height = (screen_size_t)height; 504 tems.ts_c_dimension.width = (screen_size_t)width; 505 tems.ts_p_dimension.height = tp->height; 506 tems.ts_p_dimension.width = tp->width; 507 tems.ts_callbacks = &tem_pix_callbacks; 508 509 tems_setup_font(tp->height, tp->width); 510 511 snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.height); 512 env_setenv("screen-height", EV_VOLATILE | EV_NOHOOK, env, 513 env_noset, env_screen_nounset); 514 snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.width); 515 env_setenv("screen-width", EV_VOLATILE | EV_NOHOOK, env, 516 env_noset, env_screen_nounset); 517 518 tems.ts_p_offset.y = (tems.ts_p_dimension.height - 519 (tems.ts_c_dimension.height * tems.ts_font.vf_height)) / 2; 520 tems.ts_p_offset.x = (tems.ts_p_dimension.width - 521 (tems.ts_c_dimension.width * tems.ts_font.vf_width)) / 2; 522 tems.ts_pix_data_size = 523 tems.ts_font.vf_width * tems.ts_font.vf_height; 524 tems.ts_pix_data_size *= 4; 525 tems.ts_pdepth = tp->depth; 526 527 break; 528 } 529 530 tems.update_font = false; 531 532 snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height); 533 env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env, 534 env_noset, env_nounset); 535 snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width); 536 env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env, 537 env_noset, env_nounset); 538 539 snprintf(env, sizeof (env), "%dx%d", tems.ts_font.vf_width, 540 tems.ts_font.vf_height); 541 env_setenv("screen-font", EV_VOLATILE | EV_NOHOOK, env, NULL, 542 NULL); 543 } 544 545 /* 546 * This is a callback function that we register with the frame 547 * buffer driver layered underneath. It gets invoked from 548 * the underlying frame buffer driver to reconfigure the terminal 549 * emulator to a new screen size and depth in conjunction with 550 * framebuffer videomode changes. 551 * Here we keep the foreground/background color and attributes, 552 * which may be different with the initial settings, so that 553 * the color won't change while the framebuffer videomode changes. 554 * And we also reset the kernel terminal emulator and clear the 555 * whole screen. 556 */ 557 /* ARGSUSED */ 558 void 559 tems_modechange_callback(struct vis_modechg_arg *arg __unused, 560 struct vis_devinit *devinit) 561 { 562 uint8_t diff; 563 struct tem_vt_state *p; 564 tem_modechg_cb_t cb; 565 tem_modechg_cb_arg_t cb_arg; 566 size_t height = 0; 567 size_t width = 0; 568 int state; 569 570 diff = tems_check_videomode(devinit); 571 if (diff == 0) { 572 /* 573 * This is color related change, reset color and redraw the 574 * screen. Only need to reinit the active tem. 575 */ 576 struct tem_vt_state *active = tems.ts_active; 577 tems_get_initial_color(&tems.ts_init_color); 578 active->tvs_fg_color = tems.ts_init_color.fg_color; 579 active->tvs_bg_color = tems.ts_init_color.bg_color; 580 active->tvs_flags = tems.ts_init_color.a_flags; 581 tem_reinit(active, B_TRUE); 582 return; 583 } 584 585 diff = diff & TEMS_DIMENSION_DIFF; 586 587 if (diff == 0) { 588 /* 589 * Only need to reinit the active tem. 590 */ 591 struct tem_vt_state *active = tems.ts_active; 592 tems.ts_pdepth = devinit->depth; 593 /* color depth did change, reset colors */ 594 tems_reset_colormap(); 595 tems_get_initial_color(&tems.ts_init_color); 596 tem_reinit(active, B_TRUE); 597 598 return; 599 } 600 601 plat_tem_get_prom_size(&height, &width); 602 603 state = tems.ts_initialized; 604 tems.ts_initialized = 0; /* stop all output */ 605 tems_setup_terminal(devinit, height, width); 606 607 tems_reset_colormap(); 608 tems_get_initial_color(&tems.ts_init_color); 609 tems.ts_initialized = state; /* restore state */ 610 611 for (p = list_head(&tems.ts_list); p != NULL; 612 p = list_next(&tems.ts_list, p)) { 613 tem_reinit(p, p->tvs_isactive); 614 } 615 616 617 if (tems.ts_modechg_cb == NULL) { 618 return; 619 } 620 621 cb = tems.ts_modechg_cb; 622 cb_arg = tems.ts_modechg_arg; 623 624 cb(cb_arg); 625 } 626 627 /* 628 * This function is used to clear entire screen via the underlying framebuffer 629 * driver. 630 */ 631 int 632 tems_cls(struct vis_consclear *pda) 633 { 634 if (tems.ts_hdl == NULL) 635 return (1); 636 return (tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCLEAR, pda)); 637 } 638 639 /* 640 * This function is used to display a rectangular blit of data 641 * of a given size and location via the underlying framebuffer driver. 642 * The blit can be as small as a pixel or as large as the screen. 643 */ 644 void 645 tems_display(struct vis_consdisplay *pda) 646 { 647 if (tems.ts_hdl != NULL) 648 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSDISPLAY, pda); 649 } 650 651 /* 652 * This function is used to invoke a block copy operation in the 653 * underlying framebuffer driver. Rectangle copies are how scrolling 654 * is implemented, as well as horizontal text shifting escape seqs. 655 * such as from vi when deleting characters and words. 656 */ 657 void 658 tems_copy(struct vis_conscopy *pma) 659 { 660 if (tems.ts_hdl != NULL) 661 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCOPY, pma); 662 } 663 664 /* 665 * This function is used to show or hide a rectangluar monochrom 666 * pixel inverting, text block cursor via the underlying framebuffer. 667 */ 668 void 669 tems_cursor(struct vis_conscursor *pca) 670 { 671 if (tems.ts_hdl != NULL) 672 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCURSOR, pca); 673 } 674 675 static void 676 tem_kdsetmode(int mode) 677 { 678 if (tems.ts_hdl != NULL) { 679 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE, 680 (void *)(intptr_t)mode); 681 } 682 } 683 684 static void 685 tems_reset_colormap(void) 686 { 687 struct vis_cmap cm; 688 689 switch (tems.ts_pdepth) { 690 case 8: 691 cm.index = 0; 692 cm.count = 16; 693 /* 8-bits (1/3 of TrueColor 24) */ 694 cm.red = (uint8_t *)cmap4_to_24.red; 695 /* 8-bits (1/3 of TrueColor 24) */ 696 cm.blue = (uint8_t *)cmap4_to_24.blue; 697 /* 8-bits (1/3 of TrueColor 24) */ 698 cm.green = (uint8_t *)cmap4_to_24.green; 699 if (tems.ts_hdl != NULL) 700 (void) tems.ts_hdl->c_ioctl(tems.ts_hdl, 701 VIS_PUTCMAP, &cm); 702 break; 703 } 704 } 705 706 void 707 tem_get_size(uint16_t *r, uint16_t *c, uint16_t *x, uint16_t *y) 708 { 709 *r = (uint16_t)tems.ts_c_dimension.height; 710 *c = (uint16_t)tems.ts_c_dimension.width; 711 *x = (uint16_t)tems.ts_p_dimension.width; 712 *y = (uint16_t)tems.ts_p_dimension.height; 713 } 714 715 /* 716 * Loader extension. Store important data in environment. Intended to be used 717 * just before booting the OS to make the data available in kernel 718 * environment module. 719 */ 720 void 721 tem_save_state(void) 722 { 723 struct tem_vt_state *active = tems.ts_active; 724 char buf[80]; 725 726 /* 727 * We already have in environment: 728 * tem.inverse, tem.inverse_screen 729 * tem.fg_color, tem.bg_color. 730 * So we only need to add the position of the cursor. 731 */ 732 733 if (active != NULL) { 734 snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.col); 735 setenv("tem.cursor.col", buf, 1); 736 snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.row); 737 setenv("tem.cursor.row", buf, 1); 738 } 739 } 740 741 void 742 tem_register_modechg_cb(tem_modechg_cb_t func, tem_modechg_cb_arg_t arg) 743 { 744 tems.ts_modechg_cb = func; 745 tems.ts_modechg_arg = arg; 746 } 747 748 /* 749 * This function is to scroll up the OBP output, which has 750 * different screen height and width with our kernel console. 751 */ 752 static void 753 tem_prom_scroll_up(struct tem_vt_state *tem, int nrows) 754 { 755 struct vis_conscopy ma; 756 int ncols, width; 757 758 /* copy */ 759 ma.s_row = nrows * tems.ts_font.vf_height; 760 ma.e_row = tems.ts_p_dimension.height - 1; 761 ma.t_row = 0; 762 763 ma.s_col = 0; 764 ma.e_col = tems.ts_p_dimension.width - 1; 765 ma.t_col = 0; 766 767 tems_copy(&ma); 768 769 /* clear */ 770 width = tems.ts_font.vf_width; 771 ncols = (tems.ts_p_dimension.width + (width - 1)) / width; 772 773 tem_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, 774 0, ncols, 0, B_TRUE); 775 } 776 777 /* 778 * This function is to compute the starting row of the console, according to 779 * PROM cursor's position. Here we have to take different fonts into account. 780 */ 781 static int 782 tem_adjust_row(struct tem_vt_state *tem, int prom_row) 783 { 784 int tem_row; 785 int tem_y; 786 int prom_charheight = 0; 787 int prom_window_top = 0; 788 int scroll_up_lines; 789 790 plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top); 791 if (prom_charheight == 0) 792 prom_charheight = tems.ts_font.vf_height; 793 794 tem_y = (prom_row + 1) * prom_charheight + prom_window_top - 795 tems.ts_p_offset.y; 796 tem_row = (tem_y + tems.ts_font.vf_height - 1) / 797 tems.ts_font.vf_height - 1; 798 799 if (tem_row < 0) { 800 tem_row = 0; 801 } else if (tem_row >= (tems.ts_c_dimension.height - 1)) { 802 /* 803 * Scroll up the prom outputs if the PROM cursor's position is 804 * below our tem's lower boundary. 805 */ 806 scroll_up_lines = tem_row - 807 (tems.ts_c_dimension.height - 1); 808 tem_prom_scroll_up(tem, scroll_up_lines); 809 tem_row = tems.ts_c_dimension.height - 1; 810 } 811 812 return (tem_row); 813 } 814 815 static void 816 tem_pix_align(struct tem_vt_state *tem) 817 { 818 uint32_t row = 0; 819 uint32_t col = 0; 820 821 if (plat_stdout_is_framebuffer()) { 822 plat_tem_hide_prom_cursor(); 823 824 /* 825 * We are getting the current cursor position in pixel 826 * mode so that we don't over-write the console output 827 * during boot. 828 */ 829 plat_tem_get_prom_pos(&row, &col); 830 831 /* 832 * Adjust the row if necessary when the font of our 833 * kernel console tem is different with that of prom 834 * tem. 835 */ 836 row = tem_adjust_row(tem, row); 837 838 /* first line of our kernel console output */ 839 tem->tvs_first_line = row + 1; 840 841 /* re-set and align cursor position */ 842 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row = 843 (screen_pos_t)row; 844 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0; 845 } else { 846 tem_reset_display(tem, B_TRUE, B_TRUE); 847 } 848 } 849 850 static void 851 tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen) 852 { 853 int i_inverse = 0; 854 int i_inverse_screen = 0; 855 856 plat_tem_get_inverses(&i_inverse, &i_inverse_screen); 857 858 *p_inverse = (i_inverse == 0) ? B_FALSE : B_TRUE; 859 *p_inverse_screen = (i_inverse_screen == 0) ? B_FALSE : B_TRUE; 860 } 861 862 /* 863 * Get the foreground/background color and attributes from environment. 864 */ 865 static void 866 tems_get_initial_color(tem_color_t *pcolor) 867 { 868 boolean_t inverse, inverse_screen; 869 unsigned short flags = 0; 870 871 pcolor->fg_color = DEFAULT_ANSI_FOREGROUND; 872 pcolor->bg_color = DEFAULT_ANSI_BACKGROUND; 873 plat_tem_get_colors(&pcolor->fg_color, &pcolor->bg_color); 874 875 tems_get_inverses(&inverse, &inverse_screen); 876 if (inverse) 877 flags |= TEM_ATTR_REVERSE; 878 if (inverse_screen) 879 flags |= TEM_ATTR_SCREEN_REVERSE; 880 881 if (flags != 0) { 882 /* 883 * The reverse attribute is set. 884 * In case of black on white we want bright white for BG. 885 */ 886 if (pcolor->fg_color == ANSI_COLOR_WHITE) 887 flags |= TEM_ATTR_BRIGHT_BG; 888 889 /* 890 * For white on black, unset the bright attribute we 891 * had set to have bright white background. 892 */ 893 if (pcolor->fg_color == ANSI_COLOR_BLACK) 894 flags &= ~TEM_ATTR_BRIGHT_BG; 895 } else { 896 /* 897 * In case of black on white we want bright white for BG. 898 */ 899 if (pcolor->bg_color == ANSI_COLOR_WHITE) 900 flags |= TEM_ATTR_BRIGHT_BG; 901 } 902 903 pcolor->a_flags = flags; 904 } 905 906 void 907 tem_activate(tem_vt_state_t tem_arg, boolean_t unblank) 908 { 909 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; 910 911 tems.ts_active = tem; 912 tem->tvs_isactive = true; 913 914 tem_kdsetmode(tem->tvs_fbmode); 915 916 if (unblank) 917 tem_cls(tem); 918 } 919 920 static void 921 tem_check_first_time(struct tem_vt_state *tem) 922 { 923 static int first_time = 1; 924 925 /* 926 * Realign the console cursor. We did this in tem_init(). 927 * However, drivers in the console stream may emit additional 928 * messages before we are ready. This causes text overwrite 929 * on the screen. This is a workaround. 930 */ 931 if (!first_time) 932 return; 933 934 first_time = 0; 935 if (tems.ts_display_mode == VIS_TEXT) 936 tem_text_cursor(tem, VIS_GET_CURSOR); 937 else 938 tem_pix_cursor(tem, VIS_GET_CURSOR); 939 tem_align_cursor(tem); 940 } 941 942 /* Process partial UTF-8 sequence. */ 943 static void 944 tem_input_partial(struct tem_vt_state *tem) 945 { 946 unsigned i; 947 tem_char_t c; 948 949 if (tem->tvs_utf8_left == 0) 950 return; 951 952 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) { 953 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff; 954 if (c != 0) { 955 tem_parse(tem, c); 956 } 957 } 958 tem->tvs_utf8_left = 0; 959 tem->tvs_utf8_partial = 0; 960 } 961 962 /* 963 * Handle UTF-8 sequences. 964 */ 965 static void 966 tem_input_byte(struct tem_vt_state *tem, uint8_t c) 967 { 968 /* 969 * Check for UTF-8 code points. In case of error fall back to 970 * 8-bit code. As we only have 8859-1 fonts for console, this will set 971 * the limits on what chars we actually can display, therefore we 972 * have to return to this code once we have solved the font issue. 973 */ 974 if ((c & 0x80) == 0x00) { 975 /* One-byte sequence. */ 976 tem_input_partial(tem); 977 tem_parse(tem, c); 978 return; 979 } 980 if ((c & 0xe0) == 0xc0) { 981 /* Two-byte sequence. */ 982 tem_input_partial(tem); 983 tem->tvs_utf8_left = 1; 984 tem->tvs_utf8_partial = c; 985 return; 986 } 987 if ((c & 0xf0) == 0xe0) { 988 /* Three-byte sequence. */ 989 tem_input_partial(tem); 990 tem->tvs_utf8_left = 2; 991 tem->tvs_utf8_partial = c; 992 return; 993 } 994 if ((c & 0xf8) == 0xf0) { 995 /* Four-byte sequence. */ 996 tem_input_partial(tem); 997 tem->tvs_utf8_left = 3; 998 tem->tvs_utf8_partial = c; 999 return; 1000 } 1001 if ((c & 0xc0) == 0x80) { 1002 /* Invalid state? */ 1003 if (tem->tvs_utf8_left == 0) { 1004 tem_parse(tem, c); 1005 return; 1006 } 1007 tem->tvs_utf8_left--; 1008 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c; 1009 if (tem->tvs_utf8_left == 0) { 1010 tem_char_t v, u; 1011 uint8_t b; 1012 1013 /* 1014 * Transform the sequence of 2 to 4 bytes to 1015 * unicode number. 1016 */ 1017 v = 0; 1018 u = tem->tvs_utf8_partial; 1019 b = (u >> 24) & 0xff; 1020 if (b != 0) { /* Four-byte sequence */ 1021 v = b & 0x07; 1022 b = (u >> 16) & 0xff; 1023 v = (v << 6) | (b & 0x3f); 1024 b = (u >> 8) & 0xff; 1025 v = (v << 6) | (b & 0x3f); 1026 b = u & 0xff; 1027 v = (v << 6) | (b & 0x3f); 1028 } else if ((b = (u >> 16) & 0xff) != 0) { 1029 v = b & 0x0f; /* Three-byte sequence */ 1030 b = (u >> 8) & 0xff; 1031 v = (v << 6) | (b & 0x3f); 1032 b = u & 0xff; 1033 v = (v << 6) | (b & 0x3f); 1034 } else if ((b = (u >> 8) & 0xff) != 0) { 1035 v = b & 0x1f; /* Two-byte sequence */ 1036 b = u & 0xff; 1037 v = (v << 6) | (b & 0x3f); 1038 } 1039 1040 tem_parse(tem, v); 1041 tem->tvs_utf8_partial = 0; 1042 } 1043 return; 1044 } 1045 /* Anything left is illegal in UTF-8 sequence. */ 1046 tem_input_partial(tem); 1047 tem_parse(tem, c); 1048 } 1049 1050 /* 1051 * This is the main entry point into the terminal emulator. 1052 * 1053 * For each data message coming downstream, ANSI assumes that it is composed 1054 * of ASCII characters, which are treated as a byte-stream input to the 1055 * parsing state machine. All data is parsed immediately -- there is 1056 * no enqueing. 1057 */ 1058 static void 1059 tem_terminal_emulate(struct tem_vt_state *tem, uint8_t *buf, int len) 1060 { 1061 if (tem->tvs_isactive) 1062 tem_callback_cursor(tem, VIS_HIDE_CURSOR); 1063 1064 for (; len > 0; len--, buf++) 1065 tem_input_byte(tem, *buf); 1066 1067 /* 1068 * Send the data we just got to the framebuffer. 1069 */ 1070 tem_send_data(tem); 1071 1072 if (tem->tvs_isactive) 1073 tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); 1074 } 1075 1076 /* 1077 * send the appropriate control message or set state based on the 1078 * value of the control character ch 1079 */ 1080 1081 static void 1082 tem_control(struct tem_vt_state *tem, uint8_t ch) 1083 { 1084 tem->tvs_state = A_STATE_START; 1085 switch (ch) { 1086 case A_BEL: 1087 tem_bell(tem); 1088 break; 1089 1090 case A_BS: 1091 tem_mv_cursor(tem, 1092 tem->tvs_c_cursor.row, 1093 tem->tvs_c_cursor.col - 1); 1094 break; 1095 1096 case A_HT: 1097 tem_tab(tem); 1098 break; 1099 1100 case A_NL: 1101 /* 1102 * tem_send_data(tem, credp, called_from); 1103 * tem_new_line(tem, credp, called_from); 1104 * break; 1105 */ 1106 1107 case A_VT: 1108 tem_send_data(tem); 1109 tem_lf(tem); 1110 break; 1111 1112 case A_FF: 1113 tem_send_data(tem); 1114 tem_cls(tem); 1115 break; 1116 1117 case A_CR: 1118 tem_send_data(tem); 1119 tem_cr(tem); 1120 break; 1121 1122 case A_ESC: 1123 tem->tvs_state = A_STATE_ESC; 1124 break; 1125 1126 case A_CSI: 1127 tem->tvs_curparam = 0; 1128 tem->tvs_paramval = 0; 1129 tem->tvs_gotparam = B_FALSE; 1130 /* clear the parameters */ 1131 for (int i = 0; i < TEM_MAXPARAMS; i++) 1132 tem->tvs_params[i] = -1; 1133 tem->tvs_state = A_STATE_CSI; 1134 break; 1135 1136 case A_GS: 1137 tem_back_tab(tem); 1138 break; 1139 1140 default: 1141 break; 1142 } 1143 } 1144 1145 1146 /* 1147 * if parameters [0..count - 1] are not set, set them to the value 1148 * of newparam. 1149 */ 1150 1151 static void 1152 tem_setparam(struct tem_vt_state *tem, int count, int newparam) 1153 { 1154 int i; 1155 1156 for (i = 0; i < count; i++) { 1157 if (tem->tvs_params[i] == -1) 1158 tem->tvs_params[i] = newparam; 1159 } 1160 } 1161 1162 /* 1163 * For colors 0-15 the tem is using color code translation 1164 * from sun colors to vga (dim_xlate and brt_xlate tables, see tem_get_color). 1165 * Colors 16-255 are used without translation. 1166 */ 1167 static void 1168 tem_select_color(struct tem_vt_state *tem, text_color_t color, bool fg) 1169 { 1170 if (fg == true) 1171 tem->tvs_fg_color = color; 1172 else 1173 tem->tvs_bg_color = color; 1174 1175 /* 1176 * For colors 0-7, make sure the BRIGHT attribute is not set. 1177 */ 1178 if (color < 8) { 1179 if (fg == true) 1180 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 1181 else 1182 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 1183 return; 1184 } 1185 1186 /* 1187 * For colors 8-15, we use color codes 0-7 and set BRIGHT attribute. 1188 */ 1189 if (color < 16) { 1190 if (fg == true) { 1191 tem->tvs_fg_color -= 8; 1192 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 1193 } else { 1194 tem->tvs_bg_color -= 8; 1195 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 1196 } 1197 } 1198 } 1199 1200 /* 1201 * select graphics mode based on the param vals stored in a_params 1202 */ 1203 static void 1204 tem_selgraph(struct tem_vt_state *tem) 1205 { 1206 int curparam; 1207 int count = 0; 1208 int param; 1209 1210 tem->tvs_state = A_STATE_START; 1211 1212 curparam = tem->tvs_curparam; 1213 do { 1214 param = tem->tvs_params[count]; 1215 1216 switch (param) { 1217 case -1: 1218 case 0: 1219 /* reset to initial normal settings */ 1220 tem->tvs_fg_color = tems.ts_init_color.fg_color; 1221 tem->tvs_bg_color = tems.ts_init_color.bg_color; 1222 tem->tvs_flags = tems.ts_init_color.a_flags; 1223 break; 1224 1225 case 1: /* Bold Intense */ 1226 tem->tvs_flags |= TEM_ATTR_BOLD; 1227 break; 1228 1229 case 2: /* Faint Intense */ 1230 tem->tvs_flags &= ~TEM_ATTR_BOLD; 1231 break; 1232 1233 case 4: /* Underline */ 1234 tem->tvs_flags |= TEM_ATTR_UNDERLINE; 1235 break; 1236 1237 case 5: /* Blink */ 1238 tem->tvs_flags |= TEM_ATTR_BLINK; 1239 break; 1240 1241 case 7: /* Reverse video */ 1242 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 1243 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1244 } else { 1245 tem->tvs_flags |= TEM_ATTR_REVERSE; 1246 } 1247 break; 1248 1249 case 22: /* Remove Bold */ 1250 tem->tvs_flags &= ~TEM_ATTR_BOLD; 1251 break; 1252 1253 case 24: /* Remove Underline */ 1254 tem->tvs_flags &= ~TEM_ATTR_UNDERLINE; 1255 break; 1256 1257 case 25: /* Remove Blink */ 1258 tem->tvs_flags &= ~TEM_ATTR_BLINK; 1259 break; 1260 1261 case 27: /* Remove Reverse */ 1262 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 1263 tem->tvs_flags |= TEM_ATTR_REVERSE; 1264 } else { 1265 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1266 } 1267 break; 1268 1269 case 30: /* black (grey) foreground */ 1270 case 31: /* red (light red) foreground */ 1271 case 32: /* green (light green) foreground */ 1272 case 33: /* brown (yellow) foreground */ 1273 case 34: /* blue (light blue) foreground */ 1274 case 35: /* magenta (light magenta) foreground */ 1275 case 36: /* cyan (light cyan) foreground */ 1276 case 37: /* white (bright white) foreground */ 1277 tem->tvs_fg_color = param - 30; 1278 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 1279 break; 1280 1281 case 38: 1282 /* We should have at least 3 parameters */ 1283 if (curparam < 3) 1284 break; 1285 1286 /* 1287 * 256 and truecolor needs depth at least 24, but 1288 * we still need to process the sequence. 1289 */ 1290 count++; 1291 curparam--; 1292 param = tem->tvs_params[count]; 1293 switch (param) { 1294 case 5: /* 256 colors */ 1295 count++; 1296 curparam--; 1297 tem_select_color(tem, tem->tvs_params[count], 1298 true); 1299 break; 1300 default: 1301 break; 1302 } 1303 break; 1304 1305 case 39: 1306 /* 1307 * Reset the foreground colour and brightness. 1308 */ 1309 tem->tvs_fg_color = tems.ts_init_color.fg_color; 1310 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG) 1311 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 1312 else 1313 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG; 1314 break; 1315 1316 case 40: /* black (grey) background */ 1317 case 41: /* red (light red) background */ 1318 case 42: /* green (light green) background */ 1319 case 43: /* brown (yellow) background */ 1320 case 44: /* blue (light blue) background */ 1321 case 45: /* magenta (light magenta) background */ 1322 case 46: /* cyan (light cyan) background */ 1323 case 47: /* white (bright white) background */ 1324 tem->tvs_bg_color = param - 40; 1325 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 1326 break; 1327 1328 case 48: 1329 /* We should have at least 3 parameters */ 1330 if (curparam < 3) 1331 break; 1332 1333 /* 1334 * 256 and truecolor needs depth at least 24, but 1335 * we still need to process the sequence. 1336 */ 1337 count++; 1338 curparam--; 1339 param = tem->tvs_params[count]; 1340 switch (param) { 1341 case 5: /* 256 colors */ 1342 count++; 1343 curparam--; 1344 tem_select_color(tem, tem->tvs_params[count], 1345 false); 1346 break; 1347 default: 1348 break; 1349 } 1350 break; 1351 1352 case 49: 1353 /* 1354 * Reset the background colour and brightness. 1355 */ 1356 tem->tvs_bg_color = tems.ts_init_color.bg_color; 1357 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG) 1358 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 1359 else 1360 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG; 1361 break; 1362 1363 case 90: /* black (grey) foreground */ 1364 case 91: /* red (light red) foreground */ 1365 case 92: /* green (light green) foreground */ 1366 case 93: /* brown (yellow) foreground */ 1367 case 94: /* blue (light blue) foreground */ 1368 case 95: /* magenta (light magenta) foreground */ 1369 case 96: /* cyan (light cyan) foreground */ 1370 case 97: /* white (bright white) foreground */ 1371 tem->tvs_fg_color = param - 90; 1372 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG; 1373 break; 1374 1375 case 100: /* black (grey) background */ 1376 case 101: /* red (light red) background */ 1377 case 102: /* green (light green) background */ 1378 case 103: /* brown (yellow) background */ 1379 case 104: /* blue (light blue) background */ 1380 case 105: /* magenta (light magenta) background */ 1381 case 106: /* cyan (light cyan) background */ 1382 case 107: /* white (bright white) background */ 1383 tem->tvs_bg_color = param - 100; 1384 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG; 1385 break; 1386 1387 default: 1388 break; 1389 } 1390 count++; 1391 curparam--; 1392 1393 } while (curparam > 0); 1394 } 1395 1396 /* 1397 * perform the appropriate action for the escape sequence 1398 * 1399 * General rule: This code does not validate the arguments passed. 1400 * It assumes that the next lower level will do so. 1401 */ 1402 static void 1403 tem_chkparam(struct tem_vt_state *tem, uint8_t ch) 1404 { 1405 int i; 1406 int row; 1407 int col; 1408 1409 row = tem->tvs_c_cursor.row; 1410 col = tem->tvs_c_cursor.col; 1411 1412 switch (ch) { 1413 1414 case 'm': /* select terminal graphics mode */ 1415 tem_send_data(tem); 1416 tem_selgraph(tem); 1417 break; 1418 1419 case '@': /* insert char */ 1420 tem_setparam(tem, 1, 1); 1421 tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT); 1422 break; 1423 1424 case 'A': /* cursor up */ 1425 tem_setparam(tem, 1, 1); 1426 tem_mv_cursor(tem, row - tem->tvs_params[0], col); 1427 break; 1428 1429 case 'd': /* VPA - vertical position absolute */ 1430 tem_setparam(tem, 1, 1); 1431 tem_mv_cursor(tem, tem->tvs_params[0] - 1, col); 1432 break; 1433 1434 case 'e': /* VPR - vertical position relative */ 1435 case 'B': /* cursor down */ 1436 tem_setparam(tem, 1, 1); 1437 tem_mv_cursor(tem, row + tem->tvs_params[0], col); 1438 break; 1439 1440 case 'a': /* HPR - horizontal position relative */ 1441 case 'C': /* cursor right */ 1442 tem_setparam(tem, 1, 1); 1443 tem_mv_cursor(tem, row, col + tem->tvs_params[0]); 1444 break; 1445 1446 case '`': /* HPA - horizontal position absolute */ 1447 tem_setparam(tem, 1, 1); 1448 tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); 1449 break; 1450 1451 case 'D': /* cursor left */ 1452 tem_setparam(tem, 1, 1); 1453 tem_mv_cursor(tem, row, col - tem->tvs_params[0]); 1454 break; 1455 1456 case 'E': /* CNL cursor next line */ 1457 tem_setparam(tem, 1, 1); 1458 tem_mv_cursor(tem, row + tem->tvs_params[0], 0); 1459 break; 1460 1461 case 'F': /* CPL cursor previous line */ 1462 tem_setparam(tem, 1, 1); 1463 tem_mv_cursor(tem, row - tem->tvs_params[0], 0); 1464 break; 1465 1466 case 'G': /* cursor horizontal position */ 1467 tem_setparam(tem, 1, 1); 1468 tem_mv_cursor(tem, row, tem->tvs_params[0] - 1); 1469 break; 1470 1471 case 'g': /* clear tabs */ 1472 tem_setparam(tem, 1, 0); 1473 tem_clear_tabs(tem, tem->tvs_params[0]); 1474 break; 1475 1476 case 'f': /* HVP Horizontal and Vertical Position */ 1477 case 'H': /* CUP position cursor */ 1478 tem_setparam(tem, 2, 1); 1479 tem_mv_cursor(tem, 1480 tem->tvs_params[0] - 1, tem->tvs_params[1] - 1); 1481 break; 1482 1483 case 'I': /* CHT - Cursor Horizontal Tab */ 1484 /* Not implemented */ 1485 break; 1486 1487 case 'J': /* ED - Erase in Display */ 1488 tem_send_data(tem); 1489 tem_setparam(tem, 1, 0); 1490 switch (tem->tvs_params[0]) { 1491 case 0: 1492 /* erase cursor to end of screen */ 1493 /* FIRST erase cursor to end of line */ 1494 tem_clear_chars(tem, 1495 tems.ts_c_dimension.width - 1496 tem->tvs_c_cursor.col, 1497 tem->tvs_c_cursor.row, 1498 tem->tvs_c_cursor.col); 1499 1500 /* THEN erase lines below the cursor */ 1501 for (row = tem->tvs_c_cursor.row + 1; 1502 row < tems.ts_c_dimension.height; 1503 row++) { 1504 tem_clear_chars(tem, 1505 tems.ts_c_dimension.width, row, 0); 1506 } 1507 break; 1508 1509 case 1: 1510 /* erase beginning of screen to cursor */ 1511 /* FIRST erase lines above the cursor */ 1512 for (row = 0; 1513 row < tem->tvs_c_cursor.row; 1514 row++) { 1515 tem_clear_chars(tem, 1516 tems.ts_c_dimension.width, row, 0); 1517 } 1518 /* THEN erase beginning of line to cursor */ 1519 tem_clear_chars(tem, 1520 tem->tvs_c_cursor.col + 1, 1521 tem->tvs_c_cursor.row, 0); 1522 break; 1523 1524 case 2: 1525 /* erase whole screen */ 1526 for (row = 0; 1527 row < tems.ts_c_dimension.height; 1528 row++) { 1529 tem_clear_chars(tem, 1530 tems.ts_c_dimension.width, row, 0); 1531 } 1532 break; 1533 } 1534 break; 1535 1536 case 'K': /* EL - Erase in Line */ 1537 tem_send_data(tem); 1538 tem_setparam(tem, 1, 0); 1539 switch (tem->tvs_params[0]) { 1540 case 0: 1541 /* erase cursor to end of line */ 1542 tem_clear_chars(tem, 1543 (tems.ts_c_dimension.width - 1544 tem->tvs_c_cursor.col), 1545 tem->tvs_c_cursor.row, 1546 tem->tvs_c_cursor.col); 1547 break; 1548 1549 case 1: 1550 /* erase beginning of line to cursor */ 1551 tem_clear_chars(tem, 1552 tem->tvs_c_cursor.col + 1, 1553 tem->tvs_c_cursor.row, 0); 1554 break; 1555 1556 case 2: 1557 /* erase whole line */ 1558 tem_clear_chars(tem, 1559 tems.ts_c_dimension.width, 1560 tem->tvs_c_cursor.row, 0); 1561 break; 1562 } 1563 break; 1564 1565 case 'L': /* insert line */ 1566 tem_send_data(tem); 1567 tem_setparam(tem, 1, 1); 1568 tem_scroll(tem, 1569 tem->tvs_c_cursor.row, 1570 tems.ts_c_dimension.height - 1, 1571 tem->tvs_params[0], TEM_SCROLL_DOWN); 1572 break; 1573 1574 case 'M': /* delete line */ 1575 tem_send_data(tem); 1576 tem_setparam(tem, 1, 1); 1577 tem_scroll(tem, 1578 tem->tvs_c_cursor.row, 1579 tems.ts_c_dimension.height - 1, 1580 tem->tvs_params[0], TEM_SCROLL_UP); 1581 break; 1582 1583 case 'P': /* DCH - delete char */ 1584 tem_setparam(tem, 1, 1); 1585 tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT); 1586 break; 1587 1588 case 'S': /* scroll up */ 1589 tem_send_data(tem); 1590 tem_setparam(tem, 1, 1); 1591 tem_scroll(tem, 0, 1592 tems.ts_c_dimension.height - 1, 1593 tem->tvs_params[0], TEM_SCROLL_UP); 1594 break; 1595 1596 case 'T': /* scroll down */ 1597 tem_send_data(tem); 1598 tem_setparam(tem, 1, 1); 1599 tem_scroll(tem, 0, 1600 tems.ts_c_dimension.height - 1, 1601 tem->tvs_params[0], TEM_SCROLL_DOWN); 1602 break; 1603 1604 case 'X': /* erase char */ 1605 tem_setparam(tem, 1, 1); 1606 tem_clear_chars(tem, 1607 tem->tvs_params[0], 1608 tem->tvs_c_cursor.row, 1609 tem->tvs_c_cursor.col); 1610 break; 1611 1612 case 'Z': /* cursor backward tabulation */ 1613 tem_setparam(tem, 1, 1); 1614 1615 /* 1616 * Rule exception - We do sanity checking here. 1617 * 1618 * Restrict the count to a sane value to keep from 1619 * looping for a long time. There can't be more than one 1620 * tab stop per column, so use that as a limit. 1621 */ 1622 if (tem->tvs_params[0] > tems.ts_c_dimension.width) 1623 tem->tvs_params[0] = tems.ts_c_dimension.width; 1624 1625 for (i = 0; i < tem->tvs_params[0]; i++) 1626 tem_back_tab(tem); 1627 break; 1628 } 1629 tem->tvs_state = A_STATE_START; 1630 } 1631 1632 1633 /* 1634 * Gather the parameters of an ANSI escape sequence 1635 */ 1636 static void 1637 tem_getparams(struct tem_vt_state *tem, uint8_t ch) 1638 { 1639 if (isdigit(ch)) { 1640 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0')); 1641 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */ 1642 return; /* Return immediately */ 1643 } else if (tem->tvs_state == A_STATE_CSI_EQUAL || 1644 tem->tvs_state == A_STATE_CSI_QMARK) { 1645 tem->tvs_state = A_STATE_START; 1646 } else { 1647 if (tem->tvs_curparam < TEM_MAXPARAMS) { 1648 if (tem->tvs_gotparam) { 1649 /* get the parameter value */ 1650 tem->tvs_params[tem->tvs_curparam] = 1651 tem->tvs_paramval; 1652 } 1653 tem->tvs_curparam++; 1654 } 1655 1656 if (ch == ';') { 1657 /* Restart parameter search */ 1658 tem->tvs_gotparam = B_FALSE; 1659 tem->tvs_paramval = 0; /* No parame value yet */ 1660 } else { 1661 /* Handle escape sequence */ 1662 tem_chkparam(tem, ch); 1663 } 1664 } 1665 } 1666 1667 /* 1668 * Add character to internal buffer. 1669 * When its full, send it to the next layer. 1670 */ 1671 static void 1672 tem_outch(struct tem_vt_state *tem, tem_char_t ch) 1673 { 1674 text_color_t fg; 1675 text_color_t bg; 1676 text_attr_t attr; 1677 1678 /* buffer up the character until later */ 1679 tem_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE); 1680 tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr); 1681 tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg; 1682 tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg; 1683 tem->tvs_outindex++; 1684 tem->tvs_c_cursor.col++; 1685 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) { 1686 tem_send_data(tem); 1687 tem_new_line(tem); 1688 } 1689 } 1690 1691 static void 1692 tem_new_line(struct tem_vt_state *tem) 1693 { 1694 tem_cr(tem); 1695 tem_lf(tem); 1696 } 1697 1698 static void 1699 tem_cr(struct tem_vt_state *tem) 1700 { 1701 tem->tvs_c_cursor.col = 0; 1702 tem_align_cursor(tem); 1703 } 1704 1705 static void 1706 tem_lf(struct tem_vt_state *tem) 1707 { 1708 int row; 1709 1710 /* 1711 * Sanity checking notes: 1712 * . a_nscroll was validated when it was set. 1713 * . Regardless of that, tem_scroll and tem_mv_cursor 1714 * will prevent anything bad from happening. 1715 */ 1716 row = tem->tvs_c_cursor.row + 1; 1717 1718 if (row >= tems.ts_c_dimension.height) { 1719 if (tem->tvs_nscroll != 0) { 1720 tem_scroll(tem, 0, 1721 tems.ts_c_dimension.height - 1, 1722 tem->tvs_nscroll, TEM_SCROLL_UP); 1723 row = tems.ts_c_dimension.height - 1724 tem->tvs_nscroll; 1725 } else { /* no scroll */ 1726 /* 1727 * implement Esc[#r when # is zero. This means no 1728 * scroll but just return cursor to top of screen, 1729 * do not clear screen. 1730 */ 1731 row = 0; 1732 } 1733 } 1734 1735 tem_mv_cursor(tem, row, tem->tvs_c_cursor.col); 1736 1737 if (tem->tvs_nscroll == 0) { 1738 /* erase rest of cursor line */ 1739 tem_clear_chars(tem, 1740 tems.ts_c_dimension.width - 1741 tem->tvs_c_cursor.col, 1742 tem->tvs_c_cursor.row, 1743 tem->tvs_c_cursor.col); 1744 1745 } 1746 1747 tem_align_cursor(tem); 1748 } 1749 1750 static void 1751 tem_send_data(struct tem_vt_state *tem) 1752 { 1753 if (tem->tvs_outindex == 0) { 1754 tem_align_cursor(tem); 1755 return; 1756 } 1757 1758 tem_virtual_display(tem, tem->tvs_outbuf, tem->tvs_outindex, 1759 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); 1760 1761 if (tem->tvs_isactive) { 1762 /* 1763 * Call the primitive to render this data. 1764 */ 1765 tem_callback_display(tem, 1766 tem->tvs_outbuf, tem->tvs_outindex, 1767 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col); 1768 } 1769 1770 tem->tvs_outindex = 0; 1771 1772 tem_align_cursor(tem); 1773 } 1774 1775 1776 /* 1777 * We have just done something to the current output point. Reset the start 1778 * point for the buffered data in a_outbuf. There shouldn't be any data 1779 * buffered yet. 1780 */ 1781 static void 1782 tem_align_cursor(struct tem_vt_state *tem) 1783 { 1784 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row; 1785 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col; 1786 } 1787 1788 /* 1789 * State machine parser based on the current state and character input 1790 * major terminations are to control character or normal character 1791 */ 1792 1793 static void 1794 tem_parse(struct tem_vt_state *tem, tem_char_t ch) 1795 { 1796 int i; 1797 1798 if (tem->tvs_state == A_STATE_START) { /* Normal state? */ 1799 if (ch == A_CSI || ch == A_ESC || ch < ' ') { 1800 /* Control */ 1801 tem_control(tem, ch); 1802 } else { 1803 /* Display */ 1804 tem_outch(tem, ch); 1805 } 1806 return; 1807 } 1808 1809 /* In <ESC> sequence */ 1810 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */ 1811 if (tem->tvs_state != A_STATE_CSI) { 1812 tem_getparams(tem, ch); 1813 return; 1814 } 1815 1816 switch (ch) { 1817 case '?': 1818 tem->tvs_state = A_STATE_CSI_QMARK; 1819 return; 1820 case '=': 1821 tem->tvs_state = A_STATE_CSI_EQUAL; 1822 return; 1823 case 's': 1824 /* 1825 * As defined below, this sequence 1826 * saves the cursor. However, Sun 1827 * defines ESC[s as reset. We resolved 1828 * the conflict by selecting reset as it 1829 * is exported in the termcap file for 1830 * sun-mon, while the "save cursor" 1831 * definition does not exist anywhere in 1832 * /etc/termcap. 1833 * However, having no coherent 1834 * definition of reset, we have not 1835 * implemented it. 1836 */ 1837 1838 /* 1839 * Original code 1840 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; 1841 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; 1842 * tem->tvs_state = A_STATE_START; 1843 */ 1844 1845 tem->tvs_state = A_STATE_START; 1846 return; 1847 case 'u': 1848 tem_mv_cursor(tem, tem->tvs_r_cursor.row, 1849 tem->tvs_r_cursor.col); 1850 tem->tvs_state = A_STATE_START; 1851 return; 1852 case 'p': /* sunbow */ 1853 tem_send_data(tem); 1854 /* 1855 * Don't set anything if we are 1856 * already as we want to be. 1857 */ 1858 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) { 1859 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE; 1860 /* 1861 * If we have switched the characters to be the 1862 * inverse from the screen, then switch them as 1863 * well to keep them the inverse of the screen. 1864 */ 1865 if (tem->tvs_flags & TEM_ATTR_REVERSE) 1866 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1867 else 1868 tem->tvs_flags |= TEM_ATTR_REVERSE; 1869 } 1870 tem_cls(tem); 1871 tem->tvs_state = A_STATE_START; 1872 return; 1873 case 'q': /* sunwob */ 1874 tem_send_data(tem); 1875 /* 1876 * Don't set anything if we are 1877 * already where as we want to be. 1878 */ 1879 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) { 1880 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE; 1881 /* 1882 * If we have switched the characters to be the 1883 * inverse from the screen, then switch them as 1884 * well to keep them the inverse of the screen. 1885 */ 1886 if (!(tem->tvs_flags & TEM_ATTR_REVERSE)) 1887 tem->tvs_flags |= TEM_ATTR_REVERSE; 1888 else 1889 tem->tvs_flags &= ~TEM_ATTR_REVERSE; 1890 } 1891 1892 tem_cls(tem); 1893 tem->tvs_state = A_STATE_START; 1894 return; 1895 case 'r': /* sunscrl */ 1896 /* 1897 * Rule exception: check for validity here. 1898 */ 1899 tem->tvs_nscroll = tem->tvs_paramval; 1900 if (tem->tvs_nscroll > tems.ts_c_dimension.height) 1901 tem->tvs_nscroll = tems.ts_c_dimension.height; 1902 if (tem->tvs_nscroll < 0) 1903 tem->tvs_nscroll = 1; 1904 tem->tvs_state = A_STATE_START; 1905 return; 1906 default: 1907 tem_getparams(tem, ch); 1908 return; 1909 } 1910 } 1911 1912 /* Previous char was <ESC> */ 1913 if (ch == '[') { 1914 tem->tvs_curparam = 0; 1915 tem->tvs_paramval = 0; 1916 tem->tvs_gotparam = B_FALSE; 1917 /* clear the parameters */ 1918 for (i = 0; i < TEM_MAXPARAMS; i++) 1919 tem->tvs_params[i] = -1; 1920 tem->tvs_state = A_STATE_CSI; 1921 } else if (ch == 'Q') { /* <ESC>Q ? */ 1922 tem->tvs_state = A_STATE_START; 1923 } else if (ch == 'C') { /* <ESC>C ? */ 1924 tem->tvs_state = A_STATE_START; 1925 } else { 1926 tem->tvs_state = A_STATE_START; 1927 if (ch == 'c') { 1928 /* ESC c resets display */ 1929 tem_reset_display(tem, B_TRUE, B_TRUE); 1930 } else if (ch == 'H') { 1931 /* ESC H sets a tab */ 1932 tem_set_tab(tem); 1933 } else if (ch == '7') { 1934 /* ESC 7 Save Cursor position */ 1935 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row; 1936 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col; 1937 } else if (ch == '8') { 1938 /* ESC 8 Restore Cursor position */ 1939 tem_mv_cursor(tem, tem->tvs_r_cursor.row, 1940 tem->tvs_r_cursor.col); 1941 /* check for control chars */ 1942 } else if (ch < ' ') { 1943 tem_control(tem, ch); 1944 } else { 1945 tem_outch(tem, ch); 1946 } 1947 } 1948 } 1949 1950 /* ARGSUSED */ 1951 static void 1952 tem_bell(struct tem_vt_state *tem __unused) 1953 { 1954 /* (void) beep(BEEP_CONSOLE); */ 1955 } 1956 1957 1958 static void 1959 tem_scroll(struct tem_vt_state *tem, int start, int end, int count, 1960 int direction) 1961 { 1962 int row; 1963 int lines_affected; 1964 1965 lines_affected = end - start + 1; 1966 if (count > lines_affected) 1967 count = lines_affected; 1968 if (count <= 0) 1969 return; 1970 1971 switch (direction) { 1972 case TEM_SCROLL_UP: 1973 if (count < lines_affected) { 1974 tem_copy_area(tem, 0, start + count, 1975 tems.ts_c_dimension.width - 1, end, 0, start); 1976 } 1977 for (row = (end - count) + 1; row <= end; row++) { 1978 tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); 1979 } 1980 break; 1981 1982 case TEM_SCROLL_DOWN: 1983 if (count < lines_affected) { 1984 tem_copy_area(tem, 0, start, 1985 tems.ts_c_dimension.width - 1, 1986 end - count, 0, start + count); 1987 } 1988 for (row = start; row < start + count; row++) { 1989 tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0); 1990 } 1991 break; 1992 } 1993 } 1994 1995 static int 1996 tem_copy_width(term_char_t *src, term_char_t *dst, int cols) 1997 { 1998 int width = cols - 1; 1999 2000 while (width >= 0) { 2001 /* We do not have image bits to compare, stop there. */ 2002 if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE || 2003 TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE) 2004 break; 2005 2006 /* 2007 * Find difference on line, compare char with its attributes 2008 * and colors. 2009 */ 2010 if (src[width].tc_char != dst[width].tc_char || 2011 src[width].tc_fg_color != dst[width].tc_fg_color || 2012 src[width].tc_bg_color != dst[width].tc_bg_color) { 2013 break; 2014 } 2015 width--; 2016 } 2017 return (width + 1); 2018 } 2019 2020 static void 2021 tem_copy_area(struct tem_vt_state *tem, 2022 screen_pos_t s_col, screen_pos_t s_row, 2023 screen_pos_t e_col, screen_pos_t e_row, 2024 screen_pos_t t_col, screen_pos_t t_row) 2025 { 2026 size_t soffset, toffset; 2027 term_char_t *src, *dst; 2028 int rows; 2029 int cols; 2030 2031 if (s_col < 0 || s_row < 0 || 2032 e_col < 0 || e_row < 0 || 2033 t_col < 0 || t_row < 0 || 2034 s_col >= tems.ts_c_dimension.width || 2035 e_col >= tems.ts_c_dimension.width || 2036 t_col >= tems.ts_c_dimension.width || 2037 s_row >= tems.ts_c_dimension.height || 2038 e_row >= tems.ts_c_dimension.height || 2039 t_row >= tems.ts_c_dimension.height) 2040 return; 2041 2042 if (s_row > e_row || s_col > e_col) 2043 return; 2044 2045 rows = e_row - s_row + 1; 2046 cols = e_col - s_col + 1; 2047 if (t_row + rows > tems.ts_c_dimension.height || 2048 t_col + cols > tems.ts_c_dimension.width) 2049 return; 2050 2051 if (tem->tvs_screen_buf == NULL) { 2052 if (tem->tvs_isactive) { 2053 tem_callback_copy(tem, s_col, s_row, 2054 e_col, e_row, t_col, t_row); 2055 } 2056 return; 2057 } 2058 2059 soffset = s_col + s_row * tems.ts_c_dimension.width; 2060 toffset = t_col + t_row * tems.ts_c_dimension.width; 2061 src = tem->tvs_screen_buf + soffset; 2062 dst = tem->tvs_screen_buf + toffset; 2063 2064 /* 2065 * Copy line by line. We determine the length by comparing the 2066 * screen content from cached text in tvs_screen_buf. 2067 */ 2068 if (toffset <= soffset) { 2069 for (int i = 0; i < rows; i++) { 2070 int increment = i * tems.ts_c_dimension.width; 2071 int width; 2072 2073 width = tem_copy_width(src + increment, 2074 dst + increment, cols); 2075 memmove(dst + increment, src + increment, 2076 width * sizeof (term_char_t)); 2077 if (tem->tvs_isactive) { 2078 tem_callback_copy(tem, s_col, s_row + i, 2079 e_col - cols + width, s_row + i, 2080 t_col, t_row + i); 2081 } 2082 } 2083 } else { 2084 for (int i = rows - 1; i >= 0; i--) { 2085 int increment = i * tems.ts_c_dimension.width; 2086 int width; 2087 2088 width = tem_copy_width(src + increment, 2089 dst + increment, cols); 2090 memmove(dst + increment, src + increment, 2091 width * sizeof (term_char_t)); 2092 if (tem->tvs_isactive) { 2093 tem_callback_copy(tem, s_col, s_row + i, 2094 e_col - cols + width, s_row + i, 2095 t_col, t_row + i); 2096 } 2097 } 2098 } 2099 } 2100 2101 static void 2102 tem_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row, 2103 screen_pos_t col) 2104 { 2105 if (row < 0 || row >= tems.ts_c_dimension.height || 2106 col < 0 || col >= tems.ts_c_dimension.width || 2107 count < 0) 2108 return; 2109 2110 /* 2111 * Note that very large values of "count" could cause col+count 2112 * to overflow, so we check "count" independently. 2113 */ 2114 if (count > tems.ts_c_dimension.width || 2115 col + count > tems.ts_c_dimension.width) 2116 count = tems.ts_c_dimension.width - col; 2117 2118 tem_virtual_cls(tem, count, row, col); 2119 2120 if (!tem->tvs_isactive) 2121 return; 2122 2123 tem_callback_cls(tem, count, row, col); 2124 } 2125 2126 static void 2127 tem_text_display(struct tem_vt_state *tem __unused, term_char_t *string, 2128 int count, screen_pos_t row, screen_pos_t col) 2129 { 2130 struct vis_consdisplay da; 2131 int i; 2132 tem_char_t c; 2133 2134 if (count == 0) 2135 return; 2136 2137 da.data = (unsigned char *)&c; 2138 da.width = 1; 2139 da.row = row; 2140 da.col = col; 2141 2142 for (i = 0; i < count; i++) { 2143 tem_get_color(&da.fg_color, &da.bg_color, string[i]); 2144 c = TEM_CHAR(string[i].tc_char); 2145 tems_display(&da); 2146 da.col++; 2147 } 2148 } 2149 2150 /* 2151 * This function is used to mark a rectangular image area so the scrolling 2152 * will know we need to copy the data from there. 2153 */ 2154 void 2155 tem_image_display(struct tem_vt_state *tem, screen_pos_t s_row, 2156 screen_pos_t s_col, screen_pos_t e_row, screen_pos_t e_col) 2157 { 2158 screen_pos_t i, j; 2159 term_char_t c; 2160 2161 c.tc_char = TEM_ATTR(TEM_ATTR_IMAGE); 2162 2163 for (i = s_row; i <= e_row; i++) { 2164 for (j = s_col; j <= e_col; j++) { 2165 tem_virtual_display(tem, &c, 1, i, j); 2166 } 2167 } 2168 } 2169 2170 /*ARGSUSED*/ 2171 static void 2172 tem_text_copy(struct tem_vt_state *tem __unused, 2173 screen_pos_t s_col, screen_pos_t s_row, 2174 screen_pos_t e_col, screen_pos_t e_row, 2175 screen_pos_t t_col, screen_pos_t t_row) 2176 { 2177 struct vis_conscopy da; 2178 2179 da.s_row = s_row; 2180 da.s_col = s_col; 2181 da.e_row = e_row; 2182 da.e_col = e_col; 2183 da.t_row = t_row; 2184 da.t_col = t_col; 2185 tems_copy(&da); 2186 } 2187 2188 static void 2189 tem_text_cls(struct tem_vt_state *tem, 2190 int count, screen_pos_t row, screen_pos_t col) 2191 { 2192 text_attr_t attr; 2193 term_char_t c; 2194 int i; 2195 2196 tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2197 TEM_ATTR_SCREEN_REVERSE); 2198 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; 2199 2200 if (count > tems.ts_c_dimension.width || 2201 col + count > tems.ts_c_dimension.width) 2202 count = tems.ts_c_dimension.width - col; 2203 2204 for (i = 0; i < count; i++) 2205 tem_text_display(tem, &c, 1, row, col++); 2206 2207 } 2208 2209 static void 2210 tem_pix_display(struct tem_vt_state *tem, 2211 term_char_t *string, int count, 2212 screen_pos_t row, screen_pos_t col) 2213 { 2214 struct vis_consdisplay da; 2215 int i; 2216 2217 da.data = (uint8_t *)tem->tvs_pix_data; 2218 da.width = tems.ts_font.vf_width; 2219 da.height = tems.ts_font.vf_height; 2220 da.row = (row * da.height) + tems.ts_p_offset.y; 2221 da.col = (col * da.width) + tems.ts_p_offset.x; 2222 2223 for (i = 0; i < count; i++) { 2224 tem_callback_bit2pix(tem, string[i]); 2225 tems_display(&da); 2226 da.col += da.width; 2227 } 2228 } 2229 2230 static void 2231 tem_pix_copy(struct tem_vt_state *tem, 2232 screen_pos_t s_col, screen_pos_t s_row, 2233 screen_pos_t e_col, screen_pos_t e_row, 2234 screen_pos_t t_col, screen_pos_t t_row) 2235 { 2236 struct vis_conscopy ma; 2237 static boolean_t need_clear = B_TRUE; 2238 2239 if (need_clear && tem->tvs_first_line > 0) { 2240 /* 2241 * Clear OBP output above our kernel console term 2242 * when our kernel console term begins to scroll up, 2243 * we hope it is user friendly. 2244 * (Also see comments on tem_pix_clear_prom_output) 2245 * 2246 * This is only one time call. 2247 */ 2248 tem_pix_clear_prom_output(tem); 2249 } 2250 need_clear = B_FALSE; 2251 2252 ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y; 2253 ma.e_row = (e_row + 1) * tems.ts_font.vf_height + 2254 tems.ts_p_offset.y - 1; 2255 ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y; 2256 2257 /* 2258 * Check if we're in process of clearing OBP's columns area, 2259 * which only happens when term scrolls up a whole line. 2260 */ 2261 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 && 2262 e_col == tems.ts_c_dimension.width - 1) { 2263 /* 2264 * We need to clear OBP's columns area outside our kernel 2265 * console term. So that we set ma.e_col to entire row here. 2266 */ 2267 ma.s_col = s_col * tems.ts_font.vf_width; 2268 ma.e_col = tems.ts_p_dimension.width - 1; 2269 2270 ma.t_col = t_col * tems.ts_font.vf_width; 2271 } else { 2272 ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x; 2273 ma.e_col = (e_col + 1) * tems.ts_font.vf_width + 2274 tems.ts_p_offset.x - 1; 2275 ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x; 2276 } 2277 2278 tems_copy(&ma); 2279 2280 if (tem->tvs_first_line > 0 && t_row < s_row) { 2281 /* We have scrolled up (s_row - t_row) rows. */ 2282 tem->tvs_first_line -= (s_row - t_row); 2283 if (tem->tvs_first_line <= 0) { 2284 /* All OBP rows have been cleared. */ 2285 tem->tvs_first_line = 0; 2286 } 2287 } 2288 } 2289 2290 static void 2291 tem_pix_bit2pix(struct tem_vt_state *tem, term_char_t c) 2292 { 2293 text_color_t fg, bg; 2294 2295 fg = DEFAULT_ANSI_FOREGROUND; 2296 bg = DEFAULT_ANSI_BACKGROUND; 2297 2298 tem_get_color(&fg, &bg, c); 2299 bit_to_pix32(tem, c.tc_char, fg, bg); 2300 } 2301 2302 2303 /* 2304 * This function only clears count of columns in one row 2305 */ 2306 static void 2307 tem_pix_cls(struct tem_vt_state *tem, int count, 2308 screen_pos_t row, screen_pos_t col) 2309 { 2310 tem_pix_cls_range(tem, row, 1, tems.ts_p_offset.y, 2311 col, count, tems.ts_p_offset.x, B_FALSE); 2312 } 2313 2314 /* 2315 * This function clears OBP output above our kernel console term area 2316 * because OBP's term may have a bigger terminal window than that of 2317 * our kernel console term. So we need to clear OBP output garbage outside 2318 * of our kernel console term at a proper time, which is when the first 2319 * row output of our kernel console term scrolls at the first screen line. 2320 * 2321 * _________________________________ 2322 * | _____________________ | ---> OBP's bigger term window 2323 * | | | | 2324 * |___| | | 2325 * | | | | | 2326 * | | | | | 2327 * |_|_|___________________|_______| 2328 * | | | ---> first line 2329 * | |___________________|---> our kernel console term window 2330 * | 2331 * |---> columns area to be cleared 2332 * 2333 * This function only takes care of the output above our kernel console term, 2334 * and tem_prom_scroll_up takes care of columns area outside of our kernel 2335 * console term. 2336 */ 2337 static void 2338 tem_pix_clear_prom_output(struct tem_vt_state *tem) 2339 { 2340 int nrows, ncols, width, height, offset; 2341 2342 width = tems.ts_font.vf_width; 2343 height = tems.ts_font.vf_height; 2344 offset = tems.ts_p_offset.y % height; 2345 2346 nrows = tems.ts_p_offset.y / height; 2347 ncols = (tems.ts_p_dimension.width + (width - 1)) / width; 2348 2349 if (nrows > 0) 2350 tem_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0, 2351 B_FALSE); 2352 } 2353 2354 /* 2355 * Clear the whole screen and reset the cursor to start point. 2356 */ 2357 static void 2358 tem_cls(struct tem_vt_state *tem) 2359 { 2360 struct vis_consclear cl; 2361 text_color_t fg_color; 2362 text_color_t bg_color; 2363 text_attr_t attr; 2364 term_char_t c; 2365 int row; 2366 2367 for (row = 0; row < tems.ts_c_dimension.height; row++) { 2368 tem_virtual_cls(tem, tems.ts_c_dimension.width, row, 0); 2369 } 2370 2371 if (!tem->tvs_isactive) 2372 return; 2373 2374 tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2375 TEM_ATTR_SCREEN_REVERSE); 2376 c.tc_char = TEM_ATTR(attr); 2377 2378 fg_color = DEFAULT_ANSI_FOREGROUND; 2379 bg_color = DEFAULT_ANSI_BACKGROUND; 2380 tem_get_color(&fg_color, &bg_color, c); 2381 cl.bg_color = bg_color; 2382 (void) tems_cls(&cl); 2383 2384 tem->tvs_c_cursor.row = 0; 2385 tem->tvs_c_cursor.col = 0; 2386 tem_align_cursor(tem); 2387 } 2388 2389 static void 2390 tem_back_tab(struct tem_vt_state *tem) 2391 { 2392 int i; 2393 screen_pos_t tabstop; 2394 2395 tabstop = 0; 2396 2397 for (i = tem->tvs_ntabs - 1; i >= 0; i--) { 2398 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) { 2399 tabstop = tem->tvs_tabs[i]; 2400 break; 2401 } 2402 } 2403 2404 tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); 2405 } 2406 2407 static void 2408 tem_tab(struct tem_vt_state *tem) 2409 { 2410 size_t i; 2411 screen_pos_t tabstop; 2412 2413 tabstop = tems.ts_c_dimension.width - 1; 2414 2415 for (i = 0; i < tem->tvs_ntabs; i++) { 2416 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { 2417 tabstop = tem->tvs_tabs[i]; 2418 break; 2419 } 2420 } 2421 2422 tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop); 2423 } 2424 2425 static void 2426 tem_set_tab(struct tem_vt_state *tem) 2427 { 2428 size_t i, j; 2429 2430 if (tem->tvs_ntabs == tem->tvs_maxtab) 2431 return; 2432 if (tem->tvs_ntabs == 0 || 2433 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) { 2434 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col; 2435 return; 2436 } 2437 for (i = 0; i < tem->tvs_ntabs; i++) { 2438 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) 2439 return; 2440 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) { 2441 for (j = tem->tvs_ntabs - 1; j >= i; j--) 2442 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j]; 2443 tem->tvs_tabs[i] = tem->tvs_c_cursor.col; 2444 tem->tvs_ntabs++; 2445 return; 2446 } 2447 } 2448 } 2449 2450 static void 2451 tem_clear_tabs(struct tem_vt_state *tem, int action) 2452 { 2453 size_t i, j; 2454 2455 switch (action) { 2456 case 3: /* clear all tabs */ 2457 tem->tvs_ntabs = 0; 2458 break; 2459 case 0: /* clr tab at cursor */ 2460 2461 for (i = 0; i < tem->tvs_ntabs; i++) { 2462 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) { 2463 tem->tvs_ntabs--; 2464 for (j = i; j < tem->tvs_ntabs; j++) 2465 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1]; 2466 return; 2467 } 2468 } 2469 break; 2470 } 2471 } 2472 2473 static void 2474 tem_mv_cursor(struct tem_vt_state *tem, int row, int col) 2475 { 2476 /* 2477 * Sanity check and bounds enforcement. Out of bounds requests are 2478 * clipped to the screen boundaries. This seems to be what SPARC 2479 * does. 2480 */ 2481 if (row < 0) 2482 row = 0; 2483 if (row >= tems.ts_c_dimension.height) 2484 row = tems.ts_c_dimension.height - 1; 2485 if (col < 0) 2486 col = 0; 2487 if (col >= tems.ts_c_dimension.width) 2488 col = tems.ts_c_dimension.width - 1; 2489 2490 tem_send_data(tem); 2491 tem->tvs_c_cursor.row = (screen_pos_t)row; 2492 tem->tvs_c_cursor.col = (screen_pos_t)col; 2493 tem_align_cursor(tem); 2494 } 2495 2496 /* ARGSUSED */ 2497 static void 2498 tem_reset_emulator(struct tem_vt_state *tem, boolean_t init_color) 2499 { 2500 int j; 2501 2502 tem->tvs_c_cursor.row = 0; 2503 tem->tvs_c_cursor.col = 0; 2504 tem->tvs_r_cursor.row = 0; 2505 tem->tvs_r_cursor.col = 0; 2506 tem->tvs_s_cursor.row = 0; 2507 tem->tvs_s_cursor.col = 0; 2508 tem->tvs_outindex = 0; 2509 tem->tvs_state = A_STATE_START; 2510 tem->tvs_gotparam = B_FALSE; 2511 tem->tvs_curparam = 0; 2512 tem->tvs_paramval = 0; 2513 tem->tvs_nscroll = 1; 2514 2515 if (init_color) { 2516 /* use initial settings */ 2517 tem->tvs_fg_color = tems.ts_init_color.fg_color; 2518 tem->tvs_bg_color = tems.ts_init_color.bg_color; 2519 tem->tvs_flags = tems.ts_init_color.a_flags; 2520 } 2521 2522 /* 2523 * set up the initial tab stops 2524 */ 2525 tem->tvs_ntabs = 0; 2526 for (j = 8; j < tems.ts_c_dimension.width; j += 8) 2527 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j; 2528 2529 for (j = 0; j < TEM_MAXPARAMS; j++) 2530 tem->tvs_params[j] = 0; 2531 } 2532 2533 static void 2534 tem_reset_display(struct tem_vt_state *tem, 2535 boolean_t clear_txt, boolean_t init_color) 2536 { 2537 tem_reset_emulator(tem, init_color); 2538 2539 if (clear_txt) { 2540 if (tem->tvs_isactive) 2541 tem_callback_cursor(tem, VIS_HIDE_CURSOR); 2542 2543 tem_cls(tem); 2544 2545 if (tem->tvs_isactive) 2546 tem_callback_cursor(tem, VIS_DISPLAY_CURSOR); 2547 } 2548 } 2549 2550 static void 2551 tem_shift(struct tem_vt_state *tem, int count, int direction) 2552 { 2553 int rest_of_line; 2554 2555 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col; 2556 if (count > rest_of_line) 2557 count = rest_of_line; 2558 2559 if (count <= 0) 2560 return; 2561 2562 switch (direction) { 2563 case TEM_SHIFT_LEFT: 2564 if (count < rest_of_line) { 2565 tem_copy_area(tem, 2566 tem->tvs_c_cursor.col + count, 2567 tem->tvs_c_cursor.row, 2568 tems.ts_c_dimension.width - 1, 2569 tem->tvs_c_cursor.row, 2570 tem->tvs_c_cursor.col, 2571 tem->tvs_c_cursor.row); 2572 } 2573 2574 tem_clear_chars(tem, count, tem->tvs_c_cursor.row, 2575 (tems.ts_c_dimension.width - count)); 2576 break; 2577 case TEM_SHIFT_RIGHT: 2578 if (count < rest_of_line) { 2579 tem_copy_area(tem, 2580 tem->tvs_c_cursor.col, 2581 tem->tvs_c_cursor.row, 2582 tems.ts_c_dimension.width - count - 1, 2583 tem->tvs_c_cursor.row, 2584 tem->tvs_c_cursor.col + count, 2585 tem->tvs_c_cursor.row); 2586 } 2587 2588 tem_clear_chars(tem, count, tem->tvs_c_cursor.row, 2589 tem->tvs_c_cursor.col); 2590 break; 2591 } 2592 } 2593 2594 static void 2595 tem_text_cursor(struct tem_vt_state *tem, short action) 2596 { 2597 struct vis_conscursor ca; 2598 2599 ca.row = tem->tvs_c_cursor.row; 2600 ca.col = tem->tvs_c_cursor.col; 2601 ca.action = action; 2602 2603 tems_cursor(&ca); 2604 2605 if (action == VIS_GET_CURSOR) { 2606 tem->tvs_c_cursor.row = ca.row; 2607 tem->tvs_c_cursor.col = ca.col; 2608 } 2609 } 2610 2611 static void 2612 tem_pix_cursor(struct tem_vt_state *tem, short action) 2613 { 2614 struct vis_conscursor ca; 2615 uint32_t color; 2616 text_color_t fg, bg; 2617 term_char_t c; 2618 text_attr_t attr; 2619 2620 ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height + 2621 tems.ts_p_offset.y; 2622 ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width + 2623 tems.ts_p_offset.x; 2624 ca.width = tems.ts_font.vf_width; 2625 ca.height = tems.ts_font.vf_height; 2626 2627 tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2628 TEM_ATTR_REVERSE); 2629 c.tc_char = TEM_ATTR(attr); 2630 2631 fg = DEFAULT_ANSI_FOREGROUND; 2632 bg = DEFAULT_ANSI_BACKGROUND; 2633 tem_get_color(&fg, &bg, c); 2634 2635 color = tems.ts_color_map(fg); 2636 ca.fg_color.twentyfour[0] = (color >> 16) & 0xFF; 2637 ca.fg_color.twentyfour[1] = (color >> 8) & 0xFF; 2638 ca.fg_color.twentyfour[2] = color & 0xFF; 2639 color = tems.ts_color_map(bg); 2640 ca.bg_color.twentyfour[0] = (color >> 16) & 0xFF; 2641 ca.bg_color.twentyfour[1] = (color >> 8) & 0xFF; 2642 ca.bg_color.twentyfour[2] = color & 0xFF; 2643 2644 ca.action = action; 2645 2646 tems_cursor(&ca); 2647 2648 if (action == VIS_GET_CURSOR) { 2649 tem->tvs_c_cursor.row = 0; 2650 tem->tvs_c_cursor.col = 0; 2651 2652 if (ca.row != 0) { 2653 tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) / 2654 tems.ts_font.vf_height; 2655 } 2656 if (ca.col != 0) { 2657 tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) / 2658 tems.ts_font.vf_width; 2659 } 2660 } 2661 } 2662 2663 static void 2664 bit_to_pix32(struct tem_vt_state *tem, 2665 tem_char_t c, 2666 text_color_t fg_color4, 2667 text_color_t bg_color4) 2668 { 2669 uint32_t fg_color32, bg_color32, *dest; 2670 2671 fg_color32 = (0xFF << 24) | tems.ts_color_map(fg_color4); 2672 bg_color32 = (0xFF << 24) | tems.ts_color_map(bg_color4); 2673 2674 dest = (uint32_t *)tem->tvs_pix_data; 2675 font_bit_to_pix32(&tems.ts_font, dest, c, fg_color32, bg_color32); 2676 } 2677 2678 /* 2679 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE 2680 */ 2681 static void 2682 tem_get_attr(struct tem_vt_state *tem, text_color_t *fg, 2683 text_color_t *bg, text_attr_t *attr, uint8_t flag) 2684 { 2685 if (tem->tvs_flags & flag) { 2686 *fg = tem->tvs_bg_color; 2687 *bg = tem->tvs_fg_color; 2688 } else { 2689 *fg = tem->tvs_fg_color; 2690 *bg = tem->tvs_bg_color; 2691 } 2692 2693 if (attr == NULL) 2694 return; 2695 2696 *attr = tem->tvs_flags; 2697 } 2698 2699 static void 2700 tem_get_color(text_color_t *fg, text_color_t *bg, term_char_t c) 2701 { 2702 bool bold_font; 2703 2704 *fg = c.tc_fg_color; 2705 *bg = c.tc_bg_color; 2706 2707 bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0; 2708 2709 /* 2710 * If we have both normal and bold font components, 2711 * we use bold font for TEM_ATTR_BOLD. 2712 * The bright color is traditionally used with TEM_ATTR_BOLD, 2713 * in case there is no bold font. 2714 */ 2715 if (c.tc_fg_color < XLATE_NCOLORS) { 2716 if (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BRIGHT_FG) || 2717 (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BOLD) && !bold_font)) 2718 *fg = brt_xlate[c.tc_fg_color]; 2719 else 2720 *fg = dim_xlate[c.tc_fg_color]; 2721 } 2722 2723 if (c.tc_bg_color < XLATE_NCOLORS) { 2724 if (TEM_ATTR_ISSET(c.tc_char, TEM_ATTR_BRIGHT_BG)) 2725 *bg = brt_xlate[c.tc_bg_color]; 2726 else 2727 *bg = dim_xlate[c.tc_bg_color]; 2728 } 2729 } 2730 2731 void 2732 tem_get_colors(tem_vt_state_t tem_arg, text_color_t *fg, text_color_t *bg) 2733 { 2734 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg; 2735 text_attr_t attr; 2736 term_char_t c; 2737 2738 tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2739 TEM_ATTR_REVERSE); 2740 c.tc_char = TEM_ATTR(attr); 2741 tem_get_color(fg, bg, c); 2742 } 2743 2744 /* 2745 * Clear a rectangle of screen for pixel mode. 2746 * 2747 * arguments: 2748 * row: start row# 2749 * nrows: the number of rows to clear 2750 * offset_y: the offset of height in pixels to begin clear 2751 * col: start col# 2752 * ncols: the number of cols to clear 2753 * offset_x: the offset of width in pixels to begin clear 2754 * scroll_up: whether this function is called during sroll up, 2755 * which is called only once. 2756 */ 2757 static void 2758 tem_pix_cls_range(struct tem_vt_state *tem, 2759 screen_pos_t row, int nrows, int offset_y, 2760 screen_pos_t col, int ncols, int offset_x, 2761 boolean_t sroll_up) 2762 { 2763 struct vis_consdisplay da; 2764 int i, j; 2765 int row_add = 0; 2766 term_char_t c; 2767 text_attr_t attr; 2768 2769 if (sroll_up) 2770 row_add = tems.ts_c_dimension.height - 1; 2771 2772 da.width = tems.ts_font.vf_width; 2773 da.height = tems.ts_font.vf_height; 2774 2775 tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr, 2776 TEM_ATTR_SCREEN_REVERSE); 2777 /* Make sure we will not draw underlines */ 2778 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' '; 2779 2780 tem_callback_bit2pix(tem, c); 2781 da.data = (uint8_t *)tem->tvs_pix_data; 2782 2783 for (i = 0; i < nrows; i++, row++) { 2784 da.row = (row + row_add) * da.height + offset_y; 2785 da.col = col * da.width + offset_x; 2786 for (j = 0; j < ncols; j++) { 2787 tems_display(&da); 2788 da.col += da.width; 2789 } 2790 } 2791 } 2792 2793 /* 2794 * virtual screen operations 2795 */ 2796 static void 2797 tem_virtual_display(struct tem_vt_state *tem, term_char_t *string, 2798 size_t count, screen_pos_t row, screen_pos_t col) 2799 { 2800 size_t i, width; 2801 term_char_t *addr; 2802 2803 if (tem->tvs_screen_buf == NULL) 2804 return; 2805 2806 if (row < 0 || row >= tems.ts_c_dimension.height || 2807 col < 0 || col >= tems.ts_c_dimension.width || 2808 col + count > (size_t)tems.ts_c_dimension.width) 2809 return; 2810 2811 width = tems.ts_c_dimension.width; 2812 addr = tem->tvs_screen_buf + (row * width + col); 2813 for (i = 0; i < count; i++) { 2814 *addr++ = string[i]; 2815 } 2816 } 2817 2818 static void 2819 tem_virtual_cls(struct tem_vt_state *tem, size_t count, 2820 screen_pos_t row, screen_pos_t col) 2821 { 2822 term_char_t c; 2823 2824 c.tc_char = ' '; 2825 tem_get_colors((tem_vt_state_t)tem, &c.tc_fg_color, &c.tc_bg_color); 2826 2827 while (count > 0) { 2828 tem_virtual_display(tem, &c, 1, row, col); 2829 col++; 2830 count--; 2831 } 2832 } 2833