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