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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2016 Joyent, Inc.
29 * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
32 * How Virtual Terminal Emulator Works:
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.
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).
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().
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.
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>
71 extern int lz4_decompress(void *, void *, size_t, size_t, int);
73 /* Terminal emulator internal helper functions */
74 static void tems_setup_terminal(struct vis_devinit
*, size_t, size_t);
75 static void tems_modechange_callback(struct vis_modechg_arg
*,
76 struct vis_devinit
*);
78 static void tems_reset_colormap(void);
80 static void tem_free_buf(struct tem_vt_state
*);
81 static void tem_internal_init(struct tem_vt_state
*, boolean_t
, boolean_t
);
82 static void tems_get_initial_color(tem_color_t
*pcolor
);
84 static void tem_control(struct tem_vt_state
*, uint8_t);
85 static void tem_setparam(struct tem_vt_state
*, int, int);
86 static void tem_selgraph(struct tem_vt_state
*);
87 static void tem_chkparam(struct tem_vt_state
*, uint8_t);
88 static void tem_getparams(struct tem_vt_state
*, uint8_t);
89 static void tem_outch(struct tem_vt_state
*, tem_char_t
);
90 static void tem_parse(struct tem_vt_state
*, tem_char_t
);
92 static void tem_new_line(struct tem_vt_state
*);
93 static void tem_cr(struct tem_vt_state
*);
94 static void tem_lf(struct tem_vt_state
*);
95 static void tem_send_data(struct tem_vt_state
*);
96 static void tem_cls(struct tem_vt_state
*);
97 static void tem_tab(struct tem_vt_state
*);
98 static void tem_back_tab(struct tem_vt_state
*);
99 static void tem_clear_tabs(struct tem_vt_state
*, int);
100 static void tem_set_tab(struct tem_vt_state
*);
101 static void tem_mv_cursor(struct tem_vt_state
*, int, int);
102 static void tem_shift(struct tem_vt_state
*, int, int);
103 static void tem_scroll(struct tem_vt_state
*, int, int, int, int);
104 static void tem_clear_chars(struct tem_vt_state
*tem
,
105 int count
, screen_pos_t row
, screen_pos_t col
);
106 static void tem_copy_area(struct tem_vt_state
*tem
,
107 screen_pos_t s_col
, screen_pos_t s_row
,
108 screen_pos_t e_col
, screen_pos_t e_row
,
109 screen_pos_t t_col
, screen_pos_t t_row
);
110 static void tem_bell(struct tem_vt_state
*tem
);
111 static void tem_pix_clear_prom_output(struct tem_vt_state
*tem
);
113 static void tem_virtual_cls(struct tem_vt_state
*, size_t, screen_pos_t
,
115 static void tem_virtual_display(struct tem_vt_state
*, term_char_t
*,
116 size_t, screen_pos_t
, screen_pos_t
);
117 static void tem_align_cursor(struct tem_vt_state
*tem
);
119 static void tem_check_first_time(struct tem_vt_state
*tem
);
120 static void tem_reset_display(struct tem_vt_state
*, boolean_t
, boolean_t
);
121 static void tem_terminal_emulate(struct tem_vt_state
*, uint8_t *, int);
122 static void tem_text_cursor(struct tem_vt_state
*, short);
123 static void tem_text_cls(struct tem_vt_state
*,
124 int count
, screen_pos_t row
, screen_pos_t col
);
125 static void tem_pix_display(struct tem_vt_state
*, term_char_t
*,
126 int, screen_pos_t
, screen_pos_t
);
127 static void tem_pix_copy(struct tem_vt_state
*,
128 screen_pos_t
, screen_pos_t
,
129 screen_pos_t
, screen_pos_t
,
130 screen_pos_t
, screen_pos_t
);
131 static void tem_pix_cursor(struct tem_vt_state
*, short);
132 static void tem_get_attr(struct tem_vt_state
*, text_color_t
*,
133 text_color_t
*, text_attr_t
*, uint8_t);
134 static void tem_get_color(text_color_t
*, text_color_t
*, term_char_t
);
135 static void tem_pix_align(struct tem_vt_state
*);
136 static void tem_text_display(struct tem_vt_state
*, term_char_t
*, int,
137 screen_pos_t
, screen_pos_t
);
138 static void tem_text_copy(struct tem_vt_state
*,
139 screen_pos_t
, screen_pos_t
, screen_pos_t
, screen_pos_t
,
140 screen_pos_t
, screen_pos_t
);
141 static void tem_pix_bit2pix(struct tem_vt_state
*, term_char_t
);
142 static void tem_pix_cls_range(struct tem_vt_state
*, screen_pos_t
, int,
143 int, screen_pos_t
, int, int, boolean_t
);
144 static void tem_pix_cls(struct tem_vt_state
*, int,
145 screen_pos_t
, screen_pos_t
);
147 static void bit_to_pix4(struct tem_vt_state
*tem
, tem_char_t c
,
148 text_color_t fg_color
, text_color_t bg_color
);
149 static void bit_to_pix8(struct tem_vt_state
*tem
, tem_char_t c
,
150 text_color_t fg_color
, text_color_t bg_color
);
151 static void bit_to_pix16(struct tem_vt_state
*tem
, tem_char_t c
,
152 text_color_t fg_color
, text_color_t bg_color
);
153 static void bit_to_pix24(struct tem_vt_state
*tem
, tem_char_t c
,
154 text_color_t fg_color
, text_color_t bg_color
);
155 static void bit_to_pix32(struct tem_vt_state
*tem
, tem_char_t c
,
156 text_color_t fg_color
, text_color_t bg_color
);
161 tem_state_t tems
; /* common term info */
163 tem_callbacks_t tem_text_callbacks
= {
164 .tsc_display
= &tem_text_display
,
165 .tsc_copy
= &tem_text_copy
,
166 .tsc_cursor
= &tem_text_cursor
,
168 .tsc_cls
= &tem_text_cls
170 tem_callbacks_t tem_pix_callbacks
= {
171 .tsc_display
= &tem_pix_display
,
172 .tsc_copy
= &tem_pix_copy
,
173 .tsc_cursor
= &tem_pix_cursor
,
174 .tsc_bit2pix
= &tem_pix_bit2pix
,
175 .tsc_cls
= &tem_pix_cls
178 #define tem_callback_display (*tems.ts_callbacks->tsc_display)
179 #define tem_callback_copy (*tems.ts_callbacks->tsc_copy)
180 #define tem_callback_cursor (*tems.ts_callbacks->tsc_cursor)
181 #define tem_callback_cls (*tems.ts_callbacks->tsc_cls)
182 #define tem_callback_bit2pix (*tems.ts_callbacks->tsc_bit2pix)
185 tem_add(struct tem_vt_state
*tem
)
187 list_insert_head(&tems
.ts_list
, tem
);
191 * This is the main entry point to the module. It handles output requests
192 * during normal system operation, when (e.g.) mutexes are available.
195 tem_write(tem_vt_state_t tem_arg
, uint8_t *buf
, ssize_t len
)
197 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
199 if (!tem
->tvs_initialized
) {
203 tem_check_first_time(tem
);
204 tem_terminal_emulate(tem
, buf
, len
);
208 tem_internal_init(struct tem_vt_state
*ptem
,
209 boolean_t init_color
, boolean_t clear_screen
)
211 size_t size
, width
, height
;
213 if (tems
.ts_display_mode
== VIS_PIXEL
) {
214 ptem
->tvs_pix_data_size
= tems
.ts_pix_data_size
;
215 ptem
->tvs_pix_data
= malloc(ptem
->tvs_pix_data_size
);
218 width
= tems
.ts_c_dimension
.width
;
219 height
= tems
.ts_c_dimension
.height
;
221 size
= width
* sizeof (tem_char_t
);
222 ptem
->tvs_outbuf
= malloc(size
);
223 if (ptem
->tvs_outbuf
== NULL
)
224 panic("out of memory in tem_internal_init()\n");
226 tem_reset_display(ptem
, clear_screen
, init_color
);
228 ptem
->tvs_utf8_left
= 0;
229 ptem
->tvs_utf8_partial
= 0;
231 ptem
->tvs_initialized
= true;
234 * Out of memory is not fatal there, without the screen history,
235 * we can not optimize the screen copy.
237 size
= width
* height
* sizeof (term_char_t
);
238 ptem
->tvs_screen_buf
= malloc(size
);
239 tem_virtual_cls(ptem
, width
* height
, 0, 0);
243 tem_initialized(tem_vt_state_t tem_arg
)
245 struct tem_vt_state
*ptem
= (struct tem_vt_state
*)tem_arg
;
247 return (ptem
->tvs_initialized
);
253 struct tem_vt_state
*ptem
;
255 ptem
= malloc(sizeof (struct tem_vt_state
));
257 return ((tem_vt_state_t
)ptem
);
258 bzero(ptem
, sizeof (*ptem
));
260 ptem
->tvs_isactive
= false;
261 ptem
->tvs_fbmode
= KD_TEXT
;
264 * A tem is regarded as initialized only after tem_internal_init(),
265 * will be set at the end of tem_internal_init().
267 ptem
->tvs_initialized
= 0;
269 if (!tems
.ts_initialized
) {
271 * Only happens during early console configuration.
274 return ((tem_vt_state_t
)ptem
);
277 tem_internal_init(ptem
, B_TRUE
, B_FALSE
);
280 return ((tem_vt_state_t
)ptem
);
284 * re-init the tem after video mode has changed and tems_info has
288 tem_reinit(struct tem_vt_state
*tem
, boolean_t reset_display
)
290 tem_free_buf(tem
); /* only free virtual buffers */
293 tem_internal_init(tem
, B_FALSE
, reset_display
);
297 tem_free_buf(struct tem_vt_state
*tem
)
299 free(tem
->tvs_outbuf
);
300 tem
->tvs_outbuf
= NULL
;
302 free(tem
->tvs_pix_data
);
303 tem
->tvs_pix_data
= NULL
;
305 free(tem
->tvs_screen_buf
);
306 tem
->tvs_screen_buf
= NULL
;
310 tems_failed(boolean_t finish_ioctl
)
312 if (finish_ioctl
&& tems
.ts_hdl
!= NULL
)
313 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, VIS_DEVFINI
, NULL
);
320 * Only called once during boot
323 tem_info_init(struct console
*cp
)
326 struct vis_devinit temargs
;
329 struct tem_vt_state
*p
;
331 if (tems
.ts_initialized
) {
335 list_create(&tems
.ts_list
, sizeof (struct tem_vt_state
),
336 __offsetof(struct tem_vt_state
, tvs_list_node
));
337 tems
.ts_active
= NULL
;
340 bzero(&temargs
, sizeof (temargs
));
341 temargs
.modechg_cb
= (vis_modechg_cb_t
)tems_modechange_callback
;
342 temargs
.modechg_arg
= NULL
;
345 * Initialize the console and get the device parameters
347 if (cp
->c_ioctl(cp
, VIS_DEVINIT
, &temargs
) != 0) {
348 printf("terminal emulator: Compatible fb not found\n");
349 ret
= tems_failed(B_FALSE
);
353 /* Make sure the fb driver and terminal emulator versions match */
354 if (temargs
.version
!= VIS_CONS_REV
) {
356 "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
357 "of console fb driver not supported\n", temargs
.version
);
358 ret
= tems_failed(B_TRUE
);
362 /* other sanity checks */
363 if (!((temargs
.depth
== 4) || (temargs
.depth
== 8) ||
364 (temargs
.depth
== 15) || (temargs
.depth
== 16) ||
365 (temargs
.depth
== 24) || (temargs
.depth
== 32))) {
366 printf("terminal emulator: unsupported depth\n");
367 ret
= tems_failed(B_TRUE
);
371 if ((temargs
.mode
!= VIS_TEXT
) && (temargs
.mode
!= VIS_PIXEL
)) {
372 printf("terminal emulator: unsupported mode\n");
373 ret
= tems_failed(B_TRUE
);
377 plat_tem_get_prom_size(&height
, &width
);
380 * Initialize the common terminal emulator info
382 tems_setup_terminal(&temargs
, height
, width
);
384 tems_reset_colormap();
385 tems_get_initial_color(&tems
.ts_init_color
);
387 tems
.ts_initialized
= 1; /* initialization flag */
389 for (p
= list_head(&tems
.ts_list
); p
!= NULL
;
390 p
= list_next(&tems
.ts_list
, p
)) {
391 tem_internal_init(p
, B_TRUE
, B_FALSE
);
392 if (temargs
.mode
== VIS_PIXEL
)
399 #define TEMS_DEPTH_DIFF 0x01
400 #define TEMS_DIMENSION_DIFF 0x02
403 tems_check_videomode(struct vis_devinit
*tp
)
407 if (tems
.ts_pdepth
!= tp
->depth
)
408 result
|= TEMS_DEPTH_DIFF
;
410 if (tp
->mode
== VIS_TEXT
) {
411 if (tems
.ts_c_dimension
.width
!= tp
->width
||
412 tems
.ts_c_dimension
.height
!= tp
->height
)
413 result
|= TEMS_DIMENSION_DIFF
;
415 if (tems
.ts_p_dimension
.width
!= tp
->width
||
416 tems
.ts_p_dimension
.height
!= tp
->height
)
417 result
|= TEMS_DIMENSION_DIFF
;
419 if (tems
.update_font
== true)
420 result
|= TEMS_DIMENSION_DIFF
;
426 env_screen_nounset(struct env_var
*ev __unused
)
428 if (tems
.ts_p_dimension
.width
== 0 &&
429 tems
.ts_p_dimension
.height
== 0)
435 tems_setup_terminal(struct vis_devinit
*tp
, size_t height
, size_t width
)
437 bitmap_data_t
*font_data
;
441 tems
.ts_pdepth
= tp
->depth
;
442 tems
.ts_linebytes
= tp
->linebytes
;
443 tems
.ts_display_mode
= tp
->mode
;
444 tems
.ts_color_map
= tp
->color_map
;
448 tems
.ts_p_dimension
.width
= 0;
449 tems
.ts_p_dimension
.height
= 0;
450 tems
.ts_c_dimension
.width
= tp
->width
;
451 tems
.ts_c_dimension
.height
= tp
->height
;
452 tems
.ts_callbacks
= &tem_text_callbacks
;
454 snprintf(env
, sizeof (env
), "%d", tems
.ts_c_dimension
.height
);
455 env_setenv("screen-#rows", EV_VOLATILE
| EV_NOHOOK
, env
,
456 env_noset
, env_nounset
);
457 snprintf(env
, sizeof (env
), "%d", tems
.ts_c_dimension
.width
);
458 env_setenv("screen-#cols", EV_VOLATILE
| EV_NOHOOK
, env
,
459 env_noset
, env_nounset
);
461 /* ensure the following are not set for text mode */
462 unsetenv("screen-height");
463 unsetenv("screen-width");
468 * First check to see if the user has specified a screen size.
469 * If so, use those values. Else use 34x80 as the default.
472 width
= TEM_DEFAULT_COLS
;
473 height
= TEM_DEFAULT_ROWS
;
475 tems
.ts_c_dimension
.height
= (screen_size_t
)height
;
476 tems
.ts_c_dimension
.width
= (screen_size_t
)width
;
478 tems
.ts_p_dimension
.height
= tp
->height
;
479 tems
.ts_p_dimension
.width
= tp
->width
;
481 tems
.ts_callbacks
= &tem_pix_callbacks
;
484 * set_font() will select a appropriate sized font for
485 * the number of rows and columns selected. If we don't
486 * have a font that will fit, then it will use the
487 * default builtin font and adjust the rows and columns
488 * to fit on the screen.
490 font_data
= set_font(&tems
.ts_c_dimension
.height
,
491 &tems
.ts_c_dimension
.width
,
492 tems
.ts_p_dimension
.height
,
493 tems
.ts_p_dimension
.width
);
496 * The built in font is compressed, to use it, we
497 * uncompress it into the allocated buffer.
498 * To use loaded font, we assign the loaded buffer.
499 * In case of next load, the previously loaded data
500 * is freed by the process of loading the new font.
502 tems
.update_font
= false;
504 if (tems
.ts_font
.vf_bytes
== NULL
) {
505 for (i
= 0; i
< VFNT_MAPS
; i
++) {
506 tems
.ts_font
.vf_map
[i
] =
507 font_data
->font
->vf_map
[i
];
510 if (font_data
->compressed_size
!= 0) {
512 * We only expect this allocation to
513 * happen at startup, and therefore not to fail.
515 tems
.ts_font
.vf_bytes
=
516 malloc(font_data
->uncompressed_size
);
517 if (tems
.ts_font
.vf_bytes
== NULL
)
518 panic("out of memory\n");
519 (void)lz4_decompress(font_data
->compressed_data
,
520 tems
.ts_font
.vf_bytes
,
521 font_data
->compressed_size
,
522 font_data
->uncompressed_size
, 0);
524 tems
.ts_font
.vf_bytes
=
525 font_data
->font
->vf_bytes
;
527 tems
.ts_font
.vf_width
= font_data
->font
->vf_width
;
528 tems
.ts_font
.vf_height
= font_data
->font
->vf_height
;
529 for (i
= 0; i
< VFNT_MAPS
; i
++) {
530 tems
.ts_font
.vf_map_count
[i
] =
531 font_data
->font
->vf_map_count
[i
];
535 snprintf(env
, sizeof (env
), "%d", tems
.ts_c_dimension
.height
);
536 env_setenv("screen-#rows", EV_VOLATILE
| EV_NOHOOK
, env
,
537 env_noset
, env_nounset
);
538 snprintf(env
, sizeof (env
), "%d", tems
.ts_c_dimension
.width
);
539 env_setenv("screen-#cols", EV_VOLATILE
| EV_NOHOOK
, env
,
540 env_noset
, env_nounset
);
542 snprintf(env
, sizeof (env
), "%d", tems
.ts_p_dimension
.height
);
543 env_setenv("screen-height", EV_VOLATILE
| EV_NOHOOK
, env
,
544 env_noset
, env_screen_nounset
);
545 snprintf(env
, sizeof (env
), "%d", tems
.ts_p_dimension
.width
);
546 env_setenv("screen-width", EV_VOLATILE
| EV_NOHOOK
, env
,
547 env_noset
, env_screen_nounset
);
549 snprintf(env
, sizeof (env
), "%dx%d", tems
.ts_font
.vf_width
,
550 tems
.ts_font
.vf_height
);
551 env_setenv("screen-font", EV_VOLATILE
| EV_NOHOOK
, env
, NULL
,
554 tems
.ts_p_offset
.y
= (tems
.ts_p_dimension
.height
-
555 (tems
.ts_c_dimension
.height
* tems
.ts_font
.vf_height
)) / 2;
556 tems
.ts_p_offset
.x
= (tems
.ts_p_dimension
.width
-
557 (tems
.ts_c_dimension
.width
* tems
.ts_font
.vf_width
)) / 2;
559 tems
.ts_pix_data_size
=
560 tems
.ts_font
.vf_width
* tems
.ts_font
.vf_height
;
562 tems
.ts_pix_data_size
*= 4;
564 tems
.ts_pdepth
= tp
->depth
;
571 * This is a callback function that we register with the frame
572 * buffer driver layered underneath. It gets invoked from
573 * the underlying frame buffer driver to reconfigure the terminal
574 * emulator to a new screen size and depth in conjunction with
575 * framebuffer videomode changes.
576 * Here we keep the foreground/background color and attributes,
577 * which may be different with the initial settings, so that
578 * the color won't change while the framebuffer videomode changes.
579 * And we also reset the kernel terminal emulator and clear the
584 tems_modechange_callback(struct vis_modechg_arg
*arg __unused
,
585 struct vis_devinit
*devinit
)
588 struct tem_vt_state
*p
;
590 tem_modechg_cb_arg_t cb_arg
;
594 diff
= tems_check_videomode(devinit
);
597 * This is color related change, reset color and redraw the
598 * screen. Only need to reinit the active tem.
600 struct tem_vt_state
*active
= tems
.ts_active
;
601 tems_get_initial_color(&tems
.ts_init_color
);
602 active
->tvs_fg_color
= tems
.ts_init_color
.fg_color
;
603 active
->tvs_bg_color
= tems
.ts_init_color
.bg_color
;
604 active
->tvs_flags
= tems
.ts_init_color
.a_flags
;
605 tem_reinit(active
, B_TRUE
);
609 diff
= diff
& TEMS_DIMENSION_DIFF
;
613 * Only need to reinit the active tem.
615 struct tem_vt_state
*active
= tems
.ts_active
;
616 tems
.ts_pdepth
= devinit
->depth
;
617 /* color depth did change, reset colors */
618 tems_reset_colormap();
619 tems_get_initial_color(&tems
.ts_init_color
);
620 tem_reinit(active
, B_TRUE
);
625 plat_tem_get_prom_size(&height
, &width
);
627 tems_setup_terminal(devinit
, height
, width
);
629 tems_reset_colormap();
630 tems_get_initial_color(&tems
.ts_init_color
);
632 for (p
= list_head(&tems
.ts_list
); p
!= NULL
;
633 p
= list_next(&tems
.ts_list
, p
)) {
634 tem_reinit(p
, p
->tvs_isactive
);
638 if (tems
.ts_modechg_cb
== NULL
) {
642 cb
= tems
.ts_modechg_cb
;
643 cb_arg
= tems
.ts_modechg_arg
;
649 * This function is used to clear entire screen via the underlying framebuffer
653 tems_cls(struct vis_consclear
*pda
)
655 if (tems
.ts_hdl
== NULL
)
657 return (tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, VIS_CONSCLEAR
, pda
));
661 * This function is used to display a rectangular blit of data
662 * of a given size and location via the underlying framebuffer driver.
663 * The blit can be as small as a pixel or as large as the screen.
666 tems_display(struct vis_consdisplay
*pda
)
668 if (tems
.ts_hdl
!= NULL
)
669 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, VIS_CONSDISPLAY
, pda
);
673 * This function is used to invoke a block copy operation in the
674 * underlying framebuffer driver. Rectangle copies are how scrolling
675 * is implemented, as well as horizontal text shifting escape seqs.
676 * such as from vi when deleting characters and words.
679 tems_copy(struct vis_conscopy
*pma
)
681 if (tems
.ts_hdl
!= NULL
)
682 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, VIS_CONSCOPY
, pma
);
686 * This function is used to show or hide a rectangluar monochrom
687 * pixel inverting, text block cursor via the underlying framebuffer.
690 tems_cursor(struct vis_conscursor
*pca
)
692 if (tems
.ts_hdl
!= NULL
)
693 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, VIS_CONSCURSOR
, pca
);
697 tem_kdsetmode(int mode
)
699 if (tems
.ts_hdl
!= NULL
)
700 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
, KDSETMODE
,
701 (void *)(intptr_t)mode
);
705 tems_reset_colormap(void)
709 switch (tems
.ts_pdepth
) {
713 /* 8-bits (1/3 of TrueColor 24) */
714 cm
.red
= (uint8_t *)cmap4_to_24
.red
;
715 /* 8-bits (1/3 of TrueColor 24) */
716 cm
.blue
= (uint8_t *)cmap4_to_24
.blue
;
717 /* 8-bits (1/3 of TrueColor 24) */
718 cm
.green
= (uint8_t *)cmap4_to_24
.green
;
719 if (tems
.ts_hdl
!= NULL
)
720 (void) tems
.ts_hdl
->c_ioctl(tems
.ts_hdl
,
727 tem_get_size(uint16_t *r
, uint16_t *c
, uint16_t *x
, uint16_t *y
)
729 *r
= (uint16_t)tems
.ts_c_dimension
.height
;
730 *c
= (uint16_t)tems
.ts_c_dimension
.width
;
731 *x
= (uint16_t)tems
.ts_p_dimension
.width
;
732 *y
= (uint16_t)tems
.ts_p_dimension
.height
;
736 * Loader extension. Store important data in environment. Intended to be used
737 * just before booting the OS to make the data available in kernel
738 * environment module.
743 struct tem_vt_state
*active
= tems
.ts_active
;
747 * We already have in environment:
748 * tem.inverse, tem.inverse_screen
749 * tem.fg_color, tem.bg_color.
750 * So we only need to add the position of the cursor.
753 if (active
!= NULL
) {
754 snprintf(buf
, sizeof (buf
), "%d", active
->tvs_c_cursor
.col
);
755 setenv("tem.cursor.col", buf
, 1);
756 snprintf(buf
, sizeof (buf
), "%d", active
->tvs_c_cursor
.row
);
757 setenv("tem.cursor.row", buf
, 1);
762 tem_register_modechg_cb(tem_modechg_cb_t func
, tem_modechg_cb_arg_t arg
)
764 tems
.ts_modechg_cb
= func
;
765 tems
.ts_modechg_arg
= arg
;
769 * This function is to scroll up the OBP output, which has
770 * different screen height and width with our kernel console.
773 tem_prom_scroll_up(struct tem_vt_state
*tem
, int nrows
)
775 struct vis_conscopy ma
;
779 ma
.s_row
= nrows
* tems
.ts_font
.vf_height
;
780 ma
.e_row
= tems
.ts_p_dimension
.height
- 1;
784 ma
.e_col
= tems
.ts_p_dimension
.width
- 1;
790 width
= tems
.ts_font
.vf_width
;
791 ncols
= (tems
.ts_p_dimension
.width
+ (width
- 1))/ width
;
793 tem_pix_cls_range(tem
, 0, nrows
, tems
.ts_p_offset
.y
,
794 0, ncols
, 0, B_TRUE
);
798 * This function is to compute the starting row of the console, according to
799 * PROM cursor's position. Here we have to take different fonts into account.
802 tem_adjust_row(struct tem_vt_state
*tem
, int prom_row
)
806 int prom_charheight
= 0;
807 int prom_window_top
= 0;
810 plat_tem_get_prom_font_size(&prom_charheight
, &prom_window_top
);
811 if (prom_charheight
== 0)
812 prom_charheight
= tems
.ts_font
.vf_height
;
814 tem_y
= (prom_row
+ 1) * prom_charheight
+ prom_window_top
-
816 tem_row
= (tem_y
+ tems
.ts_font
.vf_height
- 1) /
817 tems
.ts_font
.vf_height
- 1;
821 } else if (tem_row
>= (tems
.ts_c_dimension
.height
- 1)) {
823 * Scroll up the prom outputs if the PROM cursor's position is
824 * below our tem's lower boundary.
826 scroll_up_lines
= tem_row
-
827 (tems
.ts_c_dimension
.height
- 1);
828 tem_prom_scroll_up(tem
, scroll_up_lines
);
829 tem_row
= tems
.ts_c_dimension
.height
- 1;
836 tem_pix_align(struct tem_vt_state
*tem
)
841 if (plat_stdout_is_framebuffer()) {
842 plat_tem_hide_prom_cursor();
845 * We are getting the current cursor position in pixel
846 * mode so that we don't over-write the console output
849 plat_tem_get_prom_pos(&row
, &col
);
852 * Adjust the row if necessary when the font of our
853 * kernel console tem is different with that of prom
856 row
= tem_adjust_row(tem
, row
);
858 /* first line of our kernel console output */
859 tem
->tvs_first_line
= row
+ 1;
861 /* re-set and align cursor position */
862 tem
->tvs_s_cursor
.row
= tem
->tvs_c_cursor
.row
=
864 tem
->tvs_s_cursor
.col
= tem
->tvs_c_cursor
.col
= 0;
866 tem_reset_display(tem
, B_TRUE
, B_TRUE
);
871 tems_get_inverses(boolean_t
*p_inverse
, boolean_t
*p_inverse_screen
)
874 int i_inverse_screen
= 0;
876 plat_tem_get_inverses(&i_inverse
, &i_inverse_screen
);
878 *p_inverse
= (i_inverse
== 0) ? B_FALSE
: B_TRUE
;
879 *p_inverse_screen
= (i_inverse_screen
== 0) ? B_FALSE
: B_TRUE
;
883 * Get the foreground/background color and attributes from environment.
886 tems_get_initial_color(tem_color_t
*pcolor
)
888 boolean_t inverse
, inverse_screen
;
889 unsigned short flags
= 0;
891 pcolor
->fg_color
= DEFAULT_ANSI_FOREGROUND
;
892 pcolor
->bg_color
= DEFAULT_ANSI_BACKGROUND
;
893 plat_tem_get_colors(&pcolor
->fg_color
, &pcolor
->bg_color
);
895 tems_get_inverses(&inverse
, &inverse_screen
);
897 flags
|= TEM_ATTR_REVERSE
;
899 flags
|= TEM_ATTR_SCREEN_REVERSE
;
902 * In case of black on white we want bright white for BG.
903 * In case if white on black, to improve readability,
904 * we want bold white.
908 * If either reverse flag is set, the screen is in
909 * white-on-black mode. We set the bold flag to
910 * improve readability.
912 flags
|= TEM_ATTR_BOLD
;
915 * Otherwise, the screen is in black-on-white mode.
916 * The SPARC PROM console, which starts in this mode,
917 * uses the bright white background colour so we
920 if (pcolor
->bg_color
== ANSI_COLOR_WHITE
)
921 flags
|= TEM_ATTR_BRIGHT_BG
;
924 pcolor
->a_flags
= flags
;
928 tem_activate(tem_vt_state_t tem_arg
, boolean_t unblank
)
930 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
932 tems
.ts_active
= tem
;
933 tem
->tvs_isactive
= true;
935 tem_kdsetmode(tem
->tvs_fbmode
);
942 tem_check_first_time(struct tem_vt_state
*tem
)
944 static int first_time
= 1;
947 * Realign the console cursor. We did this in tem_init().
948 * However, drivers in the console stream may emit additional
949 * messages before we are ready. This causes text overwrite
950 * on the screen. This is a workaround.
956 if (tems
.ts_display_mode
== VIS_TEXT
)
957 tem_text_cursor(tem
, VIS_GET_CURSOR
);
959 tem_pix_cursor(tem
, VIS_GET_CURSOR
);
960 tem_align_cursor(tem
);
963 /* Process partial UTF-8 sequence. */
965 tem_input_partial(struct tem_vt_state
*tem
)
970 if (tem
->tvs_utf8_left
== 0)
973 for (i
= 0; i
< sizeof (tem
->tvs_utf8_partial
); i
++) {
974 c
= (tem
->tvs_utf8_partial
>> (24 - (i
<< 3))) & 0xff;
979 tem
->tvs_utf8_left
= 0;
980 tem
->tvs_utf8_partial
= 0;
984 * Handle UTF-8 sequences.
987 tem_input_byte(struct tem_vt_state
*tem
, uint8_t c
)
990 * Check for UTF-8 code points. In case of error fall back to
991 * 8-bit code. As we only have 8859-1 fonts for console, this will set
992 * the limits on what chars we actually can display, therefore we
993 * have to return to this code once we have solved the font issue.
995 if ((c
& 0x80) == 0x00) {
996 /* One-byte sequence. */
997 tem_input_partial(tem
);
1001 if ((c
& 0xe0) == 0xc0) {
1002 /* Two-byte sequence. */
1003 tem_input_partial(tem
);
1004 tem
->tvs_utf8_left
= 1;
1005 tem
->tvs_utf8_partial
= c
;
1008 if ((c
& 0xf0) == 0xe0) {
1009 /* Three-byte sequence. */
1010 tem_input_partial(tem
);
1011 tem
->tvs_utf8_left
= 2;
1012 tem
->tvs_utf8_partial
= c
;
1015 if ((c
& 0xf8) == 0xf0) {
1016 /* Four-byte sequence. */
1017 tem_input_partial(tem
);
1018 tem
->tvs_utf8_left
= 3;
1019 tem
->tvs_utf8_partial
= c
;
1022 if ((c
& 0xc0) == 0x80) {
1023 /* Invalid state? */
1024 if (tem
->tvs_utf8_left
== 0) {
1028 tem
->tvs_utf8_left
--;
1029 tem
->tvs_utf8_partial
= (tem
->tvs_utf8_partial
<< 8) | c
;
1030 if (tem
->tvs_utf8_left
== 0) {
1035 * Transform the sequence of 2 to 4 bytes to
1039 u
= tem
->tvs_utf8_partial
;
1040 b
= (u
>> 24) & 0xff;
1041 if (b
!= 0) { /* Four-byte sequence */
1043 b
= (u
>> 16) & 0xff;
1044 v
= (v
<< 6) | (b
& 0x3f);
1045 b
= (u
>> 8) & 0xff;
1046 v
= (v
<< 6) | (b
& 0x3f);
1048 v
= (v
<< 6) | (b
& 0x3f);
1049 } else if ((b
= (u
>> 16) & 0xff) != 0) {
1050 v
= b
& 0x0f; /* Three-byte sequence */
1051 b
= (u
>> 8) & 0xff;
1052 v
= (v
<< 6) | (b
& 0x3f);
1054 v
= (v
<< 6) | (b
& 0x3f);
1055 } else if ((b
= (u
>> 8) & 0xff) != 0) {
1056 v
= b
& 0x1f; /* Two-byte sequence */
1058 v
= (v
<< 6) | (b
& 0x3f);
1062 tem
->tvs_utf8_partial
= 0;
1066 /* Anything left is illegal in UTF-8 sequence. */
1067 tem_input_partial(tem
);
1072 * This is the main entry point into the terminal emulator.
1074 * For each data message coming downstream, ANSI assumes that it is composed
1075 * of ASCII characters, which are treated as a byte-stream input to the
1076 * parsing state machine. All data is parsed immediately -- there is
1080 tem_terminal_emulate(struct tem_vt_state
*tem
, uint8_t *buf
, int len
)
1082 if (tem
->tvs_isactive
)
1083 tem_callback_cursor(tem
, VIS_HIDE_CURSOR
);
1085 for (; len
> 0; len
--, buf
++)
1086 tem_input_byte(tem
, *buf
);
1089 * Send the data we just got to the framebuffer.
1093 if (tem
->tvs_isactive
)
1094 tem_callback_cursor(tem
, VIS_DISPLAY_CURSOR
);
1098 * send the appropriate control message or set state based on the
1099 * value of the control character ch
1103 tem_control(struct tem_vt_state
*tem
, uint8_t ch
)
1105 tem
->tvs_state
= A_STATE_START
;
1113 tem
->tvs_c_cursor
.row
,
1114 tem
->tvs_c_cursor
.col
- 1);
1123 * tem_send_data(tem, credp, called_from);
1124 * tem_new_line(tem, credp, called_from);
1144 tem
->tvs_state
= A_STATE_ESC
;
1150 tem
->tvs_curparam
= 0;
1151 tem
->tvs_paramval
= 0;
1152 tem
->tvs_gotparam
= B_FALSE
;
1153 /* clear the parameters */
1154 for (i
= 0; i
< TEM_MAXPARAMS
; i
++)
1155 tem
->tvs_params
[i
] = -1;
1156 tem
->tvs_state
= A_STATE_CSI
;
1171 * if parameters [0..count - 1] are not set, set them to the value
1176 tem_setparam(struct tem_vt_state
*tem
, int count
, int newparam
)
1180 for (i
= 0; i
< count
; i
++) {
1181 if (tem
->tvs_params
[i
] == -1)
1182 tem
->tvs_params
[i
] = newparam
;
1188 * select graphics mode based on the param vals stored in a_params
1191 tem_selgraph(struct tem_vt_state
*tem
)
1197 tem
->tvs_state
= A_STATE_START
;
1199 curparam
= tem
->tvs_curparam
;
1201 param
= tem
->tvs_params
[count
];
1206 /* reset to initial normal settings */
1207 tem
->tvs_fg_color
= tems
.ts_init_color
.fg_color
;
1208 tem
->tvs_bg_color
= tems
.ts_init_color
.bg_color
;
1209 tem
->tvs_flags
= tems
.ts_init_color
.a_flags
;
1212 case 1: /* Bold Intense */
1213 tem
->tvs_flags
|= TEM_ATTR_BOLD
;
1216 case 2: /* Faint Intense */
1217 tem
->tvs_flags
&= ~TEM_ATTR_BOLD
;
1220 case 4: /* Underline */
1221 tem
->tvs_flags
|= TEM_ATTR_UNDERLINE
;
1225 tem
->tvs_flags
|= TEM_ATTR_BLINK
;
1228 case 7: /* Reverse video */
1229 if (tem
->tvs_flags
& TEM_ATTR_SCREEN_REVERSE
) {
1230 tem
->tvs_flags
&= ~TEM_ATTR_REVERSE
;
1232 tem
->tvs_flags
|= TEM_ATTR_REVERSE
;
1236 case 22: /* Remove Bold */
1237 tem
->tvs_flags
&= ~TEM_ATTR_BOLD
;
1240 case 24: /* Remove Underline */
1241 tem
->tvs_flags
&= ~TEM_ATTR_UNDERLINE
;
1244 case 25: /* Remove Blink */
1245 tem
->tvs_flags
&= ~TEM_ATTR_BLINK
;
1248 case 27: /* Remove Reverse */
1249 if (tem
->tvs_flags
& TEM_ATTR_SCREEN_REVERSE
) {
1250 tem
->tvs_flags
|= TEM_ATTR_REVERSE
;
1252 tem
->tvs_flags
&= ~TEM_ATTR_REVERSE
;
1256 case 30: /* black (grey) foreground */
1257 case 31: /* red (light red) foreground */
1258 case 32: /* green (light green) foreground */
1259 case 33: /* brown (yellow) foreground */
1260 case 34: /* blue (light blue) foreground */
1261 case 35: /* magenta (light magenta) foreground */
1262 case 36: /* cyan (light cyan) foreground */
1263 case 37: /* white (bright white) foreground */
1264 tem
->tvs_fg_color
= param
- 30;
1265 tem
->tvs_flags
&= ~TEM_ATTR_BRIGHT_FG
;
1270 * Reset the foreground colour and brightness.
1272 tem
->tvs_fg_color
= tems
.ts_init_color
.fg_color
;
1273 if (tems
.ts_init_color
.a_flags
& TEM_ATTR_BRIGHT_FG
)
1274 tem
->tvs_flags
|= TEM_ATTR_BRIGHT_FG
;
1276 tem
->tvs_flags
&= ~TEM_ATTR_BRIGHT_FG
;
1279 case 40: /* black (grey) background */
1280 case 41: /* red (light red) background */
1281 case 42: /* green (light green) background */
1282 case 43: /* brown (yellow) background */
1283 case 44: /* blue (light blue) background */
1284 case 45: /* magenta (light magenta) background */
1285 case 46: /* cyan (light cyan) background */
1286 case 47: /* white (bright white) background */
1287 tem
->tvs_bg_color
= param
- 40;
1288 tem
->tvs_flags
&= ~TEM_ATTR_BRIGHT_BG
;
1293 * Reset the background colour and brightness.
1295 tem
->tvs_bg_color
= tems
.ts_init_color
.bg_color
;
1296 if (tems
.ts_init_color
.a_flags
& TEM_ATTR_BRIGHT_BG
)
1297 tem
->tvs_flags
|= TEM_ATTR_BRIGHT_BG
;
1299 tem
->tvs_flags
&= ~TEM_ATTR_BRIGHT_BG
;
1302 case 90: /* black (grey) foreground */
1303 case 91: /* red (light red) foreground */
1304 case 92: /* green (light green) foreground */
1305 case 93: /* brown (yellow) foreground */
1306 case 94: /* blue (light blue) foreground */
1307 case 95: /* magenta (light magenta) foreground */
1308 case 96: /* cyan (light cyan) foreground */
1309 case 97: /* white (bright white) foreground */
1310 tem
->tvs_fg_color
= param
- 90;
1311 tem
->tvs_flags
|= TEM_ATTR_BRIGHT_FG
;
1314 case 100: /* black (grey) background */
1315 case 101: /* red (light red) background */
1316 case 102: /* green (light green) background */
1317 case 103: /* brown (yellow) background */
1318 case 104: /* blue (light blue) background */
1319 case 105: /* magenta (light magenta) background */
1320 case 106: /* cyan (light cyan) background */
1321 case 107: /* white (bright white) background */
1322 tem
->tvs_bg_color
= param
- 100;
1323 tem
->tvs_flags
|= TEM_ATTR_BRIGHT_BG
;
1332 } while (curparam
> 0);
1336 * perform the appropriate action for the escape sequence
1338 * General rule: This code does not validate the arguments passed.
1339 * It assumes that the next lower level will do so.
1342 tem_chkparam(struct tem_vt_state
*tem
, uint8_t ch
)
1348 row
= tem
->tvs_c_cursor
.row
;
1349 col
= tem
->tvs_c_cursor
.col
;
1353 case 'm': /* select terminal graphics mode */
1358 case '@': /* insert char */
1359 tem_setparam(tem
, 1, 1);
1360 tem_shift(tem
, tem
->tvs_params
[0], TEM_SHIFT_RIGHT
);
1363 case 'A': /* cursor up */
1364 tem_setparam(tem
, 1, 1);
1365 tem_mv_cursor(tem
, row
- tem
->tvs_params
[0], col
);
1368 case 'd': /* VPA - vertical position absolute */
1369 tem_setparam(tem
, 1, 1);
1370 tem_mv_cursor(tem
, tem
->tvs_params
[0] - 1, col
);
1373 case 'e': /* VPR - vertical position relative */
1374 case 'B': /* cursor down */
1375 tem_setparam(tem
, 1, 1);
1376 tem_mv_cursor(tem
, row
+ tem
->tvs_params
[0], col
);
1379 case 'a': /* HPR - horizontal position relative */
1380 case 'C': /* cursor right */
1381 tem_setparam(tem
, 1, 1);
1382 tem_mv_cursor(tem
, row
, col
+ tem
->tvs_params
[0]);
1385 case '`': /* HPA - horizontal position absolute */
1386 tem_setparam(tem
, 1, 1);
1387 tem_mv_cursor(tem
, row
, tem
->tvs_params
[0] - 1);
1390 case 'D': /* cursor left */
1391 tem_setparam(tem
, 1, 1);
1392 tem_mv_cursor(tem
, row
, col
- tem
->tvs_params
[0]);
1395 case 'E': /* CNL cursor next line */
1396 tem_setparam(tem
, 1, 1);
1397 tem_mv_cursor(tem
, row
+ tem
->tvs_params
[0], 0);
1400 case 'F': /* CPL cursor previous line */
1401 tem_setparam(tem
, 1, 1);
1402 tem_mv_cursor(tem
, row
- tem
->tvs_params
[0], 0);
1405 case 'G': /* cursor horizontal position */
1406 tem_setparam(tem
, 1, 1);
1407 tem_mv_cursor(tem
, row
, tem
->tvs_params
[0] - 1);
1410 case 'g': /* clear tabs */
1411 tem_setparam(tem
, 1, 0);
1412 tem_clear_tabs(tem
, tem
->tvs_params
[0]);
1415 case 'f': /* HVP Horizontal and Vertical Position */
1416 case 'H': /* CUP position cursor */
1417 tem_setparam(tem
, 2, 1);
1419 tem
->tvs_params
[0] - 1, tem
->tvs_params
[1] - 1);
1422 case 'I': /* CHT - Cursor Horizontal Tab */
1423 /* Not implemented */
1426 case 'J': /* ED - Erase in Display */
1428 tem_setparam(tem
, 1, 0);
1429 switch (tem
->tvs_params
[0]) {
1431 /* erase cursor to end of screen */
1432 /* FIRST erase cursor to end of line */
1433 tem_clear_chars(tem
,
1434 tems
.ts_c_dimension
.width
-
1435 tem
->tvs_c_cursor
.col
,
1436 tem
->tvs_c_cursor
.row
,
1437 tem
->tvs_c_cursor
.col
);
1439 /* THEN erase lines below the cursor */
1440 for (row
= tem
->tvs_c_cursor
.row
+ 1;
1441 row
< tems
.ts_c_dimension
.height
;
1443 tem_clear_chars(tem
,
1444 tems
.ts_c_dimension
.width
, row
, 0);
1449 /* erase beginning of screen to cursor */
1450 /* FIRST erase lines above the cursor */
1452 row
< tem
->tvs_c_cursor
.row
;
1454 tem_clear_chars(tem
,
1455 tems
.ts_c_dimension
.width
, row
, 0);
1457 /* THEN erase beginning of line to cursor */
1458 tem_clear_chars(tem
,
1459 tem
->tvs_c_cursor
.col
+ 1,
1460 tem
->tvs_c_cursor
.row
, 0);
1464 /* erase whole screen */
1466 row
< tems
.ts_c_dimension
.height
;
1468 tem_clear_chars(tem
,
1469 tems
.ts_c_dimension
.width
, row
, 0);
1475 case 'K': /* EL - Erase in Line */
1477 tem_setparam(tem
, 1, 0);
1478 switch (tem
->tvs_params
[0]) {
1480 /* erase cursor to end of line */
1481 tem_clear_chars(tem
,
1482 (tems
.ts_c_dimension
.width
-
1483 tem
->tvs_c_cursor
.col
),
1484 tem
->tvs_c_cursor
.row
,
1485 tem
->tvs_c_cursor
.col
);
1489 /* erase beginning of line to cursor */
1490 tem_clear_chars(tem
,
1491 tem
->tvs_c_cursor
.col
+ 1,
1492 tem
->tvs_c_cursor
.row
, 0);
1496 /* erase whole line */
1497 tem_clear_chars(tem
,
1498 tems
.ts_c_dimension
.width
,
1499 tem
->tvs_c_cursor
.row
, 0);
1504 case 'L': /* insert line */
1506 tem_setparam(tem
, 1, 1);
1508 tem
->tvs_c_cursor
.row
,
1509 tems
.ts_c_dimension
.height
- 1,
1510 tem
->tvs_params
[0], TEM_SCROLL_DOWN
);
1513 case 'M': /* delete line */
1515 tem_setparam(tem
, 1, 1);
1517 tem
->tvs_c_cursor
.row
,
1518 tems
.ts_c_dimension
.height
- 1,
1519 tem
->tvs_params
[0], TEM_SCROLL_UP
);
1522 case 'P': /* DCH - delete char */
1523 tem_setparam(tem
, 1, 1);
1524 tem_shift(tem
, tem
->tvs_params
[0], TEM_SHIFT_LEFT
);
1527 case 'S': /* scroll up */
1529 tem_setparam(tem
, 1, 1);
1531 tems
.ts_c_dimension
.height
- 1,
1532 tem
->tvs_params
[0], TEM_SCROLL_UP
);
1535 case 'T': /* scroll down */
1537 tem_setparam(tem
, 1, 1);
1539 tems
.ts_c_dimension
.height
- 1,
1540 tem
->tvs_params
[0], TEM_SCROLL_DOWN
);
1543 case 'X': /* erase char */
1544 tem_setparam(tem
, 1, 1);
1545 tem_clear_chars(tem
,
1547 tem
->tvs_c_cursor
.row
,
1548 tem
->tvs_c_cursor
.col
);
1551 case 'Z': /* cursor backward tabulation */
1552 tem_setparam(tem
, 1, 1);
1555 * Rule exception - We do sanity checking here.
1557 * Restrict the count to a sane value to keep from
1558 * looping for a long time. There can't be more than one
1559 * tab stop per column, so use that as a limit.
1561 if (tem
->tvs_params
[0] > tems
.ts_c_dimension
.width
)
1562 tem
->tvs_params
[0] = tems
.ts_c_dimension
.width
;
1564 for (i
= 0; i
< tem
->tvs_params
[0]; i
++)
1568 tem
->tvs_state
= A_STATE_START
;
1573 * Gather the parameters of an ANSI escape sequence
1576 tem_getparams(struct tem_vt_state
*tem
, uint8_t ch
)
1578 if (ch
>= '0' && ch
<= '9') {
1579 tem
->tvs_paramval
= ((tem
->tvs_paramval
* 10) + (ch
- '0'));
1580 tem
->tvs_gotparam
= B_TRUE
; /* Remember got parameter */
1581 return; /* Return immediately */
1582 } else if (tem
->tvs_state
== A_STATE_CSI_EQUAL
||
1583 tem
->tvs_state
== A_STATE_CSI_QMARK
) {
1584 tem
->tvs_state
= A_STATE_START
;
1586 if (tem
->tvs_curparam
< TEM_MAXPARAMS
) {
1587 if (tem
->tvs_gotparam
) {
1588 /* get the parameter value */
1589 tem
->tvs_params
[tem
->tvs_curparam
] =
1592 tem
->tvs_curparam
++;
1596 /* Restart parameter search */
1597 tem
->tvs_gotparam
= B_FALSE
;
1598 tem
->tvs_paramval
= 0; /* No parame value yet */
1600 /* Handle escape sequence */
1601 tem_chkparam(tem
, ch
);
1607 * Add character to internal buffer.
1608 * When its full, send it to the next layer.
1611 tem_outch(struct tem_vt_state
*tem
, tem_char_t ch
)
1617 /* buffer up the character until later */
1618 tem_get_attr(tem
, &fg
, &bg
, &attr
, TEM_ATTR_REVERSE
);
1619 tem
->tvs_outbuf
[tem
->tvs_outindex
].tc_char
= ch
| TEM_ATTR(attr
);
1620 tem
->tvs_outbuf
[tem
->tvs_outindex
].tc_fg_color
= fg
;
1621 tem
->tvs_outbuf
[tem
->tvs_outindex
].tc_bg_color
= bg
;
1622 tem
->tvs_outindex
++;
1623 tem
->tvs_c_cursor
.col
++;
1624 if (tem
->tvs_c_cursor
.col
>= tems
.ts_c_dimension
.width
) {
1631 tem_new_line(struct tem_vt_state
*tem
)
1638 tem_cr(struct tem_vt_state
*tem
)
1640 tem
->tvs_c_cursor
.col
= 0;
1641 tem_align_cursor(tem
);
1645 tem_lf(struct tem_vt_state
*tem
)
1650 * Sanity checking notes:
1651 * . a_nscroll was validated when it was set.
1652 * . Regardless of that, tem_scroll and tem_mv_cursor
1653 * will prevent anything bad from happening.
1655 row
= tem
->tvs_c_cursor
.row
+ 1;
1657 if (row
>= tems
.ts_c_dimension
.height
) {
1658 if (tem
->tvs_nscroll
!= 0) {
1660 tems
.ts_c_dimension
.height
- 1,
1661 tem
->tvs_nscroll
, TEM_SCROLL_UP
);
1662 row
= tems
.ts_c_dimension
.height
-
1664 } else { /* no scroll */
1666 * implement Esc[#r when # is zero. This means no
1667 * scroll but just return cursor to top of screen,
1668 * do not clear screen.
1674 tem_mv_cursor(tem
, row
, tem
->tvs_c_cursor
.col
);
1676 if (tem
->tvs_nscroll
== 0) {
1677 /* erase rest of cursor line */
1678 tem_clear_chars(tem
,
1679 tems
.ts_c_dimension
.width
-
1680 tem
->tvs_c_cursor
.col
,
1681 tem
->tvs_c_cursor
.row
,
1682 tem
->tvs_c_cursor
.col
);
1686 tem_align_cursor(tem
);
1690 tem_send_data(struct tem_vt_state
*tem
)
1692 if (tem
->tvs_outindex
== 0) {
1693 tem_align_cursor(tem
);
1697 tem_virtual_display(tem
, tem
->tvs_outbuf
, tem
->tvs_outindex
,
1698 tem
->tvs_s_cursor
.row
, tem
->tvs_s_cursor
.col
);
1700 if (tem
->tvs_isactive
) {
1702 * Call the primitive to render this data.
1704 tem_callback_display(tem
,
1705 tem
->tvs_outbuf
, tem
->tvs_outindex
,
1706 tem
->tvs_s_cursor
.row
, tem
->tvs_s_cursor
.col
);
1709 tem
->tvs_outindex
= 0;
1711 tem_align_cursor(tem
);
1716 * We have just done something to the current output point. Reset the start
1717 * point for the buffered data in a_outbuf. There shouldn't be any data
1721 tem_align_cursor(struct tem_vt_state
*tem
)
1723 tem
->tvs_s_cursor
.row
= tem
->tvs_c_cursor
.row
;
1724 tem
->tvs_s_cursor
.col
= tem
->tvs_c_cursor
.col
;
1728 * State machine parser based on the current state and character input
1729 * major terminations are to control character or normal character
1733 tem_parse(struct tem_vt_state
*tem
, tem_char_t ch
)
1737 if (tem
->tvs_state
== A_STATE_START
) { /* Normal state? */
1738 if (ch
== A_CSI
|| ch
== A_ESC
|| ch
< ' ') {
1740 tem_control(tem
, ch
);
1748 /* In <ESC> sequence */
1749 if (tem
->tvs_state
!= A_STATE_ESC
) { /* Need to get parameters? */
1750 if (tem
->tvs_state
!= A_STATE_CSI
) {
1751 tem_getparams(tem
, ch
);
1757 tem
->tvs_state
= A_STATE_CSI_QMARK
;
1760 tem
->tvs_state
= A_STATE_CSI_EQUAL
;
1764 * As defined below, this sequence
1765 * saves the cursor. However, Sun
1766 * defines ESC[s as reset. We resolved
1767 * the conflict by selecting reset as it
1768 * is exported in the termcap file for
1769 * sun-mon, while the "save cursor"
1770 * definition does not exist anywhere in
1772 * However, having no coherent
1773 * definition of reset, we have not
1779 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1780 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1781 * tem->tvs_state = A_STATE_START;
1784 tem
->tvs_state
= A_STATE_START
;
1787 tem_mv_cursor(tem
, tem
->tvs_r_cursor
.row
,
1788 tem
->tvs_r_cursor
.col
);
1789 tem
->tvs_state
= A_STATE_START
;
1791 case 'p': /* sunbow */
1794 * Don't set anything if we are
1795 * already as we want to be.
1797 if (tem
->tvs_flags
& TEM_ATTR_SCREEN_REVERSE
) {
1798 tem
->tvs_flags
&= ~TEM_ATTR_SCREEN_REVERSE
;
1800 * If we have switched the characters to be the
1801 * inverse from the screen, then switch them as
1802 * well to keep them the inverse of the screen.
1804 if (tem
->tvs_flags
& TEM_ATTR_REVERSE
)
1805 tem
->tvs_flags
&= ~TEM_ATTR_REVERSE
;
1807 tem
->tvs_flags
|= TEM_ATTR_REVERSE
;
1810 tem
->tvs_state
= A_STATE_START
;
1812 case 'q': /* sunwob */
1815 * Don't set anything if we are
1816 * already where as we want to be.
1818 if (!(tem
->tvs_flags
& TEM_ATTR_SCREEN_REVERSE
)) {
1819 tem
->tvs_flags
|= TEM_ATTR_SCREEN_REVERSE
;
1821 * If we have switched the characters to be the
1822 * inverse from the screen, then switch them as
1823 * well to keep them the inverse of the screen.
1825 if (!(tem
->tvs_flags
& TEM_ATTR_REVERSE
))
1826 tem
->tvs_flags
|= TEM_ATTR_REVERSE
;
1828 tem
->tvs_flags
&= ~TEM_ATTR_REVERSE
;
1832 tem
->tvs_state
= A_STATE_START
;
1834 case 'r': /* sunscrl */
1836 * Rule exception: check for validity here.
1838 tem
->tvs_nscroll
= tem
->tvs_paramval
;
1839 if (tem
->tvs_nscroll
> tems
.ts_c_dimension
.height
)
1840 tem
->tvs_nscroll
= tems
.ts_c_dimension
.height
;
1841 if (tem
->tvs_nscroll
< 0)
1842 tem
->tvs_nscroll
= 1;
1843 tem
->tvs_state
= A_STATE_START
;
1846 tem_getparams(tem
, ch
);
1851 /* Previous char was <ESC> */
1853 tem
->tvs_curparam
= 0;
1854 tem
->tvs_paramval
= 0;
1855 tem
->tvs_gotparam
= B_FALSE
;
1856 /* clear the parameters */
1857 for (i
= 0; i
< TEM_MAXPARAMS
; i
++)
1858 tem
->tvs_params
[i
] = -1;
1859 tem
->tvs_state
= A_STATE_CSI
;
1860 } else if (ch
== 'Q') { /* <ESC>Q ? */
1861 tem
->tvs_state
= A_STATE_START
;
1862 } else if (ch
== 'C') { /* <ESC>C ? */
1863 tem
->tvs_state
= A_STATE_START
;
1865 tem
->tvs_state
= A_STATE_START
;
1867 /* ESC c resets display */
1868 tem_reset_display(tem
, B_TRUE
, B_TRUE
);
1869 } else if (ch
== 'H') {
1870 /* ESC H sets a tab */
1872 } else if (ch
== '7') {
1873 /* ESC 7 Save Cursor position */
1874 tem
->tvs_r_cursor
.row
= tem
->tvs_c_cursor
.row
;
1875 tem
->tvs_r_cursor
.col
= tem
->tvs_c_cursor
.col
;
1876 } else if (ch
== '8') {
1877 /* ESC 8 Restore Cursor position */
1878 tem_mv_cursor(tem
, tem
->tvs_r_cursor
.row
,
1879 tem
->tvs_r_cursor
.col
);
1880 /* check for control chars */
1881 } else if (ch
< ' ') {
1882 tem_control(tem
, ch
);
1891 tem_bell(struct tem_vt_state
*tem __unused
)
1893 /* (void) beep(BEEP_CONSOLE); */
1898 tem_scroll(struct tem_vt_state
*tem
, int start
, int end
, int count
,
1904 lines_affected
= end
- start
+ 1;
1905 if (count
> lines_affected
)
1906 count
= lines_affected
;
1910 switch (direction
) {
1912 if (count
< lines_affected
) {
1913 tem_copy_area(tem
, 0, start
+ count
,
1914 tems
.ts_c_dimension
.width
- 1, end
, 0, start
);
1916 for (row
= (end
- count
) + 1; row
<= end
; row
++) {
1917 tem_clear_chars(tem
, tems
.ts_c_dimension
.width
, row
, 0);
1921 case TEM_SCROLL_DOWN
:
1922 if (count
< lines_affected
) {
1923 tem_copy_area(tem
, 0, start
,
1924 tems
.ts_c_dimension
.width
- 1,
1925 end
- count
, 0, start
+ count
);
1927 for (row
= start
; row
< start
+ count
; row
++) {
1928 tem_clear_chars(tem
, tems
.ts_c_dimension
.width
, row
, 0);
1935 tem_copy_width(term_char_t
*src
, term_char_t
*dst
, int cols
)
1937 int width
= cols
- 1;
1939 while (width
>= 0) {
1940 /* We do not have image bits to compare, stop there. */
1941 if (TEM_CHAR_ATTR(src
[width
].tc_char
) == TEM_ATTR_IMAGE
||
1942 TEM_CHAR_ATTR(dst
[width
].tc_char
) == TEM_ATTR_IMAGE
)
1946 * Find difference on line, compare char with its attributes
1949 if (src
[width
].tc_char
!= dst
[width
].tc_char
||
1950 src
[width
].tc_fg_color
!= dst
[width
].tc_fg_color
||
1951 src
[width
].tc_bg_color
!= dst
[width
].tc_bg_color
) {
1960 tem_copy_area(struct tem_vt_state
*tem
,
1961 screen_pos_t s_col
, screen_pos_t s_row
,
1962 screen_pos_t e_col
, screen_pos_t e_row
,
1963 screen_pos_t t_col
, screen_pos_t t_row
)
1965 size_t soffset
, toffset
;
1966 term_char_t
*src
, *dst
;
1970 if (s_col
< 0 || s_row
< 0 ||
1971 e_col
< 0 || e_row
< 0 ||
1972 t_col
< 0 || t_row
< 0 ||
1973 s_col
>= tems
.ts_c_dimension
.width
||
1974 e_col
>= tems
.ts_c_dimension
.width
||
1975 t_col
>= tems
.ts_c_dimension
.width
||
1976 s_row
>= tems
.ts_c_dimension
.height
||
1977 e_row
>= tems
.ts_c_dimension
.height
||
1978 t_row
>= tems
.ts_c_dimension
.height
)
1981 if (s_row
> e_row
|| s_col
> e_col
)
1984 rows
= e_row
- s_row
+ 1;
1985 cols
= e_col
- s_col
+ 1;
1986 if (t_row
+ rows
> tems
.ts_c_dimension
.height
||
1987 t_col
+ cols
> tems
.ts_c_dimension
.width
)
1990 if (tem
->tvs_screen_buf
== NULL
) {
1991 if (tem
->tvs_isactive
) {
1992 tem_callback_copy(tem
, s_col
, s_row
,
1993 e_col
, e_row
, t_col
, t_row
);
1998 soffset
= s_col
+ s_row
* tems
.ts_c_dimension
.width
;
1999 toffset
= t_col
+ t_row
* tems
.ts_c_dimension
.width
;
2000 src
= tem
->tvs_screen_buf
+ soffset
;
2001 dst
= tem
->tvs_screen_buf
+ toffset
;
2004 * Copy line by line. We determine the length by comparing the
2005 * screen content from cached text in tvs_screen_buf.
2007 if (toffset
<= soffset
) {
2008 for (int i
= 0; i
< rows
; i
++) {
2009 int increment
= i
* tems
.ts_c_dimension
.width
;
2012 width
= tem_copy_width(src
+ increment
,
2013 dst
+ increment
, cols
);
2014 memmove(dst
+ increment
, src
+ increment
,
2015 width
* sizeof (term_char_t
));
2016 if (tem
->tvs_isactive
) {
2017 tem_callback_copy(tem
, s_col
, s_row
+ i
,
2018 e_col
- cols
+ width
, s_row
+ i
,
2023 for (int i
= rows
- 1; i
>= 0; i
--) {
2024 int increment
= i
* tems
.ts_c_dimension
.width
;
2027 width
= tem_copy_width(src
+ increment
,
2028 dst
+ increment
, cols
);
2029 memmove(dst
+ increment
, src
+ increment
,
2030 width
* sizeof (term_char_t
));
2031 if (tem
->tvs_isactive
) {
2032 tem_callback_copy(tem
, s_col
, s_row
+ i
,
2033 e_col
- cols
+ width
, s_row
+ i
,
2041 tem_clear_chars(struct tem_vt_state
*tem
, int count
, screen_pos_t row
,
2044 if (row
< 0 || row
>= tems
.ts_c_dimension
.height
||
2045 col
< 0 || col
>= tems
.ts_c_dimension
.width
||
2050 * Note that very large values of "count" could cause col+count
2051 * to overflow, so we check "count" independently.
2053 if (count
> tems
.ts_c_dimension
.width
||
2054 col
+ count
> tems
.ts_c_dimension
.width
)
2055 count
= tems
.ts_c_dimension
.width
- col
;
2057 tem_virtual_cls(tem
, count
, row
, col
);
2059 if (!tem
->tvs_isactive
)
2062 tem_callback_cls(tem
, count
, row
, col
);
2066 tem_text_display(struct tem_vt_state
*tem __unused
, term_char_t
*string
,
2067 int count
, screen_pos_t row
, screen_pos_t col
)
2069 struct vis_consdisplay da
;
2076 da
.data
= (unsigned char *)&c
;
2081 for (i
= 0; i
< count
; i
++) {
2082 tem_get_color(&da
.fg_color
, &da
.bg_color
, string
[i
]);
2083 c
= TEM_CHAR(string
[i
].tc_char
);
2090 * This function is used to mark a rectangular image area so the scrolling
2091 * will know we need to copy the data from there.
2094 tem_image_display(struct tem_vt_state
*tem
, screen_pos_t s_row
,
2095 screen_pos_t s_col
, screen_pos_t e_row
, screen_pos_t e_col
)
2100 c
.tc_char
= TEM_ATTR(TEM_ATTR_IMAGE
);
2102 for (i
= s_row
; i
<= e_row
; i
++) {
2103 for (j
= s_col
; j
<= e_col
; j
++) {
2104 tem_virtual_display(tem
, &c
, 1, i
, j
);
2111 tem_text_copy(struct tem_vt_state
*tem __unused
,
2112 screen_pos_t s_col
, screen_pos_t s_row
,
2113 screen_pos_t e_col
, screen_pos_t e_row
,
2114 screen_pos_t t_col
, screen_pos_t t_row
)
2116 struct vis_conscopy da
;
2128 tem_text_cls(struct tem_vt_state
*tem
,
2129 int count
, screen_pos_t row
, screen_pos_t col
)
2135 tem_get_attr(tem
, &c
.tc_fg_color
, &c
.tc_bg_color
, &attr
,
2136 TEM_ATTR_SCREEN_REVERSE
);
2137 c
.tc_char
= TEM_ATTR(attr
& ~TEM_ATTR_UNDERLINE
) | ' ';
2139 if (count
> tems
.ts_c_dimension
.width
||
2140 col
+ count
> tems
.ts_c_dimension
.width
)
2141 count
= tems
.ts_c_dimension
.width
- col
;
2143 for (i
= 0; i
< count
; i
++)
2144 tem_text_display(tem
, &c
, 1, row
, col
++);
2149 tem_pix_display(struct tem_vt_state
*tem
,
2150 term_char_t
*string
, int count
,
2151 screen_pos_t row
, screen_pos_t col
)
2153 struct vis_consdisplay da
;
2156 da
.data
= (uint8_t *)tem
->tvs_pix_data
;
2157 da
.width
= tems
.ts_font
.vf_width
;
2158 da
.height
= tems
.ts_font
.vf_height
;
2159 da
.row
= (row
* da
.height
) + tems
.ts_p_offset
.y
;
2160 da
.col
= (col
* da
.width
) + tems
.ts_p_offset
.x
;
2162 for (i
= 0; i
< count
; i
++) {
2163 tem_callback_bit2pix(tem
, string
[i
]);
2170 tem_pix_copy(struct tem_vt_state
*tem
,
2171 screen_pos_t s_col
, screen_pos_t s_row
,
2172 screen_pos_t e_col
, screen_pos_t e_row
,
2173 screen_pos_t t_col
, screen_pos_t t_row
)
2175 struct vis_conscopy ma
;
2176 static boolean_t need_clear
= B_TRUE
;
2178 if (need_clear
&& tem
->tvs_first_line
> 0) {
2180 * Clear OBP output above our kernel console term
2181 * when our kernel console term begins to scroll up,
2182 * we hope it is user friendly.
2183 * (Also see comments on tem_pix_clear_prom_output)
2185 * This is only one time call.
2187 tem_pix_clear_prom_output(tem
);
2189 need_clear
= B_FALSE
;
2191 ma
.s_row
= s_row
* tems
.ts_font
.vf_height
+ tems
.ts_p_offset
.y
;
2192 ma
.e_row
= (e_row
+ 1) * tems
.ts_font
.vf_height
+
2193 tems
.ts_p_offset
.y
- 1;
2194 ma
.t_row
= t_row
* tems
.ts_font
.vf_height
+ tems
.ts_p_offset
.y
;
2197 * Check if we're in process of clearing OBP's columns area,
2198 * which only happens when term scrolls up a whole line.
2200 if (tem
->tvs_first_line
> 0 && t_row
< s_row
&& t_col
== 0 &&
2201 e_col
== tems
.ts_c_dimension
.width
- 1) {
2203 * We need to clear OBP's columns area outside our kernel
2204 * console term. So that we set ma.e_col to entire row here.
2206 ma
.s_col
= s_col
* tems
.ts_font
.vf_width
;
2207 ma
.e_col
= tems
.ts_p_dimension
.width
- 1;
2209 ma
.t_col
= t_col
* tems
.ts_font
.vf_width
;
2211 ma
.s_col
= s_col
* tems
.ts_font
.vf_width
+ tems
.ts_p_offset
.x
;
2212 ma
.e_col
= (e_col
+ 1) * tems
.ts_font
.vf_width
+
2213 tems
.ts_p_offset
.x
- 1;
2214 ma
.t_col
= t_col
* tems
.ts_font
.vf_width
+ tems
.ts_p_offset
.x
;
2219 if (tem
->tvs_first_line
> 0 && t_row
< s_row
) {
2220 /* We have scrolled up (s_row - t_row) rows. */
2221 tem
->tvs_first_line
-= (s_row
- t_row
);
2222 if (tem
->tvs_first_line
<= 0) {
2223 /* All OBP rows have been cleared. */
2224 tem
->tvs_first_line
= 0;
2230 tem_pix_bit2pix(struct tem_vt_state
*tem
, term_char_t c
)
2232 text_color_t fg
, bg
;
2233 void (*fp
)(struct tem_vt_state
*, tem_char_t
,
2234 unsigned char, unsigned char);
2236 tem_get_color(&fg
, &bg
, c
);
2237 switch (tems
.ts_pdepth
) {
2258 fp(tem
, c
.tc_char
, fg
, bg
);
2263 * This function only clears count of columns in one row
2266 tem_pix_cls(struct tem_vt_state
*tem
, int count
,
2267 screen_pos_t row
, screen_pos_t col
)
2269 tem_pix_cls_range(tem
, row
, 1, tems
.ts_p_offset
.y
,
2270 col
, count
, tems
.ts_p_offset
.x
, B_FALSE
);
2274 * This function clears OBP output above our kernel console term area
2275 * because OBP's term may have a bigger terminal window than that of
2276 * our kernel console term. So we need to clear OBP output garbage outside
2277 * of our kernel console term at a proper time, which is when the first
2278 * row output of our kernel console term scrolls at the first screen line.
2280 * _________________________________
2281 * | _____________________ | ---> OBP's bigger term window
2286 * |_|_|___________________|_______|
2287 * | | | ---> first line
2288 * | |___________________|---> our kernel console term window
2290 * |---> columns area to be cleared
2292 * This function only takes care of the output above our kernel console term,
2293 * and tem_prom_scroll_up takes care of columns area outside of our kernel
2297 tem_pix_clear_prom_output(struct tem_vt_state
*tem
)
2299 int nrows
, ncols
, width
, height
, offset
;
2301 width
= tems
.ts_font
.vf_width
;
2302 height
= tems
.ts_font
.vf_height
;
2303 offset
= tems
.ts_p_offset
.y
% height
;
2305 nrows
= tems
.ts_p_offset
.y
/ height
;
2306 ncols
= (tems
.ts_p_dimension
.width
+ (width
- 1))/ width
;
2309 tem_pix_cls_range(tem
, 0, nrows
, offset
, 0, ncols
, 0,
2314 * Clear the whole screen and reset the cursor to start point.
2317 tem_cls(struct tem_vt_state
*tem
)
2319 struct vis_consclear cl
;
2320 text_color_t fg_color
;
2321 text_color_t bg_color
;
2326 for (row
= 0; row
< tems
.ts_c_dimension
.height
; row
++) {
2327 tem_virtual_cls(tem
, tems
.ts_c_dimension
.width
, row
, 0);
2330 if (!tem
->tvs_isactive
)
2333 tem_get_attr(tem
, &c
.tc_fg_color
, &c
.tc_bg_color
, &attr
,
2334 TEM_ATTR_SCREEN_REVERSE
);
2335 c
.tc_char
= TEM_ATTR(attr
);
2337 tem_get_color(&fg_color
, &bg_color
, c
);
2338 cl
.bg_color
= bg_color
;
2339 (void)tems_cls(&cl
);
2341 tem
->tvs_c_cursor
.row
= 0;
2342 tem
->tvs_c_cursor
.col
= 0;
2343 tem_align_cursor(tem
);
2347 tem_back_tab(struct tem_vt_state
*tem
)
2350 screen_pos_t tabstop
;
2354 for (i
= tem
->tvs_ntabs
- 1; i
>= 0; i
--) {
2355 if (tem
->tvs_tabs
[i
] < tem
->tvs_c_cursor
.col
) {
2356 tabstop
= tem
->tvs_tabs
[i
];
2361 tem_mv_cursor(tem
, tem
->tvs_c_cursor
.row
, tabstop
);
2365 tem_tab(struct tem_vt_state
*tem
)
2368 screen_pos_t tabstop
;
2370 tabstop
= tems
.ts_c_dimension
.width
- 1;
2372 for (i
= 0; i
< tem
->tvs_ntabs
; i
++) {
2373 if (tem
->tvs_tabs
[i
] > tem
->tvs_c_cursor
.col
) {
2374 tabstop
= tem
->tvs_tabs
[i
];
2379 tem_mv_cursor(tem
, tem
->tvs_c_cursor
.row
, tabstop
);
2383 tem_set_tab(struct tem_vt_state
*tem
)
2388 if (tem
->tvs_ntabs
== TEM_MAXTAB
)
2390 if (tem
->tvs_ntabs
== 0 ||
2391 tem
->tvs_tabs
[tem
->tvs_ntabs
] < tem
->tvs_c_cursor
.col
) {
2392 tem
->tvs_tabs
[tem
->tvs_ntabs
++] = tem
->tvs_c_cursor
.col
;
2395 for (i
= 0; i
< tem
->tvs_ntabs
; i
++) {
2396 if (tem
->tvs_tabs
[i
] == tem
->tvs_c_cursor
.col
)
2398 if (tem
->tvs_tabs
[i
] > tem
->tvs_c_cursor
.col
) {
2399 for (j
= tem
->tvs_ntabs
- 1; j
>= i
; j
--)
2400 tem
->tvs_tabs
[j
+ 1] = tem
->tvs_tabs
[j
];
2401 tem
->tvs_tabs
[i
] = tem
->tvs_c_cursor
.col
;
2409 tem_clear_tabs(struct tem_vt_state
*tem
, int action
)
2415 case 3: /* clear all tabs */
2418 case 0: /* clr tab at cursor */
2420 for (i
= 0; i
< tem
->tvs_ntabs
; i
++) {
2421 if (tem
->tvs_tabs
[i
] == tem
->tvs_c_cursor
.col
) {
2423 for (j
= i
; j
< tem
->tvs_ntabs
; j
++)
2424 tem
->tvs_tabs
[j
] = tem
->tvs_tabs
[j
+ 1];
2433 tem_mv_cursor(struct tem_vt_state
*tem
, int row
, int col
)
2436 * Sanity check and bounds enforcement. Out of bounds requests are
2437 * clipped to the screen boundaries. This seems to be what SPARC
2442 if (row
>= tems
.ts_c_dimension
.height
)
2443 row
= tems
.ts_c_dimension
.height
- 1;
2446 if (col
>= tems
.ts_c_dimension
.width
)
2447 col
= tems
.ts_c_dimension
.width
- 1;
2450 tem
->tvs_c_cursor
.row
= (screen_pos_t
)row
;
2451 tem
->tvs_c_cursor
.col
= (screen_pos_t
)col
;
2452 tem_align_cursor(tem
);
2457 tem_reset_emulator(struct tem_vt_state
*tem
, boolean_t init_color
)
2461 tem
->tvs_c_cursor
.row
= 0;
2462 tem
->tvs_c_cursor
.col
= 0;
2463 tem
->tvs_r_cursor
.row
= 0;
2464 tem
->tvs_r_cursor
.col
= 0;
2465 tem
->tvs_s_cursor
.row
= 0;
2466 tem
->tvs_s_cursor
.col
= 0;
2467 tem
->tvs_outindex
= 0;
2468 tem
->tvs_state
= A_STATE_START
;
2469 tem
->tvs_gotparam
= B_FALSE
;
2470 tem
->tvs_curparam
= 0;
2471 tem
->tvs_paramval
= 0;
2472 tem
->tvs_nscroll
= 1;
2475 /* use initial settings */
2476 tem
->tvs_fg_color
= tems
.ts_init_color
.fg_color
;
2477 tem
->tvs_bg_color
= tems
.ts_init_color
.bg_color
;
2478 tem
->tvs_flags
= tems
.ts_init_color
.a_flags
;
2482 * set up the initial tab stops
2485 for (j
= 8; j
< tems
.ts_c_dimension
.width
; j
+= 8)
2486 tem
->tvs_tabs
[tem
->tvs_ntabs
++] = (screen_pos_t
)j
;
2488 for (j
= 0; j
< TEM_MAXPARAMS
; j
++)
2489 tem
->tvs_params
[j
] = 0;
2493 tem_reset_display(struct tem_vt_state
*tem
,
2494 boolean_t clear_txt
, boolean_t init_color
)
2496 tem_reset_emulator(tem
, init_color
);
2499 if (tem
->tvs_isactive
)
2500 tem_callback_cursor(tem
, VIS_HIDE_CURSOR
);
2504 if (tem
->tvs_isactive
)
2505 tem_callback_cursor(tem
, VIS_DISPLAY_CURSOR
);
2510 tem_shift(struct tem_vt_state
*tem
, int count
, int direction
)
2514 rest_of_line
= tems
.ts_c_dimension
.width
- tem
->tvs_c_cursor
.col
;
2515 if (count
> rest_of_line
)
2516 count
= rest_of_line
;
2521 switch (direction
) {
2522 case TEM_SHIFT_LEFT
:
2523 if (count
< rest_of_line
) {
2525 tem
->tvs_c_cursor
.col
+ count
,
2526 tem
->tvs_c_cursor
.row
,
2527 tems
.ts_c_dimension
.width
- 1,
2528 tem
->tvs_c_cursor
.row
,
2529 tem
->tvs_c_cursor
.col
,
2530 tem
->tvs_c_cursor
.row
);
2533 tem_clear_chars(tem
, count
, tem
->tvs_c_cursor
.row
,
2534 (tems
.ts_c_dimension
.width
- count
));
2536 case TEM_SHIFT_RIGHT
:
2537 if (count
< rest_of_line
) {
2539 tem
->tvs_c_cursor
.col
,
2540 tem
->tvs_c_cursor
.row
,
2541 tems
.ts_c_dimension
.width
- count
- 1,
2542 tem
->tvs_c_cursor
.row
,
2543 tem
->tvs_c_cursor
.col
+ count
,
2544 tem
->tvs_c_cursor
.row
);
2547 tem_clear_chars(tem
, count
, tem
->tvs_c_cursor
.row
,
2548 tem
->tvs_c_cursor
.col
);
2554 tem_text_cursor(struct tem_vt_state
*tem
, short action
)
2556 struct vis_conscursor ca
;
2558 ca
.row
= tem
->tvs_c_cursor
.row
;
2559 ca
.col
= tem
->tvs_c_cursor
.col
;
2564 if (action
== VIS_GET_CURSOR
) {
2565 tem
->tvs_c_cursor
.row
= ca
.row
;
2566 tem
->tvs_c_cursor
.col
= ca
.col
;
2571 tem_pix_cursor(struct tem_vt_state
*tem
, short action
)
2573 struct vis_conscursor ca
;
2575 text_color_t fg
, bg
;
2579 ca
.row
= tem
->tvs_c_cursor
.row
* tems
.ts_font
.vf_height
+
2581 ca
.col
= tem
->tvs_c_cursor
.col
* tems
.ts_font
.vf_width
+
2583 ca
.width
= tems
.ts_font
.vf_width
;
2584 ca
.height
= tems
.ts_font
.vf_height
;
2586 tem_get_attr(tem
, &c
.tc_fg_color
, &c
.tc_bg_color
, &attr
,
2588 c
.tc_char
= TEM_ATTR(attr
);
2590 tem_get_color(&fg
, &bg
, c
);
2592 switch (tems
.ts_pdepth
) {
2594 ca
.fg_color
.mono
= fg
;
2595 ca
.bg_color
.mono
= bg
;
2598 ca
.fg_color
.mono
= tems
.ts_color_map(fg
);
2599 ca
.bg_color
.mono
= tems
.ts_color_map(bg
);
2603 color
= tems
.ts_color_map(fg
);
2604 ca
.fg_color
.sixteen
[0] = (color
>> 8) & 0xFF;
2605 ca
.fg_color
.sixteen
[1] = color
& 0xFF;
2606 color
= tems
.ts_color_map(bg
);
2607 ca
.bg_color
.sixteen
[0] = (color
>> 8) & 0xFF;
2608 ca
.bg_color
.sixteen
[1] = color
& 0xFF;
2612 color
= tems
.ts_color_map(fg
);
2613 ca
.fg_color
.twentyfour
[0] = (color
>> 16) & 0xFF;
2614 ca
.fg_color
.twentyfour
[1] = (color
>> 8) & 0xFF;
2615 ca
.fg_color
.twentyfour
[2] = color
& 0xFF;
2616 color
= tems
.ts_color_map(bg
);
2617 ca
.bg_color
.twentyfour
[0] = (color
>> 16) & 0xFF;
2618 ca
.bg_color
.twentyfour
[1] = (color
>> 8) & 0xFF;
2619 ca
.bg_color
.twentyfour
[2] = color
& 0xFF;
2627 if (action
== VIS_GET_CURSOR
) {
2628 tem
->tvs_c_cursor
.row
= 0;
2629 tem
->tvs_c_cursor
.col
= 0;
2632 tem
->tvs_c_cursor
.row
= (ca
.row
- tems
.ts_p_offset
.y
) /
2633 tems
.ts_font
.vf_height
;
2636 tem
->tvs_c_cursor
.col
= (ca
.col
- tems
.ts_p_offset
.x
) /
2637 tems
.ts_font
.vf_width
;
2643 bit_to_pix4(struct tem_vt_state
*tem
,
2645 text_color_t fg_color
,
2646 text_color_t bg_color
)
2648 uint8_t *dest
= (uint8_t *)tem
->tvs_pix_data
;
2649 font_bit_to_pix4(&tems
.ts_font
, dest
, c
, fg_color
, bg_color
);
2653 bit_to_pix8(struct tem_vt_state
*tem
,
2655 text_color_t fg_color
,
2656 text_color_t bg_color
)
2658 uint8_t *dest
= (uint8_t *)tem
->tvs_pix_data
;
2660 fg_color
= (text_color_t
)tems
.ts_color_map(fg_color
);
2661 bg_color
= (text_color_t
)tems
.ts_color_map(bg_color
);
2662 font_bit_to_pix8(&tems
.ts_font
, dest
, c
, fg_color
, bg_color
);
2666 bit_to_pix16(struct tem_vt_state
*tem
,
2668 text_color_t fg_color4
,
2669 text_color_t bg_color4
)
2671 uint16_t fg_color16
, bg_color16
;
2674 fg_color16
= (uint16_t)tems
.ts_color_map(fg_color4
);
2675 bg_color16
= (uint16_t)tems
.ts_color_map(bg_color4
);
2677 dest
= (uint16_t *)tem
->tvs_pix_data
;
2678 font_bit_to_pix16(&tems
.ts_font
, dest
, c
, fg_color16
, bg_color16
);
2682 bit_to_pix24(struct tem_vt_state
*tem
,
2684 text_color_t fg_color4
,
2685 text_color_t bg_color4
)
2687 uint32_t fg_color32
, bg_color32
;
2690 fg_color32
= tems
.ts_color_map(fg_color4
);
2691 bg_color32
= tems
.ts_color_map(bg_color4
);
2693 dest
= (uint8_t *)tem
->tvs_pix_data
;
2694 font_bit_to_pix24(&tems
.ts_font
, dest
, c
, fg_color32
, bg_color32
);
2698 bit_to_pix32(struct tem_vt_state
*tem
,
2700 text_color_t fg_color4
,
2701 text_color_t bg_color4
)
2703 uint32_t fg_color32
, bg_color32
, *dest
;
2705 fg_color32
= (0xFF << 24) | tems
.ts_color_map(fg_color4
);
2706 bg_color32
= (0xFF << 24) | tems
.ts_color_map(bg_color4
);
2708 dest
= (uint32_t *)tem
->tvs_pix_data
;
2709 font_bit_to_pix32(&tems
.ts_font
, dest
, c
, fg_color32
, bg_color32
);
2713 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2716 tem_get_attr(struct tem_vt_state
*tem
, text_color_t
*fg
,
2717 text_color_t
*bg
, text_attr_t
*attr
, uint8_t flag
)
2719 if (tem
->tvs_flags
& flag
) {
2720 *fg
= tem
->tvs_bg_color
;
2721 *bg
= tem
->tvs_fg_color
;
2723 *fg
= tem
->tvs_fg_color
;
2724 *bg
= tem
->tvs_bg_color
;
2730 *attr
= tem
->tvs_flags
;
2734 tem_get_color(text_color_t
*fg
, text_color_t
*bg
, term_char_t c
)
2736 if (TEM_CHAR_ATTR(c
.tc_char
) & (TEM_ATTR_BRIGHT_FG
| TEM_ATTR_BOLD
))
2737 *fg
= brt_xlate
[c
.tc_fg_color
];
2739 *fg
= dim_xlate
[c
.tc_fg_color
];
2741 if (TEM_CHAR_ATTR(c
.tc_char
) & TEM_ATTR_BRIGHT_BG
)
2742 *bg
= brt_xlate
[c
.tc_bg_color
];
2744 *bg
= dim_xlate
[c
.tc_bg_color
];
2748 tem_get_colors(tem_vt_state_t tem_arg
, text_color_t
*fg
, text_color_t
*bg
)
2750 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
2754 tem_get_attr(tem
, &c
.tc_fg_color
, &c
.tc_bg_color
, &attr
,
2756 c
.tc_char
= TEM_ATTR(attr
);
2757 tem_get_color(fg
, bg
, c
);
2761 * Clear a rectangle of screen for pixel mode.
2765 * nrows: the number of rows to clear
2766 * offset_y: the offset of height in pixels to begin clear
2768 * ncols: the number of cols to clear
2769 * offset_x: the offset of width in pixels to begin clear
2770 * scroll_up: whether this function is called during sroll up,
2771 * which is called only once.
2774 tem_pix_cls_range(struct tem_vt_state
*tem
,
2775 screen_pos_t row
, int nrows
, int offset_y
,
2776 screen_pos_t col
, int ncols
, int offset_x
,
2779 struct vis_consdisplay da
;
2786 row_add
= tems
.ts_c_dimension
.height
- 1;
2788 da
.width
= tems
.ts_font
.vf_width
;
2789 da
.height
= tems
.ts_font
.vf_height
;
2791 tem_get_attr(tem
, &c
.tc_fg_color
, &c
.tc_bg_color
, &attr
,
2792 TEM_ATTR_SCREEN_REVERSE
);
2793 /* Make sure we will not draw underlines */
2794 c
.tc_char
= TEM_ATTR(attr
& ~TEM_ATTR_UNDERLINE
) | ' ';
2796 tem_callback_bit2pix(tem
, c
);
2797 da
.data
= (uint8_t *)tem
->tvs_pix_data
;
2799 for (i
= 0; i
< nrows
; i
++, row
++) {
2800 da
.row
= (row
+ row_add
) * da
.height
+ offset_y
;
2801 da
.col
= col
* da
.width
+ offset_x
;
2802 for (j
= 0; j
< ncols
; j
++) {
2810 * virtual screen operations
2813 tem_virtual_display(struct tem_vt_state
*tem
, term_char_t
*string
,
2814 size_t count
, screen_pos_t row
, screen_pos_t col
)
2819 if (tem
->tvs_screen_buf
== NULL
)
2822 if (row
< 0 || row
>= tems
.ts_c_dimension
.height
||
2823 col
< 0 || col
>= tems
.ts_c_dimension
.width
||
2824 col
+ count
> (size_t)tems
.ts_c_dimension
.width
)
2827 width
= tems
.ts_c_dimension
.width
;
2828 addr
= tem
->tvs_screen_buf
+ (row
* width
+ col
);
2829 for (i
= 0; i
< count
; i
++) {
2830 *addr
++ = string
[i
];
2835 tem_virtual_cls(struct tem_vt_state
*tem
, size_t count
,
2836 screen_pos_t row
, screen_pos_t col
)
2841 tem_get_colors((tem_vt_state_t
)tem
, &c
.tc_fg_color
, &c
.tc_bg_color
);
2844 tem_virtual_display(tem
, &c
, 1, row
, col
);