xref: /illumos-gate/usr/src/boot/common/tem.c (revision d863b4c1)
19890ff83SToomas Soome /*
29890ff83SToomas Soome  * CDDL HEADER START
39890ff83SToomas Soome  *
49890ff83SToomas Soome  * The contents of this file are subject to the terms of the
59890ff83SToomas Soome  * Common Development and Distribution License (the "License").
69890ff83SToomas Soome  * You may not use this file except in compliance with the License.
79890ff83SToomas Soome  *
89890ff83SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99890ff83SToomas Soome  * or http://www.opensolaris.org/os/licensing.
109890ff83SToomas Soome  * See the License for the specific language governing permissions
119890ff83SToomas Soome  * and limitations under the License.
129890ff83SToomas Soome  *
139890ff83SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
149890ff83SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159890ff83SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
169890ff83SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
179890ff83SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
189890ff83SToomas Soome  *
199890ff83SToomas Soome  * CDDL HEADER END
209890ff83SToomas Soome  */
219890ff83SToomas Soome 
229890ff83SToomas Soome /*
239890ff83SToomas Soome  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
249890ff83SToomas Soome  * Use is subject to license terms.
259890ff83SToomas Soome  * Copyright 2016 Joyent, Inc.
26fa9eb222SToomas Soome  * Copyright 2021 Toomas Soome <tsoome@me.com>
275e897995SToomas Soome  * Copyright 2021 RackTop Systems, Inc.
289890ff83SToomas Soome  */
299890ff83SToomas Soome 
309890ff83SToomas Soome /*
319890ff83SToomas Soome  * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
329890ff83SToomas Soome  * the like.
339890ff83SToomas Soome  *
349890ff83SToomas Soome  * How Virtual Terminal Emulator Works:
359890ff83SToomas Soome  *
369890ff83SToomas Soome  * Every virtual terminal is associated with a tem_vt_state structure
379890ff83SToomas Soome  * and maintains a virtual screen buffer in tvs_screen_buf, which contains
389890ff83SToomas Soome  * all the characters which should be shown on the physical screen when
399890ff83SToomas Soome  * the terminal is activated.
409890ff83SToomas Soome  *
419890ff83SToomas Soome  * Data written to a virtual terminal is composed of characters which
429890ff83SToomas Soome  * should be displayed on the screen when this virtual terminal is
439890ff83SToomas Soome  * activated, fg/bg colors of these characters, and other control
449890ff83SToomas Soome  * information (escape sequence, etc).
459890ff83SToomas Soome  *
469890ff83SToomas Soome  * When data is passed to a virtual terminal it first is parsed for
479890ff83SToomas Soome  * control information by tem_parse().  Subsequently the character
489890ff83SToomas Soome  * and color data are written to tvs_screen_buf.
499890ff83SToomas Soome  * They are saved in buffer in order to refresh the screen when this
509890ff83SToomas Soome  * terminal is activated.  If the terminal is currently active, the data
519890ff83SToomas Soome  * (characters and colors) are also written to the physical screen by
529890ff83SToomas Soome  * invoking a callback function, tem_text_callbacks() or tem_pix_callbacks().
539890ff83SToomas Soome  *
549890ff83SToomas Soome  * When rendering data to the framebuffer, if the framebuffer is in
559890ff83SToomas Soome  * VIS_PIXEL mode, the character data will first be converted to pixel
569890ff83SToomas Soome  * data using tem_pix_bit2pix(), and then the pixels get displayed
579890ff83SToomas Soome  * on the physical screen.  We only store the character and color data in
589890ff83SToomas Soome  * tem_vt_state since the bit2pix conversion only happens when actually
599890ff83SToomas Soome  * rendering to the physical framebuffer.
60fa9eb222SToomas Soome  *
61fa9eb222SToomas Soome  * Color support:
62fa9eb222SToomas Soome  * Text mode can only support standard system colors, 4-bit [0-15] indexed.
63fa9eb222SToomas Soome  * On framebuffer devices, we can aditionally use [16-255] or truecolor.
64fa9eb222SToomas Soome  * Additional colors can be used via CSI 38 and CSI 48 sequences.
65fa9eb222SToomas Soome  * CSI 38/48;5 is using indexed colors [0-255], CSI 38/48;2 does
66fa9eb222SToomas Soome  * specify color by RGB triple.
67fa9eb222SToomas Soome  *
68fa9eb222SToomas Soome  * While sending glyphs to display, we need to process glyph attributes:
69fa9eb222SToomas Soome  * TEM_ATTR_BOLD will cause BOLD font to be used (or BRIGHT color if we
70fa9eb222SToomas Soome  * we use indexed color [0-7]).
71fa9eb222SToomas Soome  * We ignore TEM_ATTR_BRIGHT_FG/TEM_ATTR_BRIGHT_BG with RGB colors.
72fa9eb222SToomas Soome  * TEM_ATTR_REVERSE and TEM_ATTR_SCREEN_REVERSE will cause fg and bg to be
73fa9eb222SToomas Soome  * swapped.
749890ff83SToomas Soome  */
759890ff83SToomas Soome 
769890ff83SToomas Soome #include <stand.h>
779890ff83SToomas Soome #include <sys/ascii.h>
789890ff83SToomas Soome #include <sys/errno.h>
799890ff83SToomas Soome #include <sys/tem_impl.h>
809890ff83SToomas Soome #ifdef _HAVE_TEM_FIRMWARE
819890ff83SToomas Soome #include <sys/promif.h>
829890ff83SToomas Soome #endif /* _HAVE_TEM_FIRMWARE */
839890ff83SToomas Soome #include <sys/consplat.h>
849890ff83SToomas Soome #include <sys/kd.h>
8562efa0e7SToomas Soome #include <stdbool.h>
869890ff83SToomas Soome 
879890ff83SToomas Soome /* Terminal emulator internal helper functions */
889890ff83SToomas Soome static void	tems_setup_terminal(struct vis_devinit *, size_t, size_t);
899890ff83SToomas Soome static void	tems_modechange_callback(struct vis_modechg_arg *,
909890ff83SToomas Soome 		    struct vis_devinit *);
919890ff83SToomas Soome 
929890ff83SToomas Soome static void	tems_reset_colormap(void);
939890ff83SToomas Soome 
949890ff83SToomas Soome static void	tem_free_buf(struct tem_vt_state *);
95ffd79eb6SToomas Soome static void	tem_internal_init(struct tem_vt_state *, bool, bool);
969890ff83SToomas Soome static void	tems_get_initial_color(tem_color_t *pcolor);
979890ff83SToomas Soome 
989890ff83SToomas Soome static void	tem_control(struct tem_vt_state *, uint8_t);
999890ff83SToomas Soome static void	tem_setparam(struct tem_vt_state *, int, int);
1009890ff83SToomas Soome static void	tem_selgraph(struct tem_vt_state *);
1019890ff83SToomas Soome static void	tem_chkparam(struct tem_vt_state *, uint8_t);
1029890ff83SToomas Soome static void	tem_getparams(struct tem_vt_state *, uint8_t);
1039890ff83SToomas Soome static void	tem_outch(struct tem_vt_state *, tem_char_t);
1049890ff83SToomas Soome static void	tem_parse(struct tem_vt_state *, tem_char_t);
1059890ff83SToomas Soome 
1069890ff83SToomas Soome static void	tem_new_line(struct tem_vt_state *);
1079890ff83SToomas Soome static void	tem_cr(struct tem_vt_state *);
1089890ff83SToomas Soome static void	tem_lf(struct tem_vt_state *);
1099890ff83SToomas Soome static void	tem_send_data(struct tem_vt_state *);
1109890ff83SToomas Soome static void	tem_cls(struct tem_vt_state *);
1119890ff83SToomas Soome static void	tem_tab(struct tem_vt_state *);
1129890ff83SToomas Soome static void	tem_back_tab(struct tem_vt_state *);
1139890ff83SToomas Soome static void	tem_clear_tabs(struct tem_vt_state *, int);
1149890ff83SToomas Soome static void	tem_set_tab(struct tem_vt_state *);
1159890ff83SToomas Soome static void	tem_mv_cursor(struct tem_vt_state *, int, int);
1169890ff83SToomas Soome static void	tem_shift(struct tem_vt_state *, int, int);
1179890ff83SToomas Soome static void	tem_scroll(struct tem_vt_state *, int, int, int, int);
1189890ff83SToomas Soome static void	tem_clear_chars(struct tem_vt_state *tem,
1199890ff83SToomas Soome 			int count, screen_pos_t row, screen_pos_t col);
1209890ff83SToomas Soome static void	tem_copy_area(struct tem_vt_state *tem,
1219890ff83SToomas Soome 			screen_pos_t s_col, screen_pos_t s_row,
1229890ff83SToomas Soome 			screen_pos_t e_col, screen_pos_t e_row,
1239890ff83SToomas Soome 			screen_pos_t t_col, screen_pos_t t_row);
1249890ff83SToomas Soome static void	tem_bell(struct tem_vt_state *tem);
1259890ff83SToomas Soome static void	tem_pix_clear_prom_output(struct tem_vt_state *tem);
1269890ff83SToomas Soome 
1279890ff83SToomas Soome static void	tem_virtual_cls(struct tem_vt_state *, size_t, screen_pos_t,
1289890ff83SToomas Soome 		    screen_pos_t);
1299890ff83SToomas Soome static void	tem_virtual_display(struct tem_vt_state *, term_char_t *,
1309890ff83SToomas Soome 		    size_t, screen_pos_t, screen_pos_t);
1319890ff83SToomas Soome static void	tem_align_cursor(struct tem_vt_state *tem);
1329890ff83SToomas Soome 
1339890ff83SToomas Soome static void	tem_check_first_time(struct tem_vt_state *tem);
134ffd79eb6SToomas Soome static void	tem_reset_display(struct tem_vt_state *, bool, bool);
1359890ff83SToomas Soome static void	tem_terminal_emulate(struct tem_vt_state *, uint8_t *, int);
1369890ff83SToomas Soome static void	tem_text_cursor(struct tem_vt_state *, short);
1379890ff83SToomas Soome static void	tem_text_cls(struct tem_vt_state *,
1389890ff83SToomas Soome 		    int count, screen_pos_t row, screen_pos_t col);
1399890ff83SToomas Soome static void	tem_pix_display(struct tem_vt_state *, term_char_t *,
1409890ff83SToomas Soome 		    int, screen_pos_t, screen_pos_t);
1419890ff83SToomas Soome static void	tem_pix_copy(struct tem_vt_state *,
1429890ff83SToomas Soome 		    screen_pos_t, screen_pos_t,
1439890ff83SToomas Soome 		    screen_pos_t, screen_pos_t,
1449890ff83SToomas Soome 		    screen_pos_t, screen_pos_t);
1459890ff83SToomas Soome static void	tem_pix_cursor(struct tem_vt_state *, short);
1469890ff83SToomas Soome static void	tem_get_attr(struct tem_vt_state *, text_color_t *,
1479890ff83SToomas Soome 		    text_color_t *, text_attr_t *, uint8_t);
148fa9eb222SToomas Soome static void	tem_get_color(struct tem_vt_state *,
149fa9eb222SToomas Soome 		    text_color_t *, text_color_t *, term_char_t *);
150fa9eb222SToomas Soome static void	tem_set_color(text_color_t *, color_t *);
1519890ff83SToomas Soome static void	tem_pix_align(struct tem_vt_state *);
1529890ff83SToomas Soome static void	tem_text_display(struct tem_vt_state *, term_char_t *, int,
1539890ff83SToomas Soome 		    screen_pos_t, screen_pos_t);
1549890ff83SToomas Soome static void	tem_text_copy(struct tem_vt_state *,
1559890ff83SToomas Soome 		    screen_pos_t, screen_pos_t, screen_pos_t, screen_pos_t,
1569890ff83SToomas Soome 		    screen_pos_t, screen_pos_t);
157fa9eb222SToomas Soome static void	tem_pix_bit2pix(struct tem_vt_state *, term_char_t *);
1589890ff83SToomas Soome static void	tem_pix_cls_range(struct tem_vt_state *, screen_pos_t, int,
159ffd79eb6SToomas Soome 		    int, screen_pos_t, int, int, bool);
1609890ff83SToomas Soome static void	tem_pix_cls(struct tem_vt_state *, int,
1619890ff83SToomas Soome 		    screen_pos_t, screen_pos_t);
1629890ff83SToomas Soome 
1639890ff83SToomas Soome static void	bit_to_pix32(struct tem_vt_state *tem, tem_char_t c,
1649890ff83SToomas Soome 		    text_color_t fg_color, text_color_t bg_color);
1659890ff83SToomas Soome 
1669890ff83SToomas Soome /*
1679890ff83SToomas Soome  * Globals
1689890ff83SToomas Soome  */
1699890ff83SToomas Soome tem_state_t	tems;	/* common term info */
1709890ff83SToomas Soome 
1719890ff83SToomas Soome tem_callbacks_t tem_text_callbacks = {
1729890ff83SToomas Soome 	.tsc_display = &tem_text_display,
1739890ff83SToomas Soome 	.tsc_copy = &tem_text_copy,
1749890ff83SToomas Soome 	.tsc_cursor = &tem_text_cursor,
1759890ff83SToomas Soome 	.tsc_bit2pix = NULL,
1769890ff83SToomas Soome 	.tsc_cls = &tem_text_cls
1779890ff83SToomas Soome };
1789890ff83SToomas Soome tem_callbacks_t tem_pix_callbacks = {
1799890ff83SToomas Soome 	.tsc_display = &tem_pix_display,
1809890ff83SToomas Soome 	.tsc_copy = &tem_pix_copy,
1819890ff83SToomas Soome 	.tsc_cursor = &tem_pix_cursor,
1829890ff83SToomas Soome 	.tsc_bit2pix = &tem_pix_bit2pix,
1839890ff83SToomas Soome 	.tsc_cls = &tem_pix_cls
1849890ff83SToomas Soome };
1859890ff83SToomas Soome 
1869890ff83SToomas Soome #define	tem_callback_display	(*tems.ts_callbacks->tsc_display)
1879890ff83SToomas Soome #define	tem_callback_copy	(*tems.ts_callbacks->tsc_copy)
1889890ff83SToomas Soome #define	tem_callback_cursor	(*tems.ts_callbacks->tsc_cursor)
1899890ff83SToomas Soome #define	tem_callback_cls	(*tems.ts_callbacks->tsc_cls)
1909890ff83SToomas Soome #define	tem_callback_bit2pix	(*tems.ts_callbacks->tsc_bit2pix)
1919890ff83SToomas Soome 
1929890ff83SToomas Soome static void
tem_add(struct tem_vt_state * tem)1939890ff83SToomas Soome tem_add(struct tem_vt_state *tem)
1949890ff83SToomas Soome {
1959890ff83SToomas Soome 	list_insert_head(&tems.ts_list, tem);
1969890ff83SToomas Soome }
1979890ff83SToomas Soome 
1989890ff83SToomas Soome /*
1999890ff83SToomas Soome  * This is the main entry point to the module.  It handles output requests
2009890ff83SToomas Soome  * during normal system operation, when (e.g.) mutexes are available.
2019890ff83SToomas Soome  */
2029890ff83SToomas Soome void
tem_write(tem_vt_state_t tem_arg,uint8_t * buf,ssize_t len)2039890ff83SToomas Soome tem_write(tem_vt_state_t tem_arg, uint8_t *buf, ssize_t len)
2049890ff83SToomas Soome {
2059890ff83SToomas Soome 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
2069890ff83SToomas Soome 
207726d8a6eSToomas Soome 	if (tems.ts_initialized == 0 || tem->tvs_initialized == 0) {
2089890ff83SToomas Soome 		return;
2099890ff83SToomas Soome 	}
2109890ff83SToomas Soome 
2119890ff83SToomas Soome 	tem_check_first_time(tem);
2129890ff83SToomas Soome 	tem_terminal_emulate(tem, buf, len);
2139890ff83SToomas Soome }
2149890ff83SToomas Soome 
2159890ff83SToomas Soome static void
tem_internal_init(struct tem_vt_state * ptem,bool init_color,bool clear_screen)2169890ff83SToomas Soome tem_internal_init(struct tem_vt_state *ptem,
217ffd79eb6SToomas Soome     bool init_color, bool clear_screen)
2189890ff83SToomas Soome {
2199890ff83SToomas Soome 	size_t size, width, height;
2209890ff83SToomas Soome 
2219890ff83SToomas Soome 	if (tems.ts_display_mode == VIS_PIXEL) {
2229890ff83SToomas Soome 		ptem->tvs_pix_data_size = tems.ts_pix_data_size;
2239890ff83SToomas Soome 		ptem->tvs_pix_data = malloc(ptem->tvs_pix_data_size);
2249890ff83SToomas Soome 	}
2259890ff83SToomas Soome 
226*d863b4c1SToomas Soome 	ptem->tvs_stateflags = TVS_AUTOWRAP;
227*d863b4c1SToomas Soome 
2289890ff83SToomas Soome 	width = tems.ts_c_dimension.width;
2299890ff83SToomas Soome 	height = tems.ts_c_dimension.height;
2309890ff83SToomas Soome 
2319890ff83SToomas Soome 	size = width * sizeof (tem_char_t);
2329890ff83SToomas Soome 	ptem->tvs_outbuf = malloc(size);
2339890ff83SToomas Soome 	if (ptem->tvs_outbuf == NULL)
2349890ff83SToomas Soome 		panic("out of memory in tem_internal_init()\n");
2359890ff83SToomas Soome 
236ba2848d4SToomas Soome 	ptem->tvs_maxtab = width / 8;
237ba2848d4SToomas Soome 	ptem->tvs_tabs = calloc(ptem->tvs_maxtab, sizeof (*ptem->tvs_tabs));
238ba2848d4SToomas Soome 	if (ptem->tvs_tabs == NULL)
239ba2848d4SToomas Soome 		panic("out of memory in tem_internal_init()\n");
240ba2848d4SToomas Soome 
2419890ff83SToomas Soome 	tem_reset_display(ptem, clear_screen, init_color);
2429890ff83SToomas Soome 
2439890ff83SToomas Soome 	ptem->tvs_utf8_left = 0;
2449890ff83SToomas Soome 	ptem->tvs_utf8_partial = 0;
2459890ff83SToomas Soome 
2469890ff83SToomas Soome 	ptem->tvs_initialized  = true;
2479890ff83SToomas Soome 
2489890ff83SToomas Soome 	/*
2499890ff83SToomas Soome 	 * Out of memory is not fatal there, without the screen history,
2509890ff83SToomas Soome 	 * we can not optimize the screen copy.
2519890ff83SToomas Soome 	 */
2529890ff83SToomas Soome 	size = width * height * sizeof (term_char_t);
2539890ff83SToomas Soome 	ptem->tvs_screen_buf = malloc(size);
2549890ff83SToomas Soome 	tem_virtual_cls(ptem, width * height, 0, 0);
2559890ff83SToomas Soome }
2569890ff83SToomas Soome 
2579890ff83SToomas Soome int
tem_initialized(tem_vt_state_t tem_arg)2589890ff83SToomas Soome tem_initialized(tem_vt_state_t tem_arg)
2599890ff83SToomas Soome {
2609890ff83SToomas Soome 	struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg;
2619890ff83SToomas Soome 
2629890ff83SToomas Soome 	return (ptem->tvs_initialized);
2639890ff83SToomas Soome }
2649890ff83SToomas Soome 
2659890ff83SToomas Soome tem_vt_state_t
tem_init(void)2669890ff83SToomas Soome tem_init(void)
2679890ff83SToomas Soome {
2689890ff83SToomas Soome 	struct tem_vt_state *ptem;
2699890ff83SToomas Soome 
270726d8a6eSToomas Soome 	ptem = calloc(1, sizeof (struct tem_vt_state));
2719890ff83SToomas Soome 	if (ptem == NULL)
2729890ff83SToomas Soome 		return ((tem_vt_state_t)ptem);
2739890ff83SToomas Soome 
2749890ff83SToomas Soome 	ptem->tvs_isactive = false;
2759890ff83SToomas Soome 	ptem->tvs_fbmode = KD_TEXT;
2769890ff83SToomas Soome 
2779890ff83SToomas Soome 	/*
2789890ff83SToomas Soome 	 * A tem is regarded as initialized only after tem_internal_init(),
2799890ff83SToomas Soome 	 * will be set at the end of tem_internal_init().
2809890ff83SToomas Soome 	 */
2819890ff83SToomas Soome 	ptem->tvs_initialized = 0;
2829890ff83SToomas Soome 
2839890ff83SToomas Soome 	if (!tems.ts_initialized) {
2849890ff83SToomas Soome 		/*
2859890ff83SToomas Soome 		 * Only happens during early console configuration.
2869890ff83SToomas Soome 		 */
2879890ff83SToomas Soome 		tem_add(ptem);
2889890ff83SToomas Soome 		return ((tem_vt_state_t)ptem);
2899890ff83SToomas Soome 	}
2909890ff83SToomas Soome 
291ffd79eb6SToomas Soome 	tem_internal_init(ptem, true, false);
2929890ff83SToomas Soome 	tem_add(ptem);
2939890ff83SToomas Soome 
2949890ff83SToomas Soome 	return ((tem_vt_state_t)ptem);
2959890ff83SToomas Soome }
2969890ff83SToomas Soome 
2979890ff83SToomas Soome /*
2989890ff83SToomas Soome  * re-init the tem after video mode has changed and tems_info has
2999890ff83SToomas Soome  * been re-inited.
3009890ff83SToomas Soome  */
3019890ff83SToomas Soome static void
tem_reinit(struct tem_vt_state * tem,bool reset_display)302ffd79eb6SToomas Soome tem_reinit(struct tem_vt_state *tem, bool reset_display)
3039890ff83SToomas Soome {
3049890ff83SToomas Soome 	tem_free_buf(tem); /* only free virtual buffers */
3059890ff83SToomas Soome 
3069890ff83SToomas Soome 	/* reserve color */
307ffd79eb6SToomas Soome 	tem_internal_init(tem, false, reset_display);
3089890ff83SToomas Soome }
3099890ff83SToomas Soome 
3109890ff83SToomas Soome static void
tem_free_buf(struct tem_vt_state * tem)3119890ff83SToomas Soome tem_free_buf(struct tem_vt_state *tem)
3129890ff83SToomas Soome {
3139890ff83SToomas Soome 	free(tem->tvs_outbuf);
3149890ff83SToomas Soome 	tem->tvs_outbuf = NULL;
3159890ff83SToomas Soome 
3169890ff83SToomas Soome 	free(tem->tvs_pix_data);
3179890ff83SToomas Soome 	tem->tvs_pix_data = NULL;
3189890ff83SToomas Soome 
3199890ff83SToomas Soome 	free(tem->tvs_screen_buf);
3209890ff83SToomas Soome 	tem->tvs_screen_buf = NULL;
321ba2848d4SToomas Soome 
322ba2848d4SToomas Soome 	free(tem->tvs_tabs);
323ba2848d4SToomas Soome 	tem->tvs_tabs = NULL;
3249890ff83SToomas Soome }
3259890ff83SToomas Soome 
3269890ff83SToomas Soome static int
tems_failed(bool finish_ioctl)327ffd79eb6SToomas Soome tems_failed(bool finish_ioctl)
3289890ff83SToomas Soome {
3299890ff83SToomas Soome 	if (finish_ioctl && tems.ts_hdl != NULL)
3309890ff83SToomas Soome 		(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_DEVFINI, NULL);
3319890ff83SToomas Soome 
3329890ff83SToomas Soome 	tems.ts_hdl = NULL;
3339890ff83SToomas Soome 	return (ENXIO);
3349890ff83SToomas Soome }
3359890ff83SToomas Soome 
3369890ff83SToomas Soome /*
3379890ff83SToomas Soome  * Only called once during boot
3389890ff83SToomas Soome  */
3399890ff83SToomas Soome int
tem_info_init(struct console * cp)3409890ff83SToomas Soome tem_info_init(struct console *cp)
3419890ff83SToomas Soome {
3429890ff83SToomas Soome 	int			ret;
3439890ff83SToomas Soome 	struct vis_devinit	temargs;
3449890ff83SToomas Soome 	size_t height = 0;
3459890ff83SToomas Soome 	size_t width = 0;
3469890ff83SToomas Soome 	struct tem_vt_state *p;
3479890ff83SToomas Soome 
3489890ff83SToomas Soome 	if (tems.ts_initialized) {
3499890ff83SToomas Soome 		return (0);
3509890ff83SToomas Soome 	}
3519890ff83SToomas Soome 
3529890ff83SToomas Soome 	list_create(&tems.ts_list, sizeof (struct tem_vt_state),
3539890ff83SToomas Soome 	    __offsetof(struct tem_vt_state, tvs_list_node));
3549890ff83SToomas Soome 	tems.ts_active = NULL;
3559890ff83SToomas Soome 
3569890ff83SToomas Soome 	tems.ts_hdl = cp;
3579890ff83SToomas Soome 	bzero(&temargs, sizeof (temargs));
3589890ff83SToomas Soome 	temargs.modechg_cb  = (vis_modechg_cb_t)tems_modechange_callback;
3599890ff83SToomas Soome 	temargs.modechg_arg = NULL;
3609890ff83SToomas Soome 
3619890ff83SToomas Soome 	/*
3629890ff83SToomas Soome 	 * Initialize the console and get the device parameters
3639890ff83SToomas Soome 	 */
3649890ff83SToomas Soome 	if (cp->c_ioctl(cp, VIS_DEVINIT, &temargs) != 0) {
3659890ff83SToomas Soome 		printf("terminal emulator: Compatible fb not found\n");
366ffd79eb6SToomas Soome 		ret = tems_failed(false);
3679890ff83SToomas Soome 		return (ret);
3689890ff83SToomas Soome 	}
3699890ff83SToomas Soome 
3709890ff83SToomas Soome 	/* Make sure the fb driver and terminal emulator versions match */
3719890ff83SToomas Soome 	if (temargs.version != VIS_CONS_REV) {
3729890ff83SToomas Soome 		printf(
3739890ff83SToomas Soome 		    "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
3749890ff83SToomas Soome 		    "of console fb driver not supported\n", temargs.version);
375ffd79eb6SToomas Soome 		ret = tems_failed(true);
3769890ff83SToomas Soome 		return (ret);
3779890ff83SToomas Soome 	}
3789890ff83SToomas Soome 
3799890ff83SToomas Soome 	/* other sanity checks */
3809890ff83SToomas Soome 	if (!((temargs.depth == 4) || (temargs.depth == 8) ||
3819890ff83SToomas Soome 	    (temargs.depth == 15) || (temargs.depth == 16) ||
3829890ff83SToomas Soome 	    (temargs.depth == 24) || (temargs.depth == 32))) {
3839890ff83SToomas Soome 		printf("terminal emulator: unsupported depth\n");
384ffd79eb6SToomas Soome 		ret = tems_failed(true);
3859890ff83SToomas Soome 		return (ret);
3869890ff83SToomas Soome 	}
3879890ff83SToomas Soome 
3889890ff83SToomas Soome 	if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) {
3899890ff83SToomas Soome 		printf("terminal emulator: unsupported mode\n");
390ffd79eb6SToomas Soome 		ret = tems_failed(true);
3919890ff83SToomas Soome 		return (ret);
3929890ff83SToomas Soome 	}
3939890ff83SToomas Soome 
3949890ff83SToomas Soome 	plat_tem_get_prom_size(&height, &width);
3959890ff83SToomas Soome 
3969890ff83SToomas Soome 	/*
3979890ff83SToomas Soome 	 * Initialize the common terminal emulator info
3989890ff83SToomas Soome 	 */
3999890ff83SToomas Soome 	tems_setup_terminal(&temargs, height, width);
4009890ff83SToomas Soome 
4019890ff83SToomas Soome 	tems_reset_colormap();
4029890ff83SToomas Soome 	tems_get_initial_color(&tems.ts_init_color);
4039890ff83SToomas Soome 
4049890ff83SToomas Soome 	tems.ts_initialized = 1; /* initialization flag */
4059890ff83SToomas Soome 
4069890ff83SToomas Soome 	for (p = list_head(&tems.ts_list); p != NULL;
4079890ff83SToomas Soome 	    p = list_next(&tems.ts_list, p)) {
408ffd79eb6SToomas Soome 		tem_internal_init(p, true, false);
4099890ff83SToomas Soome 		if (temargs.mode == VIS_PIXEL)
4109890ff83SToomas Soome 			tem_pix_align(p);
4119890ff83SToomas Soome 	}
4129890ff83SToomas Soome 
4139890ff83SToomas Soome 	return (0);
4149890ff83SToomas Soome }
4159890ff83SToomas Soome 
4169890ff83SToomas Soome #define	TEMS_DEPTH_DIFF		0x01
4179890ff83SToomas Soome #define	TEMS_DIMENSION_DIFF	0x02
4189890ff83SToomas Soome 
4199890ff83SToomas Soome static uint8_t
tems_check_videomode(struct vis_devinit * tp)4209890ff83SToomas Soome tems_check_videomode(struct vis_devinit *tp)
4219890ff83SToomas Soome {
4229890ff83SToomas Soome 	uint8_t result = 0;
4239890ff83SToomas Soome 
4249890ff83SToomas Soome 	if (tems.ts_pdepth != tp->depth)
4259890ff83SToomas Soome 		result |= TEMS_DEPTH_DIFF;
4269890ff83SToomas Soome 
4279890ff83SToomas Soome 	if (tp->mode == VIS_TEXT) {
4289890ff83SToomas Soome 		if (tems.ts_c_dimension.width != tp->width ||
4299890ff83SToomas Soome 		    tems.ts_c_dimension.height != tp->height)
4309890ff83SToomas Soome 			result |= TEMS_DIMENSION_DIFF;
4319890ff83SToomas Soome 	} else {
4329890ff83SToomas Soome 		if (tems.ts_p_dimension.width != tp->width ||
4339890ff83SToomas Soome 		    tems.ts_p_dimension.height != tp->height)
4349890ff83SToomas Soome 			result |= TEMS_DIMENSION_DIFF;
4359890ff83SToomas Soome 	}
4369890ff83SToomas Soome 	if (tems.update_font == true)
4379890ff83SToomas Soome 		result |= TEMS_DIMENSION_DIFF;
4389890ff83SToomas Soome 
4399890ff83SToomas Soome 	return (result);
4409890ff83SToomas Soome }
4419890ff83SToomas Soome 
4429890ff83SToomas Soome static int
env_screen_nounset(struct env_var * ev __unused)4439890ff83SToomas Soome env_screen_nounset(struct env_var *ev __unused)
4449890ff83SToomas Soome {
4459890ff83SToomas Soome 	if (tems.ts_p_dimension.width == 0 &&
4469890ff83SToomas Soome 	    tems.ts_p_dimension.height == 0)
4479890ff83SToomas Soome 		return (0);
448f6760972SToomas Soome 	return (EPERM);
4499890ff83SToomas Soome }
4509890ff83SToomas Soome 
4519890ff83SToomas Soome static void
tems_setup_font(screen_size_t height,screen_size_t width)452c781d872SToomas Soome tems_setup_font(screen_size_t height, screen_size_t width)
4539890ff83SToomas Soome {
4549890ff83SToomas Soome 	bitmap_data_t *font_data;
455c781d872SToomas Soome 
456c781d872SToomas Soome 	/*
457e0721d5aSToomas Soome 	 * set_font() will select an appropriate sized font for
458c781d872SToomas Soome 	 * the number of rows and columns selected.  If we don't
459c781d872SToomas Soome 	 * have a font that will fit, then it will use the
460c781d872SToomas Soome 	 * default builtin font and adjust the rows and columns
461c781d872SToomas Soome 	 * to fit on the screen.
462c781d872SToomas Soome 	 */
463c781d872SToomas Soome 	font_data = set_font(&tems.ts_c_dimension.height,
464c781d872SToomas Soome 	    &tems.ts_c_dimension.width, height, width);
465c781d872SToomas Soome 
466e0721d5aSToomas Soome 	if (font_data == NULL)
467e0721d5aSToomas Soome 		panic("out of memory");
468e0721d5aSToomas Soome 
469c781d872SToomas Soome 	/*
470e0721d5aSToomas Soome 	 * To use loaded font, we assign the loaded font data to tems.ts_font.
471e0721d5aSToomas Soome 	 * In case of next load, the previously loaded data is freed
472e0721d5aSToomas Soome 	 * when loading the new font.
473c781d872SToomas Soome 	 */
474e0721d5aSToomas Soome 	for (int i = 0; i < VFNT_MAPS; i++) {
475e0721d5aSToomas Soome 		tems.ts_font.vf_map[i] =
476e0721d5aSToomas Soome 		    font_data->font->vf_map[i];
477e0721d5aSToomas Soome 		tems.ts_font.vf_map_count[i] =
478e0721d5aSToomas Soome 		    font_data->font->vf_map_count[i];
479c781d872SToomas Soome 	}
480e0721d5aSToomas Soome 
481e0721d5aSToomas Soome 	tems.ts_font.vf_bytes = font_data->font->vf_bytes;
482e0721d5aSToomas Soome 	tems.ts_font.vf_width = font_data->font->vf_width;
483e0721d5aSToomas Soome 	tems.ts_font.vf_height = font_data->font->vf_height;
484c781d872SToomas Soome }
485c781d872SToomas Soome 
486c781d872SToomas Soome static void
tems_setup_terminal(struct vis_devinit * tp,size_t height,size_t width)487c781d872SToomas Soome tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width)
488c781d872SToomas Soome {
4899890ff83SToomas Soome 	char env[8];
4909890ff83SToomas Soome 
4919890ff83SToomas Soome 	tems.ts_pdepth = tp->depth;
4929890ff83SToomas Soome 	tems.ts_linebytes = tp->linebytes;
4939890ff83SToomas Soome 	tems.ts_display_mode = tp->mode;
4949890ff83SToomas Soome 	tems.ts_color_map = tp->color_map;
4959890ff83SToomas Soome 
4969890ff83SToomas Soome 	switch (tp->mode) {
4979890ff83SToomas Soome 	case VIS_TEXT:
498c781d872SToomas Soome 		/* Set fake pixel dimensions to assist set_font() */
4999890ff83SToomas Soome 		tems.ts_p_dimension.width = 0;
5009890ff83SToomas Soome 		tems.ts_p_dimension.height = 0;
5019890ff83SToomas Soome 		tems.ts_c_dimension.width = tp->width;
5029890ff83SToomas Soome 		tems.ts_c_dimension.height = tp->height;
5039890ff83SToomas Soome 		tems.ts_callbacks = &tem_text_callbacks;
5049890ff83SToomas Soome 
505c781d872SToomas Soome 		tems_setup_font(16 * tp->height + BORDER_PIXELS,
506c781d872SToomas Soome 		    8 * tp->width + BORDER_PIXELS);
5079890ff83SToomas Soome 
5089890ff83SToomas Soome 		/* ensure the following are not set for text mode */
5099890ff83SToomas Soome 		unsetenv("screen-height");
5109890ff83SToomas Soome 		unsetenv("screen-width");
5119890ff83SToomas Soome 		break;
5129890ff83SToomas Soome 
5139890ff83SToomas Soome 	case VIS_PIXEL:
5149890ff83SToomas Soome 		/*
5159890ff83SToomas Soome 		 * First check to see if the user has specified a screen size.
5169890ff83SToomas Soome 		 * If so, use those values.  Else use 34x80 as the default.
5179890ff83SToomas Soome 		 */
5189890ff83SToomas Soome 		if (width == 0) {
5199890ff83SToomas Soome 			width = TEM_DEFAULT_COLS;
5209890ff83SToomas Soome 			height = TEM_DEFAULT_ROWS;
5219890ff83SToomas Soome 		}
5229890ff83SToomas Soome 		tems.ts_c_dimension.height = (screen_size_t)height;
5239890ff83SToomas Soome 		tems.ts_c_dimension.width = (screen_size_t)width;
5249890ff83SToomas Soome 		tems.ts_p_dimension.height = tp->height;
5259890ff83SToomas Soome 		tems.ts_p_dimension.width = tp->width;
5269890ff83SToomas Soome 		tems.ts_callbacks = &tem_pix_callbacks;
5279890ff83SToomas Soome 
528c781d872SToomas Soome 		tems_setup_font(tp->height, tp->width);
5299890ff83SToomas Soome 
5309890ff83SToomas Soome 		snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.height);
5319890ff83SToomas Soome 		env_setenv("screen-height", EV_VOLATILE | EV_NOHOOK, env,
5329890ff83SToomas Soome 		    env_noset, env_screen_nounset);
5339890ff83SToomas Soome 		snprintf(env, sizeof (env), "%d", tems.ts_p_dimension.width);
5349890ff83SToomas Soome 		env_setenv("screen-width", EV_VOLATILE | EV_NOHOOK, env,
5359890ff83SToomas Soome 		    env_noset, env_screen_nounset);
5369890ff83SToomas Soome 
5379890ff83SToomas Soome 		tems.ts_p_offset.y = (tems.ts_p_dimension.height -
5389890ff83SToomas Soome 		    (tems.ts_c_dimension.height * tems.ts_font.vf_height)) / 2;
5399890ff83SToomas Soome 		tems.ts_p_offset.x = (tems.ts_p_dimension.width -
5409890ff83SToomas Soome 		    (tems.ts_c_dimension.width * tems.ts_font.vf_width)) / 2;
5419890ff83SToomas Soome 		tems.ts_pix_data_size =
5429890ff83SToomas Soome 		    tems.ts_font.vf_width * tems.ts_font.vf_height;
5439890ff83SToomas Soome 		tems.ts_pix_data_size *= 4;
5449890ff83SToomas Soome 		tems.ts_pdepth = tp->depth;
5459890ff83SToomas Soome 
5469890ff83SToomas Soome 		break;
5479890ff83SToomas Soome 	}
548c781d872SToomas Soome 
549c781d872SToomas Soome 	tems.update_font = false;
550c781d872SToomas Soome 
551c781d872SToomas Soome 	snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.height);
552c781d872SToomas Soome 	env_setenv("screen-#rows", EV_VOLATILE | EV_NOHOOK, env,
553c781d872SToomas Soome 	    env_noset, env_nounset);
554c781d872SToomas Soome 	snprintf(env, sizeof (env), "%d", tems.ts_c_dimension.width);
555c781d872SToomas Soome 	env_setenv("screen-#cols", EV_VOLATILE | EV_NOHOOK, env,
556c781d872SToomas Soome 	    env_noset, env_nounset);
557c781d872SToomas Soome 
558c781d872SToomas Soome 	snprintf(env, sizeof (env), "%dx%d", tems.ts_font.vf_width,
559c781d872SToomas Soome 	    tems.ts_font.vf_height);
560c781d872SToomas Soome 	env_setenv("screen-font", EV_VOLATILE | EV_NOHOOK, env, NULL,
561c781d872SToomas Soome 	    NULL);
5629890ff83SToomas Soome }
5639890ff83SToomas Soome 
5649890ff83SToomas Soome /*
5659890ff83SToomas Soome  * This is a callback function that we register with the frame
5669890ff83SToomas Soome  * buffer driver layered underneath.  It gets invoked from
5679890ff83SToomas Soome  * the underlying frame buffer driver to reconfigure the terminal
5689890ff83SToomas Soome  * emulator to a new screen size and depth in conjunction with
5699890ff83SToomas Soome  * framebuffer videomode changes.
5709890ff83SToomas Soome  * Here we keep the foreground/background color and attributes,
5719890ff83SToomas Soome  * which may be different with the initial settings, so that
5729890ff83SToomas Soome  * the color won't change while the framebuffer videomode changes.
5739890ff83SToomas Soome  * And we also reset the kernel terminal emulator and clear the
5749890ff83SToomas Soome  * whole screen.
5759890ff83SToomas Soome  */
5769890ff83SToomas Soome /* ARGSUSED */
5779890ff83SToomas Soome void
tems_modechange_callback(struct vis_modechg_arg * arg __unused,struct vis_devinit * devinit)5789890ff83SToomas Soome tems_modechange_callback(struct vis_modechg_arg *arg __unused,
5799890ff83SToomas Soome     struct vis_devinit *devinit)
5809890ff83SToomas Soome {
5819890ff83SToomas Soome 	uint8_t diff;
5829890ff83SToomas Soome 	struct tem_vt_state *p;
5839890ff83SToomas Soome 	tem_modechg_cb_t cb;
5849890ff83SToomas Soome 	tem_modechg_cb_arg_t cb_arg;
5859890ff83SToomas Soome 	size_t height = 0;
5869890ff83SToomas Soome 	size_t width = 0;
587726d8a6eSToomas Soome 	int state;
5889890ff83SToomas Soome 
5899890ff83SToomas Soome 	diff = tems_check_videomode(devinit);
5909890ff83SToomas Soome 	if (diff == 0) {
5919890ff83SToomas Soome 		/*
5929890ff83SToomas Soome 		 * This is color related change, reset color and redraw the
5939890ff83SToomas Soome 		 * screen. Only need to reinit the active tem.
5949890ff83SToomas Soome 		 */
5959890ff83SToomas Soome 		struct tem_vt_state *active = tems.ts_active;
5969890ff83SToomas Soome 		tems_get_initial_color(&tems.ts_init_color);
5979890ff83SToomas Soome 		active->tvs_fg_color = tems.ts_init_color.fg_color;
5989890ff83SToomas Soome 		active->tvs_bg_color = tems.ts_init_color.bg_color;
5999890ff83SToomas Soome 		active->tvs_flags = tems.ts_init_color.a_flags;
600ffd79eb6SToomas Soome 		tem_reinit(active, true);
6019890ff83SToomas Soome 		return;
6029890ff83SToomas Soome 	}
6039890ff83SToomas Soome 
6049890ff83SToomas Soome 	diff = diff & TEMS_DIMENSION_DIFF;
6059890ff83SToomas Soome 
6069890ff83SToomas Soome 	if (diff == 0) {
6079890ff83SToomas Soome 		/*
6089890ff83SToomas Soome 		 * Only need to reinit the active tem.
6099890ff83SToomas Soome 		 */
6109890ff83SToomas Soome 		struct tem_vt_state *active = tems.ts_active;
6119890ff83SToomas Soome 		tems.ts_pdepth = devinit->depth;
6129890ff83SToomas Soome 		/* color depth did change, reset colors */
6139890ff83SToomas Soome 		tems_reset_colormap();
6149890ff83SToomas Soome 		tems_get_initial_color(&tems.ts_init_color);
615ffd79eb6SToomas Soome 		tem_reinit(active, true);
6169890ff83SToomas Soome 
6179890ff83SToomas Soome 		return;
6189890ff83SToomas Soome 	}
6199890ff83SToomas Soome 
6209890ff83SToomas Soome 	plat_tem_get_prom_size(&height, &width);
6219890ff83SToomas Soome 
622726d8a6eSToomas Soome 	state = tems.ts_initialized;
623726d8a6eSToomas Soome 	tems.ts_initialized = 0;	/* stop all output */
6249890ff83SToomas Soome 	tems_setup_terminal(devinit, height, width);
6259890ff83SToomas Soome 
6269890ff83SToomas Soome 	tems_reset_colormap();
6279890ff83SToomas Soome 	tems_get_initial_color(&tems.ts_init_color);
628726d8a6eSToomas Soome 	tems.ts_initialized = state;	/* restore state */
6299890ff83SToomas Soome 
6309890ff83SToomas Soome 	for (p = list_head(&tems.ts_list); p != NULL;
6319890ff83SToomas Soome 	    p = list_next(&tems.ts_list, p)) {
6329890ff83SToomas Soome 		tem_reinit(p, p->tvs_isactive);
6339890ff83SToomas Soome 	}
6349890ff83SToomas Soome 
6359890ff83SToomas Soome 
6369890ff83SToomas Soome 	if (tems.ts_modechg_cb == NULL) {
6379890ff83SToomas Soome 		return;
6389890ff83SToomas Soome 	}
6399890ff83SToomas Soome 
6409890ff83SToomas Soome 	cb = tems.ts_modechg_cb;
6419890ff83SToomas Soome 	cb_arg = tems.ts_modechg_arg;
6429890ff83SToomas Soome 
6439890ff83SToomas Soome 	cb(cb_arg);
6449890ff83SToomas Soome }
6459890ff83SToomas Soome 
6469890ff83SToomas Soome /*
6479890ff83SToomas Soome  * This function is used to clear entire screen via the underlying framebuffer
6489890ff83SToomas Soome  * driver.
6499890ff83SToomas Soome  */
6509890ff83SToomas Soome int
tems_cls(struct vis_consclear * pda)6519890ff83SToomas Soome tems_cls(struct vis_consclear *pda)
6529890ff83SToomas Soome {
6539890ff83SToomas Soome 	if (tems.ts_hdl == NULL)
6549890ff83SToomas Soome 		return (1);
6559890ff83SToomas Soome 	return (tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCLEAR, pda));
6569890ff83SToomas Soome }
6579890ff83SToomas Soome 
6589890ff83SToomas Soome /*
6599890ff83SToomas Soome  * This function is used to display a rectangular blit of data
6609890ff83SToomas Soome  * of a given size and location via the underlying framebuffer driver.
6619890ff83SToomas Soome  * The blit can be as small as a pixel or as large as the screen.
6629890ff83SToomas Soome  */
6639890ff83SToomas Soome void
tems_display(struct vis_consdisplay * pda)6649890ff83SToomas Soome tems_display(struct vis_consdisplay *pda)
6659890ff83SToomas Soome {
6669890ff83SToomas Soome 	if (tems.ts_hdl != NULL)
6679890ff83SToomas Soome 		(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSDISPLAY, pda);
6689890ff83SToomas Soome }
6699890ff83SToomas Soome 
6709890ff83SToomas Soome /*
6719890ff83SToomas Soome  * This function is used to invoke a block copy operation in the
6729890ff83SToomas Soome  * underlying framebuffer driver.  Rectangle copies are how scrolling
6739890ff83SToomas Soome  * is implemented, as well as horizontal text shifting escape seqs.
6749890ff83SToomas Soome  * such as from vi when deleting characters and words.
6759890ff83SToomas Soome  */
6769890ff83SToomas Soome void
tems_copy(struct vis_conscopy * pma)6779890ff83SToomas Soome tems_copy(struct vis_conscopy *pma)
6789890ff83SToomas Soome {
6799890ff83SToomas Soome 	if (tems.ts_hdl != NULL)
6809890ff83SToomas Soome 		(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCOPY, pma);
6819890ff83SToomas Soome }
6829890ff83SToomas Soome 
6839890ff83SToomas Soome /*
6849890ff83SToomas Soome  * This function is used to show or hide a rectangluar monochrom
6859890ff83SToomas Soome  * pixel inverting, text block cursor via the underlying framebuffer.
6869890ff83SToomas Soome  */
6879890ff83SToomas Soome void
tems_cursor(struct vis_conscursor * pca)6889890ff83SToomas Soome tems_cursor(struct vis_conscursor *pca)
6899890ff83SToomas Soome {
6909890ff83SToomas Soome 	if (tems.ts_hdl != NULL)
6919890ff83SToomas Soome 		(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, VIS_CONSCURSOR, pca);
6929890ff83SToomas Soome }
6939890ff83SToomas Soome 
6949890ff83SToomas Soome static void
tem_kdsetmode(int mode)6959890ff83SToomas Soome tem_kdsetmode(int mode)
6969890ff83SToomas Soome {
697f6760972SToomas Soome 	if (tems.ts_hdl != NULL) {
6989890ff83SToomas Soome 		(void) tems.ts_hdl->c_ioctl(tems.ts_hdl, KDSETMODE,
699f6760972SToomas Soome 		    (void *)(intptr_t)mode);
700f6760972SToomas Soome 	}
7019890ff83SToomas Soome }
7029890ff83SToomas Soome 
7039890ff83SToomas Soome static void
tems_reset_colormap(void)7049890ff83SToomas Soome tems_reset_colormap(void)
7059890ff83SToomas Soome {
7069890ff83SToomas Soome 	struct vis_cmap cm;
7079890ff83SToomas Soome 
7089890ff83SToomas Soome 	switch (tems.ts_pdepth) {
7099890ff83SToomas Soome 	case 8:
7109890ff83SToomas Soome 		cm.index = 0;
7119890ff83SToomas Soome 		cm.count = 16;
7129890ff83SToomas Soome 		/* 8-bits (1/3 of TrueColor 24) */
7139890ff83SToomas Soome 		cm.red   = (uint8_t *)cmap4_to_24.red;
7149890ff83SToomas Soome 		/* 8-bits (1/3 of TrueColor 24) */
7159890ff83SToomas Soome 		cm.blue  = (uint8_t *)cmap4_to_24.blue;
7169890ff83SToomas Soome 		/* 8-bits (1/3 of TrueColor 24) */
7179890ff83SToomas Soome 		cm.green = (uint8_t *)cmap4_to_24.green;
7189890ff83SToomas Soome 		if (tems.ts_hdl != NULL)
7199890ff83SToomas Soome 			(void) tems.ts_hdl->c_ioctl(tems.ts_hdl,
7209890ff83SToomas Soome 			    VIS_PUTCMAP, &cm);
7219890ff83SToomas Soome 		break;
7229890ff83SToomas Soome 	}
7239890ff83SToomas Soome }
7249890ff83SToomas Soome 
7259890ff83SToomas Soome void
tem_get_size(uint16_t * r,uint16_t * c,uint16_t * x,uint16_t * y)7269890ff83SToomas Soome tem_get_size(uint16_t *r, uint16_t *c, uint16_t *x, uint16_t *y)
7279890ff83SToomas Soome {
7289890ff83SToomas Soome 	*r = (uint16_t)tems.ts_c_dimension.height;
7299890ff83SToomas Soome 	*c = (uint16_t)tems.ts_c_dimension.width;
7309890ff83SToomas Soome 	*x = (uint16_t)tems.ts_p_dimension.width;
7319890ff83SToomas Soome 	*y = (uint16_t)tems.ts_p_dimension.height;
7329890ff83SToomas Soome }
7339890ff83SToomas Soome 
7349890ff83SToomas Soome /*
7359890ff83SToomas Soome  * Loader extension. Store important data in environment. Intended to be used
7369890ff83SToomas Soome  * just before booting the OS to make the data available in kernel
7379890ff83SToomas Soome  * environment module.
7389890ff83SToomas Soome  */
7399890ff83SToomas Soome void
tem_save_state(void)7409890ff83SToomas Soome tem_save_state(void)
7419890ff83SToomas Soome {
7429890ff83SToomas Soome 	struct tem_vt_state *active = tems.ts_active;
7439890ff83SToomas Soome 	char buf[80];
7449890ff83SToomas Soome 
7459890ff83SToomas Soome 	/*
7469890ff83SToomas Soome 	 * We already have in environment:
7479890ff83SToomas Soome 	 * tem.inverse, tem.inverse_screen
7489890ff83SToomas Soome 	 * tem.fg_color, tem.bg_color.
7499890ff83SToomas Soome 	 * So we only need to add the position of the cursor.
7509890ff83SToomas Soome 	 */
7519890ff83SToomas Soome 
7529890ff83SToomas Soome 	if (active != NULL) {
7539890ff83SToomas Soome 		snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.col);
7549890ff83SToomas Soome 		setenv("tem.cursor.col", buf, 1);
7559890ff83SToomas Soome 		snprintf(buf, sizeof (buf), "%d", active->tvs_c_cursor.row);
7569890ff83SToomas Soome 		setenv("tem.cursor.row", buf, 1);
7579890ff83SToomas Soome 	}
7589890ff83SToomas Soome }
7599890ff83SToomas Soome 
7609890ff83SToomas Soome void
tem_register_modechg_cb(tem_modechg_cb_t func,tem_modechg_cb_arg_t arg)7619890ff83SToomas Soome tem_register_modechg_cb(tem_modechg_cb_t func, tem_modechg_cb_arg_t arg)
7629890ff83SToomas Soome {
7639890ff83SToomas Soome 	tems.ts_modechg_cb = func;
7649890ff83SToomas Soome 	tems.ts_modechg_arg = arg;
7659890ff83SToomas Soome }
7669890ff83SToomas Soome 
7679890ff83SToomas Soome /*
7689890ff83SToomas Soome  * This function is to scroll up the OBP output, which has
7699890ff83SToomas Soome  * different screen height and width with our kernel console.
7709890ff83SToomas Soome  */
7719890ff83SToomas Soome static void
tem_prom_scroll_up(struct tem_vt_state * tem,int nrows)7729890ff83SToomas Soome tem_prom_scroll_up(struct tem_vt_state *tem, int nrows)
7739890ff83SToomas Soome {
7749890ff83SToomas Soome 	struct vis_conscopy	ma;
7759890ff83SToomas Soome 	int	ncols, width;
7769890ff83SToomas Soome 
7779890ff83SToomas Soome 	/* copy */
7789890ff83SToomas Soome 	ma.s_row = nrows * tems.ts_font.vf_height;
7799890ff83SToomas Soome 	ma.e_row = tems.ts_p_dimension.height - 1;
7809890ff83SToomas Soome 	ma.t_row = 0;
7819890ff83SToomas Soome 
7829890ff83SToomas Soome 	ma.s_col = 0;
7839890ff83SToomas Soome 	ma.e_col = tems.ts_p_dimension.width - 1;
7849890ff83SToomas Soome 	ma.t_col = 0;
7859890ff83SToomas Soome 
7869890ff83SToomas Soome 	tems_copy(&ma);
7879890ff83SToomas Soome 
7889890ff83SToomas Soome 	/* clear */
7899890ff83SToomas Soome 	width = tems.ts_font.vf_width;
790726d8a6eSToomas Soome 	ncols = (tems.ts_p_dimension.width + (width - 1)) / width;
7919890ff83SToomas Soome 
7929890ff83SToomas Soome 	tem_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y,
793ffd79eb6SToomas Soome 	    0, ncols, 0, true);
7949890ff83SToomas Soome }
7959890ff83SToomas Soome 
7969890ff83SToomas Soome /*
7979890ff83SToomas Soome  * This function is to compute the starting row of the console, according to
7989890ff83SToomas Soome  * PROM cursor's position. Here we have to take different fonts into account.
7999890ff83SToomas Soome  */
8009890ff83SToomas Soome static int
tem_adjust_row(struct tem_vt_state * tem,int prom_row)8019890ff83SToomas Soome tem_adjust_row(struct tem_vt_state *tem, int prom_row)
8029890ff83SToomas Soome {
8039890ff83SToomas Soome 	int	tem_row;
8049890ff83SToomas Soome 	int	tem_y;
8059890ff83SToomas Soome 	int	prom_charheight = 0;
8069890ff83SToomas Soome 	int	prom_window_top = 0;
8079890ff83SToomas Soome 	int	scroll_up_lines;
8089890ff83SToomas Soome 
8099890ff83SToomas Soome 	plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top);
8109890ff83SToomas Soome 	if (prom_charheight == 0)
8119890ff83SToomas Soome 		prom_charheight = tems.ts_font.vf_height;
8129890ff83SToomas Soome 
8139890ff83SToomas Soome 	tem_y = (prom_row + 1) * prom_charheight + prom_window_top -
8149890ff83SToomas Soome 	    tems.ts_p_offset.y;
8159890ff83SToomas Soome 	tem_row = (tem_y + tems.ts_font.vf_height - 1) /
8169890ff83SToomas Soome 	    tems.ts_font.vf_height - 1;
8179890ff83SToomas Soome 
8189890ff83SToomas Soome 	if (tem_row < 0) {
8199890ff83SToomas Soome 		tem_row = 0;
8209890ff83SToomas Soome 	} else if (tem_row >= (tems.ts_c_dimension.height - 1)) {
8219890ff83SToomas Soome 		/*
8229890ff83SToomas Soome 		 * Scroll up the prom outputs if the PROM cursor's position is
8239890ff83SToomas Soome 		 * below our tem's lower boundary.
8249890ff83SToomas Soome 		 */
8259890ff83SToomas Soome 		scroll_up_lines = tem_row -
8269890ff83SToomas Soome 		    (tems.ts_c_dimension.height - 1);
8279890ff83SToomas Soome 		tem_prom_scroll_up(tem, scroll_up_lines);
8289890ff83SToomas Soome 		tem_row = tems.ts_c_dimension.height - 1;
8299890ff83SToomas Soome 	}
8309890ff83SToomas Soome 
8319890ff83SToomas Soome 	return (tem_row);
8329890ff83SToomas Soome }
8339890ff83SToomas Soome 
8349890ff83SToomas Soome static void
tem_pix_align(struct tem_vt_state * tem)8359890ff83SToomas Soome tem_pix_align(struct tem_vt_state *tem)
8369890ff83SToomas Soome {
8379890ff83SToomas Soome 	uint32_t row = 0;
8389890ff83SToomas Soome 	uint32_t col = 0;
8399890ff83SToomas Soome 
8409890ff83SToomas Soome 	if (plat_stdout_is_framebuffer()) {
8419890ff83SToomas Soome 		plat_tem_hide_prom_cursor();
8429890ff83SToomas Soome 
8439890ff83SToomas Soome 		/*
8449890ff83SToomas Soome 		 * We are getting the current cursor position in pixel
8459890ff83SToomas Soome 		 * mode so that we don't over-write the console output
8469890ff83SToomas Soome 		 * during boot.
8479890ff83SToomas Soome 		 */
8489890ff83SToomas Soome 		plat_tem_get_prom_pos(&row, &col);
8499890ff83SToomas Soome 
8509890ff83SToomas Soome 		/*
8519890ff83SToomas Soome 		 * Adjust the row if necessary when the font of our
8529890ff83SToomas Soome 		 * kernel console tem is different with that of prom
8539890ff83SToomas Soome 		 * tem.
8549890ff83SToomas Soome 		 */
8559890ff83SToomas Soome 		row = tem_adjust_row(tem, row);
8569890ff83SToomas Soome 
8579890ff83SToomas Soome 		/* first line of our kernel console output */
8589890ff83SToomas Soome 		tem->tvs_first_line = row + 1;
8599890ff83SToomas Soome 
8609890ff83SToomas Soome 		/* re-set and align cursor position */
8619890ff83SToomas Soome 		tem->tvs_s_cursor.row = tem->tvs_c_cursor.row =
8629890ff83SToomas Soome 		    (screen_pos_t)row;
8639890ff83SToomas Soome 		tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0;
8649890ff83SToomas Soome 	} else {
865ffd79eb6SToomas Soome 		tem_reset_display(tem, true, true);
8669890ff83SToomas Soome 	}
8679890ff83SToomas Soome }
8689890ff83SToomas Soome 
8699890ff83SToomas Soome static void
tems_get_inverses(bool * p_inverse,bool * p_inverse_screen)870ffd79eb6SToomas Soome tems_get_inverses(bool *p_inverse, bool *p_inverse_screen)
8719890ff83SToomas Soome {
8729890ff83SToomas Soome 	int i_inverse = 0;
8739890ff83SToomas Soome 	int i_inverse_screen = 0;
8749890ff83SToomas Soome 
8759890ff83SToomas Soome 	plat_tem_get_inverses(&i_inverse, &i_inverse_screen);
8769890ff83SToomas Soome 
877ffd79eb6SToomas Soome 	*p_inverse = i_inverse != 0;
878ffd79eb6SToomas Soome 	*p_inverse_screen = i_inverse_screen != 0;
8799890ff83SToomas Soome }
8809890ff83SToomas Soome 
8819890ff83SToomas Soome /*
8829890ff83SToomas Soome  * Get the foreground/background color and attributes from environment.
8839890ff83SToomas Soome  */
8849890ff83SToomas Soome static void
tems_get_initial_color(tem_color_t * pcolor)8859890ff83SToomas Soome tems_get_initial_color(tem_color_t *pcolor)
8869890ff83SToomas Soome {
887ffd79eb6SToomas Soome 	bool inverse, inverse_screen;
8889890ff83SToomas Soome 	unsigned short  flags = 0;
889fa9eb222SToomas Soome 	uint8_t fg, bg;
8909890ff83SToomas Soome 
891fa9eb222SToomas Soome 	fg = DEFAULT_ANSI_FOREGROUND;
892fa9eb222SToomas Soome 	bg = DEFAULT_ANSI_BACKGROUND;
893fa9eb222SToomas Soome 	plat_tem_get_colors(&fg, &bg);
894fa9eb222SToomas Soome 	pcolor->fg_color.n = fg;
895fa9eb222SToomas Soome 	pcolor->bg_color.n = bg;
8969890ff83SToomas Soome 
8979890ff83SToomas Soome 	tems_get_inverses(&inverse, &inverse_screen);
8989890ff83SToomas Soome 	if (inverse)
8999890ff83SToomas Soome 		flags |= TEM_ATTR_REVERSE;
9009890ff83SToomas Soome 	if (inverse_screen)
9019890ff83SToomas Soome 		flags |= TEM_ATTR_SCREEN_REVERSE;
9029890ff83SToomas Soome 
9039890ff83SToomas Soome 	if (flags != 0) {
9049890ff83SToomas Soome 		/*
905e0721d5aSToomas Soome 		 * The reverse attribute is set.
906e0721d5aSToomas Soome 		 * In case of black on white we want bright white for BG.
907e0721d5aSToomas Soome 		 */
908fa9eb222SToomas Soome 		if (pcolor->fg_color.n == ANSI_COLOR_WHITE)
909e0721d5aSToomas Soome 			flags |= TEM_ATTR_BRIGHT_BG;
910e0721d5aSToomas Soome 
911e0721d5aSToomas Soome 		/*
912e0721d5aSToomas Soome 		 * For white on black, unset the bright attribute we
913e0721d5aSToomas Soome 		 * had set to have bright white background.
9149890ff83SToomas Soome 		 */
915fa9eb222SToomas Soome 		if (pcolor->fg_color.n == ANSI_COLOR_BLACK)
916e0721d5aSToomas Soome 			flags &= ~TEM_ATTR_BRIGHT_BG;
9179890ff83SToomas Soome 	} else {
9189890ff83SToomas Soome 		/*
919e0721d5aSToomas Soome 		 * In case of black on white we want bright white for BG.
9209890ff83SToomas Soome 		 */
921fa9eb222SToomas Soome 		if (pcolor->bg_color.n == ANSI_COLOR_WHITE)
9229890ff83SToomas Soome 			flags |= TEM_ATTR_BRIGHT_BG;
9239890ff83SToomas Soome 	}
9249890ff83SToomas Soome 
9259890ff83SToomas Soome 	pcolor->a_flags = flags;
9269890ff83SToomas Soome }
9279890ff83SToomas Soome 
9289890ff83SToomas Soome void
tem_activate(tem_vt_state_t tem_arg,bool unblank)929ffd79eb6SToomas Soome tem_activate(tem_vt_state_t tem_arg, bool unblank)
9309890ff83SToomas Soome {
9319890ff83SToomas Soome 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
9329890ff83SToomas Soome 
9339890ff83SToomas Soome 	tems.ts_active = tem;
9349890ff83SToomas Soome 	tem->tvs_isactive = true;
9359890ff83SToomas Soome 
9369890ff83SToomas Soome 	tem_kdsetmode(tem->tvs_fbmode);
9379890ff83SToomas Soome 
9389890ff83SToomas Soome 	if (unblank)
9399890ff83SToomas Soome 		tem_cls(tem);
9409890ff83SToomas Soome }
9419890ff83SToomas Soome 
9429890ff83SToomas Soome static void
tem_check_first_time(struct tem_vt_state * tem)9439890ff83SToomas Soome tem_check_first_time(struct tem_vt_state *tem)
9449890ff83SToomas Soome {
9459890ff83SToomas Soome 	static int first_time = 1;
9469890ff83SToomas Soome 
9479890ff83SToomas Soome 	/*
9489890ff83SToomas Soome 	 * Realign the console cursor. We did this in tem_init().
9499890ff83SToomas Soome 	 * However, drivers in the console stream may emit additional
9509890ff83SToomas Soome 	 * messages before we are ready. This causes text overwrite
9519890ff83SToomas Soome 	 * on the screen. This is a workaround.
9529890ff83SToomas Soome 	 */
9539890ff83SToomas Soome 	if (!first_time)
9549890ff83SToomas Soome 		return;
9559890ff83SToomas Soome 
9569890ff83SToomas Soome 	first_time = 0;
9579890ff83SToomas Soome 	if (tems.ts_display_mode == VIS_TEXT)
9589890ff83SToomas Soome 		tem_text_cursor(tem, VIS_GET_CURSOR);
9599890ff83SToomas Soome 	else
9609890ff83SToomas Soome 		tem_pix_cursor(tem, VIS_GET_CURSOR);
9619890ff83SToomas Soome 	tem_align_cursor(tem);
9629890ff83SToomas Soome }
9639890ff83SToomas Soome 
9649890ff83SToomas Soome /* Process partial UTF-8 sequence. */
9659890ff83SToomas Soome static void
tem_input_partial(struct tem_vt_state * tem)9669890ff83SToomas Soome tem_input_partial(struct tem_vt_state *tem)
9679890ff83SToomas Soome {
9689890ff83SToomas Soome 	unsigned i;
9699890ff83SToomas Soome 	tem_char_t c;
9709890ff83SToomas Soome 
9719890ff83SToomas Soome 	if (tem->tvs_utf8_left == 0)
9729890ff83SToomas Soome 		return;
9739890ff83SToomas Soome 
9749890ff83SToomas Soome 	for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
9759890ff83SToomas Soome 		c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
9769890ff83SToomas Soome 		if (c != 0) {
9779890ff83SToomas Soome 			tem_parse(tem, c);
9789890ff83SToomas Soome 		}
9799890ff83SToomas Soome 	}
9809890ff83SToomas Soome 	tem->tvs_utf8_left = 0;
9819890ff83SToomas Soome 	tem->tvs_utf8_partial = 0;
9829890ff83SToomas Soome }
9839890ff83SToomas Soome 
9849890ff83SToomas Soome /*
9859890ff83SToomas Soome  * Handle UTF-8 sequences.
9869890ff83SToomas Soome  */
9879890ff83SToomas Soome static void
tem_input_byte(struct tem_vt_state * tem,uint8_t c)9889890ff83SToomas Soome tem_input_byte(struct tem_vt_state *tem, uint8_t c)
9899890ff83SToomas Soome {
9909890ff83SToomas Soome 	/*
9919890ff83SToomas Soome 	 * Check for UTF-8 code points. In case of error fall back to
9929890ff83SToomas Soome 	 * 8-bit code. As we only have 8859-1 fonts for console, this will set
9939890ff83SToomas Soome 	 * the limits on what chars we actually can display, therefore we
9949890ff83SToomas Soome 	 * have to return to this code once we have solved the font issue.
9959890ff83SToomas Soome 	 */
9969890ff83SToomas Soome 	if ((c & 0x80) == 0x00) {
9979890ff83SToomas Soome 		/* One-byte sequence. */
9989890ff83SToomas Soome 		tem_input_partial(tem);
9999890ff83SToomas Soome 		tem_parse(tem, c);
10009890ff83SToomas Soome 		return;
10019890ff83SToomas Soome 	}
10029890ff83SToomas Soome 	if ((c & 0xe0) == 0xc0) {
10039890ff83SToomas Soome 		/* Two-byte sequence. */
10049890ff83SToomas Soome 		tem_input_partial(tem);
10059890ff83SToomas Soome 		tem->tvs_utf8_left = 1;
10069890ff83SToomas Soome 		tem->tvs_utf8_partial = c;
10079890ff83SToomas Soome 		return;
10089890ff83SToomas Soome 	}
10099890ff83SToomas Soome 	if ((c & 0xf0) == 0xe0) {
10109890ff83SToomas Soome 		/* Three-byte sequence. */
10119890ff83SToomas Soome 		tem_input_partial(tem);
10129890ff83SToomas Soome 		tem->tvs_utf8_left = 2;
10139890ff83SToomas Soome 		tem->tvs_utf8_partial = c;
10149890ff83SToomas Soome 		return;
10159890ff83SToomas Soome 	}
10169890ff83SToomas Soome 	if ((c & 0xf8) == 0xf0) {
10179890ff83SToomas Soome 		/* Four-byte sequence. */
10189890ff83SToomas Soome 		tem_input_partial(tem);
10199890ff83SToomas Soome 		tem->tvs_utf8_left = 3;
10209890ff83SToomas Soome 		tem->tvs_utf8_partial = c;
10219890ff83SToomas Soome 		return;
10229890ff83SToomas Soome 	}
10239890ff83SToomas Soome 	if ((c & 0xc0) == 0x80) {
10249890ff83SToomas Soome 		/* Invalid state? */
10259890ff83SToomas Soome 		if (tem->tvs_utf8_left == 0) {
10269890ff83SToomas Soome 			tem_parse(tem, c);
10279890ff83SToomas Soome 			return;
10289890ff83SToomas Soome 		}
10299890ff83SToomas Soome 		tem->tvs_utf8_left--;
10309890ff83SToomas Soome 		tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
10319890ff83SToomas Soome 		if (tem->tvs_utf8_left == 0) {
10329890ff83SToomas Soome 			tem_char_t v, u;
10339890ff83SToomas Soome 			uint8_t b;
10349890ff83SToomas Soome 
10359890ff83SToomas Soome 			/*
10369890ff83SToomas Soome 			 * Transform the sequence of 2 to 4 bytes to
10379890ff83SToomas Soome 			 * unicode number.
10389890ff83SToomas Soome 			 */
10399890ff83SToomas Soome 			v = 0;
10409890ff83SToomas Soome 			u = tem->tvs_utf8_partial;
10419890ff83SToomas Soome 			b = (u >> 24) & 0xff;
10429890ff83SToomas Soome 			if (b != 0) {		/* Four-byte sequence */
10439890ff83SToomas Soome 				v = b & 0x07;
10449890ff83SToomas Soome 				b = (u >> 16) & 0xff;
10459890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10469890ff83SToomas Soome 				b = (u >> 8) & 0xff;
10479890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10489890ff83SToomas Soome 				b = u & 0xff;
10499890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10509890ff83SToomas Soome 			} else if ((b = (u >> 16) & 0xff) != 0) {
10519890ff83SToomas Soome 				v = b & 0x0f;	/* Three-byte sequence */
10529890ff83SToomas Soome 				b = (u >> 8) & 0xff;
10539890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10549890ff83SToomas Soome 				b = u & 0xff;
10559890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10569890ff83SToomas Soome 			} else if ((b = (u >> 8) & 0xff) != 0) {
10579890ff83SToomas Soome 				v = b & 0x1f;	/* Two-byte sequence */
10589890ff83SToomas Soome 				b = u & 0xff;
10599890ff83SToomas Soome 				v = (v << 6) | (b & 0x3f);
10609890ff83SToomas Soome 			}
10619890ff83SToomas Soome 
10629890ff83SToomas Soome 			tem_parse(tem, v);
10639890ff83SToomas Soome 			tem->tvs_utf8_partial = 0;
10649890ff83SToomas Soome 		}
10659890ff83SToomas Soome 		return;
10669890ff83SToomas Soome 	}
10679890ff83SToomas Soome 	/* Anything left is illegal in UTF-8 sequence. */
10689890ff83SToomas Soome 	tem_input_partial(tem);
10699890ff83SToomas Soome 	tem_parse(tem, c);
10709890ff83SToomas Soome }
10719890ff83SToomas Soome 
10729890ff83SToomas Soome /*
10739890ff83SToomas Soome  * This is the main entry point into the terminal emulator.
10749890ff83SToomas Soome  *
10759890ff83SToomas Soome  * For each data message coming downstream, ANSI assumes that it is composed
10769890ff83SToomas Soome  * of ASCII characters, which are treated as a byte-stream input to the
10779890ff83SToomas Soome  * parsing state machine. All data is parsed immediately -- there is
10789890ff83SToomas Soome  * no enqueing.
10799890ff83SToomas Soome  */
10809890ff83SToomas Soome static void
tem_terminal_emulate(struct tem_vt_state * tem,uint8_t * buf,int len)10819890ff83SToomas Soome tem_terminal_emulate(struct tem_vt_state *tem, uint8_t *buf, int len)
10829890ff83SToomas Soome {
10835e897995SToomas Soome 	if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
10849890ff83SToomas Soome 		tem_callback_cursor(tem, VIS_HIDE_CURSOR);
10859890ff83SToomas Soome 
10869890ff83SToomas Soome 	for (; len > 0; len--, buf++)
10879890ff83SToomas Soome 		tem_input_byte(tem, *buf);
10889890ff83SToomas Soome 
10899890ff83SToomas Soome 	/*
10909890ff83SToomas Soome 	 * Send the data we just got to the framebuffer.
10919890ff83SToomas Soome 	 */
10929890ff83SToomas Soome 	tem_send_data(tem);
10939890ff83SToomas Soome 
10945e897995SToomas Soome 	if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
10959890ff83SToomas Soome 		tem_callback_cursor(tem, VIS_DISPLAY_CURSOR);
10969890ff83SToomas Soome }
10979890ff83SToomas Soome 
10989890ff83SToomas Soome /*
10999890ff83SToomas Soome  * send the appropriate control message or set state based on the
11009890ff83SToomas Soome  * value of the control character ch
11019890ff83SToomas Soome  */
11029890ff83SToomas Soome 
11039890ff83SToomas Soome static void
tem_control(struct tem_vt_state * tem,uint8_t ch)11049890ff83SToomas Soome tem_control(struct tem_vt_state *tem, uint8_t ch)
11059890ff83SToomas Soome {
11069890ff83SToomas Soome 	tem->tvs_state = A_STATE_START;
11079890ff83SToomas Soome 	switch (ch) {
11089890ff83SToomas Soome 	case A_BEL:
11099890ff83SToomas Soome 		tem_bell(tem);
11109890ff83SToomas Soome 		break;
11119890ff83SToomas Soome 
11129890ff83SToomas Soome 	case A_BS:
11139890ff83SToomas Soome 		tem_mv_cursor(tem,
11149890ff83SToomas Soome 		    tem->tvs_c_cursor.row,
11159890ff83SToomas Soome 		    tem->tvs_c_cursor.col - 1);
11169890ff83SToomas Soome 		break;
11179890ff83SToomas Soome 
11189890ff83SToomas Soome 	case A_HT:
11199890ff83SToomas Soome 		tem_tab(tem);
11209890ff83SToomas Soome 		break;
11219890ff83SToomas Soome 
11229890ff83SToomas Soome 	case A_NL:
11239890ff83SToomas Soome 		/*
11249890ff83SToomas Soome 		 * tem_send_data(tem, credp, called_from);
11259890ff83SToomas Soome 		 * tem_new_line(tem, credp, called_from);
11269890ff83SToomas Soome 		 * break;
11279890ff83SToomas Soome 		 */
11289890ff83SToomas Soome 
11299890ff83SToomas Soome 	case A_VT:
11309890ff83SToomas Soome 		tem_send_data(tem);
11319890ff83SToomas Soome 		tem_lf(tem);
11329890ff83SToomas Soome 		break;
11339890ff83SToomas Soome 
11349890ff83SToomas Soome 	case A_FF:
11359890ff83SToomas Soome 		tem_send_data(tem);
11369890ff83SToomas Soome 		tem_cls(tem);
11379890ff83SToomas Soome 		break;
11389890ff83SToomas Soome 
11399890ff83SToomas Soome 	case A_CR:
11409890ff83SToomas Soome 		tem_send_data(tem);
11419890ff83SToomas Soome 		tem_cr(tem);
11429890ff83SToomas Soome 		break;
11439890ff83SToomas Soome 
11449890ff83SToomas Soome 	case A_ESC:
11459890ff83SToomas Soome 		tem->tvs_state = A_STATE_ESC;
11469890ff83SToomas Soome 		break;
11479890ff83SToomas Soome 
11489890ff83SToomas Soome 	case A_CSI:
1149726d8a6eSToomas Soome 		tem->tvs_curparam = 0;
1150726d8a6eSToomas Soome 		tem->tvs_paramval = 0;
1151ffd79eb6SToomas Soome 		tem->tvs_gotparam = false;
1152726d8a6eSToomas Soome 		/* clear the parameters */
1153726d8a6eSToomas Soome 		for (int i = 0; i < TEM_MAXPARAMS; i++)
1154726d8a6eSToomas Soome 			tem->tvs_params[i] = -1;
1155726d8a6eSToomas Soome 		tem->tvs_state = A_STATE_CSI;
11569890ff83SToomas Soome 		break;
11579890ff83SToomas Soome 
11589890ff83SToomas Soome 	case A_GS:
11599890ff83SToomas Soome 		tem_back_tab(tem);
11609890ff83SToomas Soome 		break;
11619890ff83SToomas Soome 
11629890ff83SToomas Soome 	default:
11639890ff83SToomas Soome 		break;
11649890ff83SToomas Soome 	}
11659890ff83SToomas Soome }
11669890ff83SToomas Soome 
11679890ff83SToomas Soome 
11689890ff83SToomas Soome /*
11699890ff83SToomas Soome  * if parameters [0..count - 1] are not set, set them to the value
11709890ff83SToomas Soome  * of newparam.
11719890ff83SToomas Soome  */
11729890ff83SToomas Soome 
11739890ff83SToomas Soome static void
tem_setparam(struct tem_vt_state * tem,int count,int newparam)11749890ff83SToomas Soome tem_setparam(struct tem_vt_state *tem, int count, int newparam)
11759890ff83SToomas Soome {
11769890ff83SToomas Soome 	int i;
11779890ff83SToomas Soome 
11789890ff83SToomas Soome 	for (i = 0; i < count; i++) {
11799890ff83SToomas Soome 		if (tem->tvs_params[i] == -1)
11809890ff83SToomas Soome 			tem->tvs_params[i] = newparam;
11819890ff83SToomas Soome 	}
11829890ff83SToomas Soome }
11839890ff83SToomas Soome 
118491061836SToomas Soome /*
118591061836SToomas Soome  * For colors 0-15 the tem is using color code translation
118691061836SToomas Soome  * from sun colors to vga (dim_xlate and brt_xlate tables, see tem_get_color).
118791061836SToomas Soome  * Colors 16-255 are used without translation.
118891061836SToomas Soome  */
118962efa0e7SToomas Soome static void
tem_select_color(struct tem_vt_state * tem,int color,bool fg)1190fa9eb222SToomas Soome tem_select_color(struct tem_vt_state *tem, int color, bool fg)
119162efa0e7SToomas Soome {
1192fa9eb222SToomas Soome 	if (color < 0 || color > 255)
1193fa9eb222SToomas Soome 		return;
1194fa9eb222SToomas Soome 
1195fa9eb222SToomas Soome 	/* VGA text mode only does support 16 colors. */
1196fa9eb222SToomas Soome 	if (tems.ts_display_mode == VIS_TEXT && color > 15)
1197fa9eb222SToomas Soome 		return;
1198fa9eb222SToomas Soome 
1199fa9eb222SToomas Soome 	/* Switch to use indexed colors. */
1200fa9eb222SToomas Soome 	if (fg == true) {
1201fa9eb222SToomas Soome 		tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
1202fa9eb222SToomas Soome 		tem->tvs_fg_color.n = color;
1203fa9eb222SToomas Soome 	} else {
1204fa9eb222SToomas Soome 		tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
1205fa9eb222SToomas Soome 		tem->tvs_bg_color.n = color;
1206fa9eb222SToomas Soome 	}
120791061836SToomas Soome 
120891061836SToomas Soome 	/*
120991061836SToomas Soome 	 * For colors 0-7, make sure the BRIGHT attribute is not set.
121091061836SToomas Soome 	 */
121191061836SToomas Soome 	if (color < 8) {
121291061836SToomas Soome 		if (fg == true)
121362efa0e7SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
121491061836SToomas Soome 		else
121562efa0e7SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
121662efa0e7SToomas Soome 		return;
121762efa0e7SToomas Soome 	}
121862efa0e7SToomas Soome 
121991061836SToomas Soome 	/*
122091061836SToomas Soome 	 * For colors 8-15, we use color codes 0-7 and set BRIGHT attribute.
122191061836SToomas Soome 	 */
122291061836SToomas Soome 	if (color < 16) {
122391061836SToomas Soome 		if (fg == true) {
1224fa9eb222SToomas Soome 			tem->tvs_fg_color.n -= 8;
122591061836SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
122691061836SToomas Soome 		} else {
1227fa9eb222SToomas Soome 			tem->tvs_bg_color.n -= 8;
122891061836SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
122991061836SToomas Soome 		}
123062efa0e7SToomas Soome 	}
123162efa0e7SToomas Soome }
123262efa0e7SToomas Soome 
12339890ff83SToomas Soome /*
12349890ff83SToomas Soome  * select graphics mode based on the param vals stored in a_params
12359890ff83SToomas Soome  */
12369890ff83SToomas Soome static void
tem_selgraph(struct tem_vt_state * tem)12379890ff83SToomas Soome tem_selgraph(struct tem_vt_state *tem)
12389890ff83SToomas Soome {
12399890ff83SToomas Soome 	int curparam;
12409890ff83SToomas Soome 	int count = 0;
12419890ff83SToomas Soome 	int param;
1242fa9eb222SToomas Soome 	int r, g, b;
12439890ff83SToomas Soome 
12449890ff83SToomas Soome 	tem->tvs_state = A_STATE_START;
12459890ff83SToomas Soome 
12469890ff83SToomas Soome 	curparam = tem->tvs_curparam;
12479890ff83SToomas Soome 	do {
12489890ff83SToomas Soome 		param = tem->tvs_params[count];
12499890ff83SToomas Soome 
12509890ff83SToomas Soome 		switch (param) {
12519890ff83SToomas Soome 		case -1:
12529890ff83SToomas Soome 		case 0:
12539890ff83SToomas Soome 			/* reset to initial normal settings */
12549890ff83SToomas Soome 			tem->tvs_fg_color = tems.ts_init_color.fg_color;
12559890ff83SToomas Soome 			tem->tvs_bg_color = tems.ts_init_color.bg_color;
12569890ff83SToomas Soome 			tem->tvs_flags = tems.ts_init_color.a_flags;
12579890ff83SToomas Soome 			break;
12589890ff83SToomas Soome 
12599890ff83SToomas Soome 		case 1: /* Bold Intense */
12609890ff83SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BOLD;
12619890ff83SToomas Soome 			break;
12629890ff83SToomas Soome 
12639890ff83SToomas Soome 		case 2: /* Faint Intense */
12649890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BOLD;
12659890ff83SToomas Soome 			break;
12669890ff83SToomas Soome 
12679890ff83SToomas Soome 		case 4: /* Underline */
12689890ff83SToomas Soome 			tem->tvs_flags |= TEM_ATTR_UNDERLINE;
12699890ff83SToomas Soome 			break;
12709890ff83SToomas Soome 
12719890ff83SToomas Soome 		case 5: /* Blink */
12729890ff83SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BLINK;
12739890ff83SToomas Soome 			break;
12749890ff83SToomas Soome 
12759890ff83SToomas Soome 		case 7: /* Reverse video */
12769890ff83SToomas Soome 			if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
12779890ff83SToomas Soome 				tem->tvs_flags &= ~TEM_ATTR_REVERSE;
12789890ff83SToomas Soome 			} else {
12799890ff83SToomas Soome 				tem->tvs_flags |= TEM_ATTR_REVERSE;
12809890ff83SToomas Soome 			}
12819890ff83SToomas Soome 			break;
12829890ff83SToomas Soome 
12839890ff83SToomas Soome 		case 22: /* Remove Bold */
12849890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BOLD;
12859890ff83SToomas Soome 			break;
12869890ff83SToomas Soome 
12879890ff83SToomas Soome 		case 24: /* Remove Underline */
12889890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_UNDERLINE;
12899890ff83SToomas Soome 			break;
12909890ff83SToomas Soome 
12919890ff83SToomas Soome 		case 25: /* Remove Blink */
12929890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BLINK;
12939890ff83SToomas Soome 			break;
12949890ff83SToomas Soome 
12959890ff83SToomas Soome 		case 27: /* Remove Reverse */
12969890ff83SToomas Soome 			if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
12979890ff83SToomas Soome 				tem->tvs_flags |= TEM_ATTR_REVERSE;
12989890ff83SToomas Soome 			} else {
12999890ff83SToomas Soome 				tem->tvs_flags &= ~TEM_ATTR_REVERSE;
13009890ff83SToomas Soome 			}
13019890ff83SToomas Soome 			break;
13029890ff83SToomas Soome 
13039890ff83SToomas Soome 		case 30: /* black	(grey)		foreground */
13049890ff83SToomas Soome 		case 31: /* red		(light red)	foreground */
13059890ff83SToomas Soome 		case 32: /* green	(light green)	foreground */
13069890ff83SToomas Soome 		case 33: /* brown	(yellow)	foreground */
13079890ff83SToomas Soome 		case 34: /* blue	(light blue)	foreground */
13089890ff83SToomas Soome 		case 35: /* magenta	(light magenta)	foreground */
13099890ff83SToomas Soome 		case 36: /* cyan	(light cyan)	foreground */
13109890ff83SToomas Soome 		case 37: /* white	(bright white)	foreground */
1311fa9eb222SToomas Soome 			tem->tvs_fg_color.n = param - 30;
13129890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
1313fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
13149890ff83SToomas Soome 			break;
13159890ff83SToomas Soome 
1316a4e6b9b6SToomas Soome 		case 38:
1317fa9eb222SToomas Soome 			/*
1318fa9eb222SToomas Soome 			 * We should have 3 parameters for 256 colors and
1319fa9eb222SToomas Soome 			 * 5 parameters for 24-bit colors.
1320fa9eb222SToomas Soome 			 */
1321fa9eb222SToomas Soome 			if (curparam < 3) {
1322fa9eb222SToomas Soome 				curparam = 0;
1323a4e6b9b6SToomas Soome 				break;
1324fa9eb222SToomas Soome 			}
1325a4e6b9b6SToomas Soome 
1326a4e6b9b6SToomas Soome 			/*
1327fa9eb222SToomas Soome 			 * 256 and truecolor needs depth > 8, but
1328a4e6b9b6SToomas Soome 			 * we still need to process the sequence.
1329a4e6b9b6SToomas Soome 			 */
1330a4e6b9b6SToomas Soome 			count++;
1331a4e6b9b6SToomas Soome 			curparam--;
1332a4e6b9b6SToomas Soome 			param = tem->tvs_params[count];
1333a4e6b9b6SToomas Soome 			switch (param) {
1334fa9eb222SToomas Soome 			case 2:	/* RGB colors */
1335fa9eb222SToomas Soome 				if (curparam < 4) {
1336fa9eb222SToomas Soome 					curparam = 0;
1337fa9eb222SToomas Soome 					break;
1338fa9eb222SToomas Soome 				}
1339fa9eb222SToomas Soome 				r = tem->tvs_params[++count];
1340fa9eb222SToomas Soome 				g = tem->tvs_params[++count];
1341fa9eb222SToomas Soome 				b = tem->tvs_params[++count];
1342fa9eb222SToomas Soome 				curparam -= 3;
1343fa9eb222SToomas Soome 				if (r < 0 || r > 255 || g < 0 || g > 255 ||
1344fa9eb222SToomas Soome 				    b < 0 || b > 255)
1345fa9eb222SToomas Soome 					break;
1346fa9eb222SToomas Soome 
1347fa9eb222SToomas Soome 				if (tems.ts_display_mode == VIS_PIXEL &&
1348fa9eb222SToomas Soome 				    tems.ts_pdepth > 8) {
1349fa9eb222SToomas Soome 					tem->tvs_flags |= TEM_ATTR_RGB_FG;
1350fa9eb222SToomas Soome 					tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
1351fa9eb222SToomas Soome 					tem->tvs_fg_color.rgb.a =
1352fa9eb222SToomas Soome 					    tem->tvs_alpha;
1353fa9eb222SToomas Soome 					tem->tvs_fg_color.rgb.r = r;
1354fa9eb222SToomas Soome 					tem->tvs_fg_color.rgb.g = g;
1355fa9eb222SToomas Soome 					tem->tvs_fg_color.rgb.b = b;
1356fa9eb222SToomas Soome 				}
1357fa9eb222SToomas Soome 				break;
1358a4e6b9b6SToomas Soome 			case 5:	/* 256 colors */
1359a4e6b9b6SToomas Soome 				count++;
1360a4e6b9b6SToomas Soome 				curparam--;
136162efa0e7SToomas Soome 				tem_select_color(tem, tem->tvs_params[count],
136262efa0e7SToomas Soome 				    true);
1363a4e6b9b6SToomas Soome 				break;
1364a4e6b9b6SToomas Soome 			default:
1365fa9eb222SToomas Soome 				curparam = 0;
1366a4e6b9b6SToomas Soome 				break;
1367a4e6b9b6SToomas Soome 			}
1368a4e6b9b6SToomas Soome 			break;
1369a4e6b9b6SToomas Soome 
13709890ff83SToomas Soome 		case 39:
13719890ff83SToomas Soome 			/*
13729890ff83SToomas Soome 			 * Reset the foreground colour and brightness.
13739890ff83SToomas Soome 			 */
13749890ff83SToomas Soome 			tem->tvs_fg_color = tems.ts_init_color.fg_color;
1375fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
13769890ff83SToomas Soome 			if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
13779890ff83SToomas Soome 				tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
13789890ff83SToomas Soome 			else
13799890ff83SToomas Soome 				tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
13809890ff83SToomas Soome 			break;
13819890ff83SToomas Soome 
13829890ff83SToomas Soome 		case 40: /* black	(grey)		background */
13839890ff83SToomas Soome 		case 41: /* red		(light red)	background */
13849890ff83SToomas Soome 		case 42: /* green	(light green)	background */
13859890ff83SToomas Soome 		case 43: /* brown	(yellow)	background */
13869890ff83SToomas Soome 		case 44: /* blue	(light blue)	background */
13879890ff83SToomas Soome 		case 45: /* magenta	(light magenta)	background */
13889890ff83SToomas Soome 		case 46: /* cyan	(light cyan)	background */
13899890ff83SToomas Soome 		case 47: /* white	(bright white)	background */
1390fa9eb222SToomas Soome 			tem->tvs_bg_color.n = param - 40;
1391fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
13929890ff83SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
13939890ff83SToomas Soome 			break;
13949890ff83SToomas Soome 
1395a4e6b9b6SToomas Soome 		case 48:
1396fa9eb222SToomas Soome 			/*
1397fa9eb222SToomas Soome 			 * We should have 3 parameters for 256 colors and
1398fa9eb222SToomas Soome 			 * 5 parameters for 24-bit colors.
1399fa9eb222SToomas Soome 			 */
1400a4e6b9b6SToomas Soome 			/* We should have at least 3 parameters */
1401fa9eb222SToomas Soome 			if (curparam < 3) {
1402fa9eb222SToomas Soome 				curparam = 0;
1403a4e6b9b6SToomas Soome 				break;
1404fa9eb222SToomas Soome 			}
1405a4e6b9b6SToomas Soome 
1406a4e6b9b6SToomas Soome 			/*
1407fa9eb222SToomas Soome 			 * 256 and truecolor needs depth > 8, but
1408a4e6b9b6SToomas Soome 			 * we still need to process the sequence.
1409a4e6b9b6SToomas Soome 			 */
1410a4e6b9b6SToomas Soome 			count++;
1411a4e6b9b6SToomas Soome 			curparam--;
1412a4e6b9b6SToomas Soome 			param = tem->tvs_params[count];
1413a4e6b9b6SToomas Soome 			switch (param) {
1414fa9eb222SToomas Soome 			case 2:	/* RGB colors */
1415fa9eb222SToomas Soome 				if (curparam < 4) {
1416fa9eb222SToomas Soome 					curparam = 0;
1417fa9eb222SToomas Soome 					break;
1418fa9eb222SToomas Soome 				}
1419fa9eb222SToomas Soome 				r = tem->tvs_params[++count];
1420fa9eb222SToomas Soome 				g = tem->tvs_params[++count];
1421fa9eb222SToomas Soome 				b = tem->tvs_params[++count];
1422fa9eb222SToomas Soome 				curparam -= 3;
1423fa9eb222SToomas Soome 				if (r < 0 || r > 255 || g < 0 || g > 255 ||
1424fa9eb222SToomas Soome 				    b < 0 || b > 255)
1425fa9eb222SToomas Soome 					break;
1426fa9eb222SToomas Soome 
1427fa9eb222SToomas Soome 				if (tems.ts_display_mode == VIS_PIXEL &&
1428fa9eb222SToomas Soome 				    tems.ts_pdepth > 8) {
1429fa9eb222SToomas Soome 					tem->tvs_flags |= TEM_ATTR_RGB_BG;
1430fa9eb222SToomas Soome 					tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
1431fa9eb222SToomas Soome 					tem->tvs_bg_color.rgb.a =
1432fa9eb222SToomas Soome 					    tem->tvs_alpha;
1433fa9eb222SToomas Soome 					tem->tvs_bg_color.rgb.r = r;
1434fa9eb222SToomas Soome 					tem->tvs_bg_color.rgb.g = g;
1435fa9eb222SToomas Soome 					tem->tvs_bg_color.rgb.b = b;
1436fa9eb222SToomas Soome 				}
1437fa9eb222SToomas Soome 				break;
1438a4e6b9b6SToomas Soome 			case 5:	/* 256 colors */
1439a4e6b9b6SToomas Soome 				count++;
1440a4e6b9b6SToomas Soome 				curparam--;
144162efa0e7SToomas Soome 				tem_select_color(tem, tem->tvs_params[count],
144262efa0e7SToomas Soome 				    false);
1443a4e6b9b6SToomas Soome 				break;
1444a4e6b9b6SToomas Soome 			default:
1445fa9eb222SToomas Soome 				curparam = 0;
1446a4e6b9b6SToomas Soome 				break;
1447a4e6b9b6SToomas Soome 			}
1448a4e6b9b6SToomas Soome 			break;
1449a4e6b9b6SToomas Soome 
14509890ff83SToomas Soome 		case 49:
14519890ff83SToomas Soome 			/*
14529890ff83SToomas Soome 			 * Reset the background colour and brightness.
14539890ff83SToomas Soome 			 */
14549890ff83SToomas Soome 			tem->tvs_bg_color = tems.ts_init_color.bg_color;
1455fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
14569890ff83SToomas Soome 			if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
14579890ff83SToomas Soome 				tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
14589890ff83SToomas Soome 			else
14599890ff83SToomas Soome 				tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
14609890ff83SToomas Soome 			break;
14619890ff83SToomas Soome 
14629890ff83SToomas Soome 		case 90: /* black	(grey)		foreground */
14639890ff83SToomas Soome 		case 91: /* red		(light red)	foreground */
14649890ff83SToomas Soome 		case 92: /* green	(light green)	foreground */
14659890ff83SToomas Soome 		case 93: /* brown	(yellow)	foreground */
14669890ff83SToomas Soome 		case 94: /* blue	(light blue)	foreground */
14679890ff83SToomas Soome 		case 95: /* magenta	(light magenta)	foreground */
14689890ff83SToomas Soome 		case 96: /* cyan	(light cyan)	foreground */
14699890ff83SToomas Soome 		case 97: /* white	(bright white)	foreground */
1470fa9eb222SToomas Soome 			tem->tvs_fg_color.n = param - 90;
14719890ff83SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
1472fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
14739890ff83SToomas Soome 			break;
14749890ff83SToomas Soome 
14759890ff83SToomas Soome 		case 100: /* black	(grey)		background */
14769890ff83SToomas Soome 		case 101: /* red	(light red)	background */
14779890ff83SToomas Soome 		case 102: /* green	(light green)	background */
14789890ff83SToomas Soome 		case 103: /* brown	(yellow)	background */
14799890ff83SToomas Soome 		case 104: /* blue	(light blue)	background */
14809890ff83SToomas Soome 		case 105: /* magenta	(light magenta)	background */
14819890ff83SToomas Soome 		case 106: /* cyan	(light cyan)	background */
14829890ff83SToomas Soome 		case 107: /* white	(bright white)	background */
1483fa9eb222SToomas Soome 			tem->tvs_bg_color.n = param - 100;
14849890ff83SToomas Soome 			tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
1485fa9eb222SToomas Soome 			tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
14869890ff83SToomas Soome 			break;
14879890ff83SToomas Soome 
14889890ff83SToomas Soome 		default:
14899890ff83SToomas Soome 			break;
14909890ff83SToomas Soome 		}
14919890ff83SToomas Soome 		count++;
14929890ff83SToomas Soome 		curparam--;
14939890ff83SToomas Soome 
14949890ff83SToomas Soome 	} while (curparam > 0);
14959890ff83SToomas Soome }
14969890ff83SToomas Soome 
14979890ff83SToomas Soome /*
14989890ff83SToomas Soome  * perform the appropriate action for the escape sequence
14999890ff83SToomas Soome  *
15009890ff83SToomas Soome  * General rule:  This code does not validate the arguments passed.
15019890ff83SToomas Soome  *                It assumes that the next lower level will do so.
15029890ff83SToomas Soome  */
15039890ff83SToomas Soome static void
tem_chkparam(struct tem_vt_state * tem,uint8_t ch)15049890ff83SToomas Soome tem_chkparam(struct tem_vt_state *tem, uint8_t ch)
15059890ff83SToomas Soome {
15069890ff83SToomas Soome 	int	i;
15079890ff83SToomas Soome 	int	row;
15089890ff83SToomas Soome 	int	col;
15099890ff83SToomas Soome 
15109890ff83SToomas Soome 	row = tem->tvs_c_cursor.row;
15119890ff83SToomas Soome 	col = tem->tvs_c_cursor.col;
15129890ff83SToomas Soome 
15139890ff83SToomas Soome 	switch (ch) {
15149890ff83SToomas Soome 
15159890ff83SToomas Soome 	case 'm': /* select terminal graphics mode */
15169890ff83SToomas Soome 		tem_send_data(tem);
15179890ff83SToomas Soome 		tem_selgraph(tem);
15189890ff83SToomas Soome 		break;
15199890ff83SToomas Soome 
15209890ff83SToomas Soome 	case '@':		/* insert char */
15219890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15229890ff83SToomas Soome 		tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT);
15239890ff83SToomas Soome 		break;
15249890ff83SToomas Soome 
15259890ff83SToomas Soome 	case 'A':		/* cursor up */
15269890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15279890ff83SToomas Soome 		tem_mv_cursor(tem, row - tem->tvs_params[0], col);
15289890ff83SToomas Soome 		break;
15299890ff83SToomas Soome 
15309890ff83SToomas Soome 	case 'd':		/* VPA - vertical position absolute */
15319890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15329890ff83SToomas Soome 		tem_mv_cursor(tem, tem->tvs_params[0] - 1, col);
15339890ff83SToomas Soome 		break;
15349890ff83SToomas Soome 
15359890ff83SToomas Soome 	case 'e':		/* VPR - vertical position relative */
15369890ff83SToomas Soome 	case 'B':		/* cursor down */
15379890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15389890ff83SToomas Soome 		tem_mv_cursor(tem, row + tem->tvs_params[0], col);
15399890ff83SToomas Soome 		break;
15409890ff83SToomas Soome 
15419890ff83SToomas Soome 	case 'a':		/* HPR - horizontal position relative */
15429890ff83SToomas Soome 	case 'C':		/* cursor right */
15439890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15449890ff83SToomas Soome 		tem_mv_cursor(tem, row, col + tem->tvs_params[0]);
15459890ff83SToomas Soome 		break;
15469890ff83SToomas Soome 
15479890ff83SToomas Soome 	case '`':		/* HPA - horizontal position absolute */
15489890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15499890ff83SToomas Soome 		tem_mv_cursor(tem, row, tem->tvs_params[0] - 1);
15509890ff83SToomas Soome 		break;
15519890ff83SToomas Soome 
15529890ff83SToomas Soome 	case 'D':		/* cursor left */
15539890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15549890ff83SToomas Soome 		tem_mv_cursor(tem, row, col - tem->tvs_params[0]);
15559890ff83SToomas Soome 		break;
15569890ff83SToomas Soome 
15579890ff83SToomas Soome 	case 'E':		/* CNL cursor next line */
15589890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15599890ff83SToomas Soome 		tem_mv_cursor(tem, row + tem->tvs_params[0], 0);
15609890ff83SToomas Soome 		break;
15619890ff83SToomas Soome 
15629890ff83SToomas Soome 	case 'F':		/* CPL cursor previous line */
15639890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15649890ff83SToomas Soome 		tem_mv_cursor(tem, row - tem->tvs_params[0], 0);
15659890ff83SToomas Soome 		break;
15669890ff83SToomas Soome 
15679890ff83SToomas Soome 	case 'G':		/* cursor horizontal position */
15689890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
15699890ff83SToomas Soome 		tem_mv_cursor(tem, row, tem->tvs_params[0] - 1);
15709890ff83SToomas Soome 		break;
15719890ff83SToomas Soome 
15729890ff83SToomas Soome 	case 'g':		/* clear tabs */
15739890ff83SToomas Soome 		tem_setparam(tem, 1, 0);
15749890ff83SToomas Soome 		tem_clear_tabs(tem, tem->tvs_params[0]);
15759890ff83SToomas Soome 		break;
15769890ff83SToomas Soome 
15779890ff83SToomas Soome 	case 'f':		/* HVP Horizontal and Vertical Position */
15789890ff83SToomas Soome 	case 'H':		/* CUP position cursor */
15799890ff83SToomas Soome 		tem_setparam(tem, 2, 1);
15809890ff83SToomas Soome 		tem_mv_cursor(tem,
15819890ff83SToomas Soome 		    tem->tvs_params[0] - 1, tem->tvs_params[1] - 1);
15829890ff83SToomas Soome 		break;
15839890ff83SToomas Soome 
15849890ff83SToomas Soome 	case 'I':		/* CHT - Cursor Horizontal Tab */
15859890ff83SToomas Soome 		/* Not implemented */
15869890ff83SToomas Soome 		break;
15879890ff83SToomas Soome 
15889890ff83SToomas Soome 	case 'J':		/* ED - Erase in Display */
15899890ff83SToomas Soome 		tem_send_data(tem);
15909890ff83SToomas Soome 		tem_setparam(tem, 1, 0);
15919890ff83SToomas Soome 		switch (tem->tvs_params[0]) {
15929890ff83SToomas Soome 		case 0:
15939890ff83SToomas Soome 			/* erase cursor to end of screen */
15949890ff83SToomas Soome 			/* FIRST erase cursor to end of line */
15959890ff83SToomas Soome 			tem_clear_chars(tem,
15969890ff83SToomas Soome 			    tems.ts_c_dimension.width -
15979890ff83SToomas Soome 			    tem->tvs_c_cursor.col,
15989890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
15999890ff83SToomas Soome 			    tem->tvs_c_cursor.col);
16009890ff83SToomas Soome 
16019890ff83SToomas Soome 			/* THEN erase lines below the cursor */
16029890ff83SToomas Soome 			for (row = tem->tvs_c_cursor.row + 1;
16039890ff83SToomas Soome 			    row < tems.ts_c_dimension.height;
16049890ff83SToomas Soome 			    row++) {
16059890ff83SToomas Soome 				tem_clear_chars(tem,
16069890ff83SToomas Soome 				    tems.ts_c_dimension.width, row, 0);
16079890ff83SToomas Soome 			}
16089890ff83SToomas Soome 			break;
16099890ff83SToomas Soome 
16109890ff83SToomas Soome 		case 1:
16119890ff83SToomas Soome 			/* erase beginning of screen to cursor */
16129890ff83SToomas Soome 			/* FIRST erase lines above the cursor */
16139890ff83SToomas Soome 			for (row = 0;
16149890ff83SToomas Soome 			    row < tem->tvs_c_cursor.row;
16159890ff83SToomas Soome 			    row++) {
16169890ff83SToomas Soome 				tem_clear_chars(tem,
16179890ff83SToomas Soome 				    tems.ts_c_dimension.width, row, 0);
16189890ff83SToomas Soome 			}
16199890ff83SToomas Soome 			/* THEN erase beginning of line to cursor */
16209890ff83SToomas Soome 			tem_clear_chars(tem,
16219890ff83SToomas Soome 			    tem->tvs_c_cursor.col + 1,
16229890ff83SToomas Soome 			    tem->tvs_c_cursor.row, 0);
16239890ff83SToomas Soome 			break;
16249890ff83SToomas Soome 
16259890ff83SToomas Soome 		case 2:
16269890ff83SToomas Soome 			/* erase whole screen */
16279890ff83SToomas Soome 			for (row = 0;
16289890ff83SToomas Soome 			    row < tems.ts_c_dimension.height;
16299890ff83SToomas Soome 			    row++) {
16309890ff83SToomas Soome 				tem_clear_chars(tem,
16319890ff83SToomas Soome 				    tems.ts_c_dimension.width, row, 0);
16329890ff83SToomas Soome 			}
16339890ff83SToomas Soome 			break;
16349890ff83SToomas Soome 		}
16359890ff83SToomas Soome 		break;
16369890ff83SToomas Soome 
16379890ff83SToomas Soome 	case 'K':		/* EL - Erase in Line */
16389890ff83SToomas Soome 		tem_send_data(tem);
16399890ff83SToomas Soome 		tem_setparam(tem, 1, 0);
16409890ff83SToomas Soome 		switch (tem->tvs_params[0]) {
16419890ff83SToomas Soome 		case 0:
16429890ff83SToomas Soome 			/* erase cursor to end of line */
16439890ff83SToomas Soome 			tem_clear_chars(tem,
16449890ff83SToomas Soome 			    (tems.ts_c_dimension.width -
16459890ff83SToomas Soome 			    tem->tvs_c_cursor.col),
16469890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
16479890ff83SToomas Soome 			    tem->tvs_c_cursor.col);
16489890ff83SToomas Soome 			break;
16499890ff83SToomas Soome 
16509890ff83SToomas Soome 		case 1:
16519890ff83SToomas Soome 			/* erase beginning of line to cursor */
16529890ff83SToomas Soome 			tem_clear_chars(tem,
16539890ff83SToomas Soome 			    tem->tvs_c_cursor.col + 1,
16549890ff83SToomas Soome 			    tem->tvs_c_cursor.row, 0);
16559890ff83SToomas Soome 			break;
16569890ff83SToomas Soome 
16579890ff83SToomas Soome 		case 2:
16589890ff83SToomas Soome 			/* erase whole line */
16599890ff83SToomas Soome 			tem_clear_chars(tem,
16609890ff83SToomas Soome 			    tems.ts_c_dimension.width,
16619890ff83SToomas Soome 			    tem->tvs_c_cursor.row, 0);
16629890ff83SToomas Soome 			break;
16639890ff83SToomas Soome 		}
16649890ff83SToomas Soome 		break;
16659890ff83SToomas Soome 
16669890ff83SToomas Soome 	case 'L':		/* insert line */
16679890ff83SToomas Soome 		tem_send_data(tem);
16689890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
16699890ff83SToomas Soome 		tem_scroll(tem,
16709890ff83SToomas Soome 		    tem->tvs_c_cursor.row,
16719890ff83SToomas Soome 		    tems.ts_c_dimension.height - 1,
16729890ff83SToomas Soome 		    tem->tvs_params[0], TEM_SCROLL_DOWN);
16739890ff83SToomas Soome 		break;
16749890ff83SToomas Soome 
16759890ff83SToomas Soome 	case 'M':		/* delete line */
16769890ff83SToomas Soome 		tem_send_data(tem);
16779890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
16789890ff83SToomas Soome 		tem_scroll(tem,
16799890ff83SToomas Soome 		    tem->tvs_c_cursor.row,
16809890ff83SToomas Soome 		    tems.ts_c_dimension.height - 1,
16819890ff83SToomas Soome 		    tem->tvs_params[0], TEM_SCROLL_UP);
16829890ff83SToomas Soome 		break;
16839890ff83SToomas Soome 
16849890ff83SToomas Soome 	case 'P':		/* DCH - delete char */
16859890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
16869890ff83SToomas Soome 		tem_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT);
16879890ff83SToomas Soome 		break;
16889890ff83SToomas Soome 
16899890ff83SToomas Soome 	case 'S':		/* scroll up */
16909890ff83SToomas Soome 		tem_send_data(tem);
16919890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
16929890ff83SToomas Soome 		tem_scroll(tem, 0,
16939890ff83SToomas Soome 		    tems.ts_c_dimension.height - 1,
16949890ff83SToomas Soome 		    tem->tvs_params[0], TEM_SCROLL_UP);
16959890ff83SToomas Soome 		break;
16969890ff83SToomas Soome 
16979890ff83SToomas Soome 	case 'T':		/* scroll down */
16989890ff83SToomas Soome 		tem_send_data(tem);
16999890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
17009890ff83SToomas Soome 		tem_scroll(tem, 0,
17019890ff83SToomas Soome 		    tems.ts_c_dimension.height - 1,
17029890ff83SToomas Soome 		    tem->tvs_params[0], TEM_SCROLL_DOWN);
17039890ff83SToomas Soome 		break;
17049890ff83SToomas Soome 
17059890ff83SToomas Soome 	case 'X':		/* erase char */
17069890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
17079890ff83SToomas Soome 		tem_clear_chars(tem,
17089890ff83SToomas Soome 		    tem->tvs_params[0],
17099890ff83SToomas Soome 		    tem->tvs_c_cursor.row,
17109890ff83SToomas Soome 		    tem->tvs_c_cursor.col);
17119890ff83SToomas Soome 		break;
17129890ff83SToomas Soome 
17139890ff83SToomas Soome 	case 'Z':		/* cursor backward tabulation */
17149890ff83SToomas Soome 		tem_setparam(tem, 1, 1);
17159890ff83SToomas Soome 
17169890ff83SToomas Soome 		/*
17179890ff83SToomas Soome 		 * Rule exception - We do sanity checking here.
17189890ff83SToomas Soome 		 *
17199890ff83SToomas Soome 		 * Restrict the count to a sane value to keep from
17209890ff83SToomas Soome 		 * looping for a long time.  There can't be more than one
17219890ff83SToomas Soome 		 * tab stop per column, so use that as a limit.
17229890ff83SToomas Soome 		 */
17239890ff83SToomas Soome 		if (tem->tvs_params[0] > tems.ts_c_dimension.width)
17249890ff83SToomas Soome 			tem->tvs_params[0] = tems.ts_c_dimension.width;
17259890ff83SToomas Soome 
17269890ff83SToomas Soome 		for (i = 0; i < tem->tvs_params[0]; i++)
17279890ff83SToomas Soome 			tem_back_tab(tem);
17289890ff83SToomas Soome 		break;
17299890ff83SToomas Soome 	}
17309890ff83SToomas Soome 	tem->tvs_state = A_STATE_START;
17319890ff83SToomas Soome }
17329890ff83SToomas Soome 
17335e897995SToomas Soome static void
tem_chkparam_qmark(struct tem_vt_state * tem,tem_char_t ch)17345e897995SToomas Soome tem_chkparam_qmark(struct tem_vt_state *tem, tem_char_t ch)
17355e897995SToomas Soome {
17365e897995SToomas Soome 	switch (ch) {
17375e897995SToomas Soome 	case 'h': /* DEC private mode set */
17385e897995SToomas Soome 		tem_setparam(tem, 1, 1);
17395e897995SToomas Soome 		switch (tem->tvs_params[0]) {
1740*d863b4c1SToomas Soome 		case 7: /* Autowrap mode. */
1741*d863b4c1SToomas Soome 			tem->tvs_stateflags |= TVS_AUTOWRAP;
1742*d863b4c1SToomas Soome 			break;
1743*d863b4c1SToomas Soome 
17445e897995SToomas Soome 		case 25: /* show cursor */
17455e897995SToomas Soome 			/*
17465e897995SToomas Soome 			 * Note that cursor is not displayed either way
17475e897995SToomas Soome 			 * at this entry point.  Clearing the flag ensures
17485e897995SToomas Soome 			 * that on exit from tem_safe_terminal_emulate
17495e897995SToomas Soome 			 * we will display the cursor.
17505e897995SToomas Soome 			 */
17515e897995SToomas Soome 			tem_send_data(tem);
17525e897995SToomas Soome 			tem->tvs_cursor_hidden = false;
17535e897995SToomas Soome 			break;
17545e897995SToomas Soome 		}
17555e897995SToomas Soome 		break;
17565e897995SToomas Soome 	case 'l':
17575e897995SToomas Soome 		/* DEC private mode reset */
17585e897995SToomas Soome 		tem_setparam(tem, 1, 1);
17595e897995SToomas Soome 		switch (tem->tvs_params[0]) {
1760*d863b4c1SToomas Soome 		case 7: /* Autowrap mode. */
1761*d863b4c1SToomas Soome 			tem->tvs_stateflags &= ~TVS_AUTOWRAP;
1762*d863b4c1SToomas Soome 			break;
1763*d863b4c1SToomas Soome 
17645e897995SToomas Soome 		case 25: /* hide cursor */
17655e897995SToomas Soome 			/*
17665e897995SToomas Soome 			 * Note that the cursor is not displayed already.
17675e897995SToomas Soome 			 * This is true regardless of the flag state.
17685e897995SToomas Soome 			 * Setting this flag ensures we won't display it
17695e897995SToomas Soome 			 * on exit from tem_safe_terminal_emulate.
17705e897995SToomas Soome 			 */
17715e897995SToomas Soome 			tem_send_data(tem);
17725e897995SToomas Soome 			tem->tvs_cursor_hidden = true;
17735e897995SToomas Soome 			break;
17745e897995SToomas Soome 		}
17755e897995SToomas Soome 		break;
17765e897995SToomas Soome 	}
17775e897995SToomas Soome 	tem->tvs_state = A_STATE_START;
17785e897995SToomas Soome }
17799890ff83SToomas Soome 
17809890ff83SToomas Soome /*
17819890ff83SToomas Soome  * Gather the parameters of an ANSI escape sequence
17829890ff83SToomas Soome  */
17839890ff83SToomas Soome static void
tem_getparams(struct tem_vt_state * tem,uint8_t ch)17849890ff83SToomas Soome tem_getparams(struct tem_vt_state *tem, uint8_t ch)
17859890ff83SToomas Soome {
1786726d8a6eSToomas Soome 	if (isdigit(ch)) {
17879890ff83SToomas Soome 		tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
1788ffd79eb6SToomas Soome 		tem->tvs_gotparam = true;  /* Remember got parameter */
17899890ff83SToomas Soome 		return; /* Return immediately */
17905e897995SToomas Soome 	} else if (tem->tvs_state == A_STATE_CSI_EQUAL) {
17919890ff83SToomas Soome 		tem->tvs_state = A_STATE_START;
17925e897995SToomas Soome 	} else if (tem->tvs_state == A_STATE_CSI_QMARK) {
17935e897995SToomas Soome 		if (tem->tvs_curparam < TEM_MAXPARAMS) {
17945e897995SToomas Soome 			if (tem->tvs_gotparam) {
17955e897995SToomas Soome 				/* get the parameter value */
17965e897995SToomas Soome 				tem->tvs_params[tem->tvs_curparam] =
17975e897995SToomas Soome 				    tem->tvs_paramval;
17985e897995SToomas Soome 			}
17995e897995SToomas Soome 			tem->tvs_curparam++;
18005e897995SToomas Soome 		}
18015e897995SToomas Soome 		if (ch == ';') {
18025e897995SToomas Soome 			/* Restart parameter search */
18035e897995SToomas Soome 			tem->tvs_gotparam = false;
18045e897995SToomas Soome 			tem->tvs_paramval = 0; /* No parameter value yet */
18055e897995SToomas Soome 		} else {
18065e897995SToomas Soome 			/* Handle escape sequence */
18075e897995SToomas Soome 			tem_chkparam_qmark(tem, ch);
18085e897995SToomas Soome 		}
18099890ff83SToomas Soome 	} else {
18109890ff83SToomas Soome 		if (tem->tvs_curparam < TEM_MAXPARAMS) {
18119890ff83SToomas Soome 			if (tem->tvs_gotparam) {
18129890ff83SToomas Soome 				/* get the parameter value */
18139890ff83SToomas Soome 				tem->tvs_params[tem->tvs_curparam] =
18149890ff83SToomas Soome 				    tem->tvs_paramval;
18159890ff83SToomas Soome 			}
18169890ff83SToomas Soome 			tem->tvs_curparam++;
18179890ff83SToomas Soome 		}
18189890ff83SToomas Soome 
18199890ff83SToomas Soome 		if (ch == ';') {
18209890ff83SToomas Soome 			/* Restart parameter search */
1821ffd79eb6SToomas Soome 			tem->tvs_gotparam = false;
18225e897995SToomas Soome 			tem->tvs_paramval = 0; /* No parameter value yet */
18239890ff83SToomas Soome 		} else {
18249890ff83SToomas Soome 			/* Handle escape sequence */
18259890ff83SToomas Soome 			tem_chkparam(tem, ch);
18269890ff83SToomas Soome 		}
18279890ff83SToomas Soome 	}
18289890ff83SToomas Soome }
18299890ff83SToomas Soome 
18309890ff83SToomas Soome /*
18319890ff83SToomas Soome  * Add character to internal buffer.
18329890ff83SToomas Soome  * When its full, send it to the next layer.
18339890ff83SToomas Soome  */
18349890ff83SToomas Soome static void
tem_outch(struct tem_vt_state * tem,tem_char_t ch)18359890ff83SToomas Soome tem_outch(struct tem_vt_state *tem, tem_char_t ch)
18369890ff83SToomas Soome {
18379890ff83SToomas Soome 	text_color_t fg;
18389890ff83SToomas Soome 	text_color_t bg;
18399890ff83SToomas Soome 	text_attr_t attr;
18409890ff83SToomas Soome 
1841*d863b4c1SToomas Soome 	/* We have autowrap enabled and we did wrap - get cursor to new line */
1842*d863b4c1SToomas Soome 	if ((tem->tvs_stateflags & (TVS_AUTOWRAP | TVS_WRAPPED)) ==
1843*d863b4c1SToomas Soome 	    (TVS_AUTOWRAP | TVS_WRAPPED)) {
1844*d863b4c1SToomas Soome 		tem_new_line(tem);
1845*d863b4c1SToomas Soome 	}
1846*d863b4c1SToomas Soome 
18479890ff83SToomas Soome 	/* buffer up the character until later */
18489890ff83SToomas Soome 	tem_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE);
18499890ff83SToomas Soome 	tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr);
18509890ff83SToomas Soome 	tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg;
18519890ff83SToomas Soome 	tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg;
18529890ff83SToomas Soome 	tem->tvs_outindex++;
18539890ff83SToomas Soome 	tem->tvs_c_cursor.col++;
18549890ff83SToomas Soome 	if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
1855*d863b4c1SToomas Soome 		tem->tvs_stateflags |= TVS_WRAPPED;
1856*d863b4c1SToomas Soome 		tem->tvs_c_cursor.col--;
18579890ff83SToomas Soome 		tem_send_data(tem);
1858*d863b4c1SToomas Soome 	} else {
1859*d863b4c1SToomas Soome 		tem->tvs_stateflags &= ~TVS_WRAPPED;
18609890ff83SToomas Soome 	}
18619890ff83SToomas Soome }
18629890ff83SToomas Soome 
18639890ff83SToomas Soome static void
tem_new_line(struct tem_vt_state * tem)18649890ff83SToomas Soome tem_new_line(struct tem_vt_state *tem)
18659890ff83SToomas Soome {
18669890ff83SToomas Soome 	tem_cr(tem);
18679890ff83SToomas Soome 	tem_lf(tem);
18689890ff83SToomas Soome }
18699890ff83SToomas Soome 
18709890ff83SToomas Soome static void
tem_cr(struct tem_vt_state * tem)18719890ff83SToomas Soome tem_cr(struct tem_vt_state *tem)
18729890ff83SToomas Soome {
18739890ff83SToomas Soome 	tem->tvs_c_cursor.col = 0;
1874*d863b4c1SToomas Soome 	tem->tvs_stateflags &= ~TVS_WRAPPED;
18759890ff83SToomas Soome 	tem_align_cursor(tem);
18769890ff83SToomas Soome }
18779890ff83SToomas Soome 
18789890ff83SToomas Soome static void
tem_lf(struct tem_vt_state * tem)18799890ff83SToomas Soome tem_lf(struct tem_vt_state *tem)
18809890ff83SToomas Soome {
18819890ff83SToomas Soome 	int row;
18829890ff83SToomas Soome 
1883*d863b4c1SToomas Soome 	tem->tvs_stateflags &= ~TVS_WRAPPED;
18849890ff83SToomas Soome 	/*
18859890ff83SToomas Soome 	 * Sanity checking notes:
18869890ff83SToomas Soome 	 * . a_nscroll was validated when it was set.
18879890ff83SToomas Soome 	 * . Regardless of that, tem_scroll and tem_mv_cursor
18889890ff83SToomas Soome 	 *   will prevent anything bad from happening.
18899890ff83SToomas Soome 	 */
18909890ff83SToomas Soome 	row = tem->tvs_c_cursor.row + 1;
18919890ff83SToomas Soome 
18929890ff83SToomas Soome 	if (row >= tems.ts_c_dimension.height) {
18939890ff83SToomas Soome 		if (tem->tvs_nscroll != 0) {
18949890ff83SToomas Soome 			tem_scroll(tem, 0,
18959890ff83SToomas Soome 			    tems.ts_c_dimension.height - 1,
18969890ff83SToomas Soome 			    tem->tvs_nscroll, TEM_SCROLL_UP);
18979890ff83SToomas Soome 			row = tems.ts_c_dimension.height -
18989890ff83SToomas Soome 			    tem->tvs_nscroll;
18999890ff83SToomas Soome 		} else {	/* no scroll */
19009890ff83SToomas Soome 			/*
19019890ff83SToomas Soome 			 * implement Esc[#r when # is zero.  This means no
19029890ff83SToomas Soome 			 * scroll but just return cursor to top of screen,
19039890ff83SToomas Soome 			 * do not clear screen.
19049890ff83SToomas Soome 			 */
19059890ff83SToomas Soome 			row = 0;
19069890ff83SToomas Soome 		}
19079890ff83SToomas Soome 	}
19089890ff83SToomas Soome 
19099890ff83SToomas Soome 	tem_mv_cursor(tem, row, tem->tvs_c_cursor.col);
19109890ff83SToomas Soome 
19119890ff83SToomas Soome 	if (tem->tvs_nscroll == 0) {
19129890ff83SToomas Soome 		/* erase rest of cursor line */
19139890ff83SToomas Soome 		tem_clear_chars(tem,
19149890ff83SToomas Soome 		    tems.ts_c_dimension.width -
19159890ff83SToomas Soome 		    tem->tvs_c_cursor.col,
19169890ff83SToomas Soome 		    tem->tvs_c_cursor.row,
19179890ff83SToomas Soome 		    tem->tvs_c_cursor.col);
19189890ff83SToomas Soome 
19199890ff83SToomas Soome 	}
19209890ff83SToomas Soome 
19219890ff83SToomas Soome 	tem_align_cursor(tem);
19229890ff83SToomas Soome }
19239890ff83SToomas Soome 
19249890ff83SToomas Soome static void
tem_send_data(struct tem_vt_state * tem)19259890ff83SToomas Soome tem_send_data(struct tem_vt_state *tem)
19269890ff83SToomas Soome {
19279890ff83SToomas Soome 	if (tem->tvs_outindex == 0) {
19289890ff83SToomas Soome 		tem_align_cursor(tem);
19299890ff83SToomas Soome 		return;
19309890ff83SToomas Soome 	}
19319890ff83SToomas Soome 
19329890ff83SToomas Soome 	tem_virtual_display(tem, tem->tvs_outbuf, tem->tvs_outindex,
19339890ff83SToomas Soome 	    tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
19349890ff83SToomas Soome 
19359890ff83SToomas Soome 	if (tem->tvs_isactive) {
19369890ff83SToomas Soome 		/*
19379890ff83SToomas Soome 		 * Call the primitive to render this data.
19389890ff83SToomas Soome 		 */
19399890ff83SToomas Soome 		tem_callback_display(tem,
19409890ff83SToomas Soome 		    tem->tvs_outbuf, tem->tvs_outindex,
19419890ff83SToomas Soome 		    tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
19429890ff83SToomas Soome 	}
19439890ff83SToomas Soome 
19449890ff83SToomas Soome 	tem->tvs_outindex = 0;
19459890ff83SToomas Soome 
19469890ff83SToomas Soome 	tem_align_cursor(tem);
19479890ff83SToomas Soome }
19489890ff83SToomas Soome 
19499890ff83SToomas Soome 
19509890ff83SToomas Soome /*
19519890ff83SToomas Soome  * We have just done something to the current output point.  Reset the start
19529890ff83SToomas Soome  * point for the buffered data in a_outbuf.  There shouldn't be any data
19539890ff83SToomas Soome  * buffered yet.
19549890ff83SToomas Soome  */
19559890ff83SToomas Soome static void
tem_align_cursor(struct tem_vt_state * tem)19569890ff83SToomas Soome tem_align_cursor(struct tem_vt_state *tem)
19579890ff83SToomas Soome {
19589890ff83SToomas Soome 	tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
19599890ff83SToomas Soome 	tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
19609890ff83SToomas Soome }
19619890ff83SToomas Soome 
19629890ff83SToomas Soome /*
19639890ff83SToomas Soome  * State machine parser based on the current state and character input
19649890ff83SToomas Soome  * major terminations are to control character or normal character
19659890ff83SToomas Soome  */
19669890ff83SToomas Soome 
19679890ff83SToomas Soome static void
tem_parse(struct tem_vt_state * tem,tem_char_t ch)19689890ff83SToomas Soome tem_parse(struct tem_vt_state *tem, tem_char_t ch)
19699890ff83SToomas Soome {
19709890ff83SToomas Soome 	int	i;
19719890ff83SToomas Soome 
19729890ff83SToomas Soome 	if (tem->tvs_state == A_STATE_START) {	/* Normal state? */
19739890ff83SToomas Soome 		if (ch == A_CSI || ch == A_ESC || ch < ' ') {
19749890ff83SToomas Soome 			/* Control */
19759890ff83SToomas Soome 			tem_control(tem, ch);
19769890ff83SToomas Soome 		} else {
19779890ff83SToomas Soome 			/* Display */
19789890ff83SToomas Soome 			tem_outch(tem, ch);
19799890ff83SToomas Soome 		}
19809890ff83SToomas Soome 		return;
19819890ff83SToomas Soome 	}
19829890ff83SToomas Soome 
19839890ff83SToomas Soome 	/* In <ESC> sequence */
19849890ff83SToomas Soome 	if (tem->tvs_state != A_STATE_ESC) {	/* Need to get parameters? */
19859890ff83SToomas Soome 		if (tem->tvs_state != A_STATE_CSI) {
19869890ff83SToomas Soome 			tem_getparams(tem, ch);
19879890ff83SToomas Soome 			return;
19889890ff83SToomas Soome 		}
19899890ff83SToomas Soome 
19909890ff83SToomas Soome 		switch (ch) {
19919890ff83SToomas Soome 		case '?':
19929890ff83SToomas Soome 			tem->tvs_state = A_STATE_CSI_QMARK;
19939890ff83SToomas Soome 			return;
19949890ff83SToomas Soome 		case '=':
19959890ff83SToomas Soome 			tem->tvs_state = A_STATE_CSI_EQUAL;
19969890ff83SToomas Soome 			return;
19979890ff83SToomas Soome 		case 's':
19989890ff83SToomas Soome 			/*
19999890ff83SToomas Soome 			 * As defined below, this sequence
20009890ff83SToomas Soome 			 * saves the cursor.  However, Sun
20019890ff83SToomas Soome 			 * defines ESC[s as reset.  We resolved
20029890ff83SToomas Soome 			 * the conflict by selecting reset as it
20039890ff83SToomas Soome 			 * is exported in the termcap file for
20049890ff83SToomas Soome 			 * sun-mon, while the "save cursor"
20059890ff83SToomas Soome 			 * definition does not exist anywhere in
20069890ff83SToomas Soome 			 * /etc/termcap.
20079890ff83SToomas Soome 			 * However, having no coherent
20089890ff83SToomas Soome 			 * definition of reset, we have not
20099890ff83SToomas Soome 			 * implemented it.
20109890ff83SToomas Soome 			 */
20119890ff83SToomas Soome 
20129890ff83SToomas Soome 			/*
20139890ff83SToomas Soome 			 * Original code
20149890ff83SToomas Soome 			 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
20159890ff83SToomas Soome 			 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
20169890ff83SToomas Soome 			 * tem->tvs_state = A_STATE_START;
20179890ff83SToomas Soome 			 */
20189890ff83SToomas Soome 
20199890ff83SToomas Soome 			tem->tvs_state = A_STATE_START;
20209890ff83SToomas Soome 			return;
20219890ff83SToomas Soome 		case 'u':
20229890ff83SToomas Soome 			tem_mv_cursor(tem, tem->tvs_r_cursor.row,
20239890ff83SToomas Soome 			    tem->tvs_r_cursor.col);
20249890ff83SToomas Soome 			tem->tvs_state = A_STATE_START;
20259890ff83SToomas Soome 			return;
20269890ff83SToomas Soome 		case 'p':	/* sunbow */
20279890ff83SToomas Soome 			tem_send_data(tem);
20289890ff83SToomas Soome 			/*
20299890ff83SToomas Soome 			 * Don't set anything if we are
20309890ff83SToomas Soome 			 * already as we want to be.
20319890ff83SToomas Soome 			 */
20329890ff83SToomas Soome 			if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
20339890ff83SToomas Soome 				tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
20349890ff83SToomas Soome 				/*
20359890ff83SToomas Soome 				 * If we have switched the characters to be the
20369890ff83SToomas Soome 				 * inverse from the screen, then switch them as
20379890ff83SToomas Soome 				 * well to keep them the inverse of the screen.
20389890ff83SToomas Soome 				 */
20399890ff83SToomas Soome 				if (tem->tvs_flags & TEM_ATTR_REVERSE)
20409890ff83SToomas Soome 					tem->tvs_flags &= ~TEM_ATTR_REVERSE;
20419890ff83SToomas Soome 				else
20429890ff83SToomas Soome 					tem->tvs_flags |= TEM_ATTR_REVERSE;
20439890ff83SToomas Soome 			}
20449890ff83SToomas Soome 			tem_cls(tem);
20459890ff83SToomas Soome 			tem->tvs_state = A_STATE_START;
20469890ff83SToomas Soome 			return;
20479890ff83SToomas Soome 		case 'q':	/* sunwob */
20489890ff83SToomas Soome 			tem_send_data(tem);
20499890ff83SToomas Soome 			/*
20509890ff83SToomas Soome 			 * Don't set anything if we are
20519890ff83SToomas Soome 			 * already where as we want to be.
20529890ff83SToomas Soome 			 */
20539890ff83SToomas Soome 			if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
20549890ff83SToomas Soome 				tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
20559890ff83SToomas Soome 				/*
20569890ff83SToomas Soome 				 * If we have switched the characters to be the
20579890ff83SToomas Soome 				 * inverse from the screen, then switch them as
20589890ff83SToomas Soome 				 * well to keep them the inverse of the screen.
20599890ff83SToomas Soome 				 */
20609890ff83SToomas Soome 				if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
20619890ff83SToomas Soome 					tem->tvs_flags |= TEM_ATTR_REVERSE;
20629890ff83SToomas Soome 				else
20639890ff83SToomas Soome 					tem->tvs_flags &= ~TEM_ATTR_REVERSE;
20649890ff83SToomas Soome 			}
20659890ff83SToomas Soome 
20669890ff83SToomas Soome 			tem_cls(tem);
20679890ff83SToomas Soome 			tem->tvs_state = A_STATE_START;
20689890ff83SToomas Soome 			return;
20699890ff83SToomas Soome 		case 'r':	/* sunscrl */
20709890ff83SToomas Soome 			/*
20719890ff83SToomas Soome 			 * Rule exception:  check for validity here.
20729890ff83SToomas Soome 			 */
20739890ff83SToomas Soome 			tem->tvs_nscroll = tem->tvs_paramval;
20749890ff83SToomas Soome 			if (tem->tvs_nscroll > tems.ts_c_dimension.height)
20759890ff83SToomas Soome 				tem->tvs_nscroll = tems.ts_c_dimension.height;
20769890ff83SToomas Soome 			if (tem->tvs_nscroll < 0)
20779890ff83SToomas Soome 				tem->tvs_nscroll = 1;
20789890ff83SToomas Soome 			tem->tvs_state = A_STATE_START;
20799890ff83SToomas Soome 			return;
20809890ff83SToomas Soome 		default:
20819890ff83SToomas Soome 			tem_getparams(tem, ch);
20829890ff83SToomas Soome 			return;
20839890ff83SToomas Soome 		}
20849890ff83SToomas Soome 	}
20859890ff83SToomas Soome 
20869890ff83SToomas Soome 	/* Previous char was <ESC> */
20879890ff83SToomas Soome 	if (ch == '[') {
20889890ff83SToomas Soome 		tem->tvs_curparam = 0;
20899890ff83SToomas Soome 		tem->tvs_paramval = 0;
2090ffd79eb6SToomas Soome 		tem->tvs_gotparam = false;
20919890ff83SToomas Soome 		/* clear the parameters */
20929890ff83SToomas Soome 		for (i = 0; i < TEM_MAXPARAMS; i++)
20939890ff83SToomas Soome 			tem->tvs_params[i] = -1;
20949890ff83SToomas Soome 		tem->tvs_state = A_STATE_CSI;
20959890ff83SToomas Soome 	} else if (ch == 'Q') {	/* <ESC>Q ? */
20969890ff83SToomas Soome 		tem->tvs_state = A_STATE_START;
20979890ff83SToomas Soome 	} else if (ch == 'C') {	/* <ESC>C ? */
20989890ff83SToomas Soome 		tem->tvs_state = A_STATE_START;
20999890ff83SToomas Soome 	} else {
21009890ff83SToomas Soome 		tem->tvs_state = A_STATE_START;
21019890ff83SToomas Soome 		if (ch == 'c') {
21029890ff83SToomas Soome 			/* ESC c resets display */
2103ffd79eb6SToomas Soome 			tem_reset_display(tem, true, true);
21049890ff83SToomas Soome 		} else if (ch == 'H') {
21059890ff83SToomas Soome 			/* ESC H sets a tab */
21069890ff83SToomas Soome 			tem_set_tab(tem);
21079890ff83SToomas Soome 		} else if (ch == '7') {
21089890ff83SToomas Soome 			/* ESC 7 Save Cursor position */
21099890ff83SToomas Soome 			tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
21109890ff83SToomas Soome 			tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
21119890ff83SToomas Soome 		} else if (ch == '8') {
21129890ff83SToomas Soome 			/* ESC 8 Restore Cursor position */
21139890ff83SToomas Soome 			tem_mv_cursor(tem, tem->tvs_r_cursor.row,
21149890ff83SToomas Soome 			    tem->tvs_r_cursor.col);
21159890ff83SToomas Soome 		/* check for control chars */
21169890ff83SToomas Soome 		} else if (ch < ' ') {
21179890ff83SToomas Soome 			tem_control(tem, ch);
21189890ff83SToomas Soome 		} else {
21199890ff83SToomas Soome 			tem_outch(tem, ch);
21209890ff83SToomas Soome 		}
21219890ff83SToomas Soome 	}
21229890ff83SToomas Soome }
21239890ff83SToomas Soome 
21249890ff83SToomas Soome /* ARGSUSED */
21259890ff83SToomas Soome static void
tem_bell(struct tem_vt_state * tem __unused)21269890ff83SToomas Soome tem_bell(struct tem_vt_state *tem __unused)
21279890ff83SToomas Soome {
21289890ff83SToomas Soome 		/* (void) beep(BEEP_CONSOLE); */
21299890ff83SToomas Soome }
21309890ff83SToomas Soome 
21319890ff83SToomas Soome 
21329890ff83SToomas Soome static void
tem_scroll(struct tem_vt_state * tem,int start,int end,int count,int direction)21339890ff83SToomas Soome tem_scroll(struct tem_vt_state *tem, int start, int end, int count,
21349890ff83SToomas Soome     int direction)
21359890ff83SToomas Soome {
21369890ff83SToomas Soome 	int	row;
21379890ff83SToomas Soome 	int	lines_affected;
21389890ff83SToomas Soome 
21399890ff83SToomas Soome 	lines_affected = end - start + 1;
21409890ff83SToomas Soome 	if (count > lines_affected)
21419890ff83SToomas Soome 		count = lines_affected;
21429890ff83SToomas Soome 	if (count <= 0)
21439890ff83SToomas Soome 		return;
21449890ff83SToomas Soome 
21459890ff83SToomas Soome 	switch (direction) {
21469890ff83SToomas Soome 	case TEM_SCROLL_UP:
21479890ff83SToomas Soome 		if (count < lines_affected) {
21489890ff83SToomas Soome 			tem_copy_area(tem, 0, start + count,
21499890ff83SToomas Soome 			    tems.ts_c_dimension.width - 1, end, 0, start);
21509890ff83SToomas Soome 		}
21519890ff83SToomas Soome 		for (row = (end - count) + 1; row <= end; row++) {
21529890ff83SToomas Soome 			tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0);
21539890ff83SToomas Soome 		}
21549890ff83SToomas Soome 		break;
21559890ff83SToomas Soome 
21569890ff83SToomas Soome 	case TEM_SCROLL_DOWN:
21579890ff83SToomas Soome 		if (count < lines_affected) {
21589890ff83SToomas Soome 			tem_copy_area(tem, 0, start,
21599890ff83SToomas Soome 			    tems.ts_c_dimension.width - 1,
21609890ff83SToomas Soome 			    end - count, 0, start + count);
21619890ff83SToomas Soome 		}
21629890ff83SToomas Soome 		for (row = start; row < start + count; row++) {
21639890ff83SToomas Soome 			tem_clear_chars(tem, tems.ts_c_dimension.width, row, 0);
21649890ff83SToomas Soome 		}
21659890ff83SToomas Soome 		break;
21669890ff83SToomas Soome 	}
21679890ff83SToomas Soome }
21689890ff83SToomas Soome 
21699890ff83SToomas Soome static int
tem_copy_width(term_char_t * src,term_char_t * dst,int cols)21709890ff83SToomas Soome tem_copy_width(term_char_t *src, term_char_t *dst, int cols)
21719890ff83SToomas Soome {
21729890ff83SToomas Soome 	int width = cols - 1;
21739890ff83SToomas Soome 
21749890ff83SToomas Soome 	while (width >= 0) {
21759890ff83SToomas Soome 		/* We do not have image bits to compare, stop there. */
21769890ff83SToomas Soome 		if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE ||
21779890ff83SToomas Soome 		    TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE)
21789890ff83SToomas Soome 			break;
21799890ff83SToomas Soome 
21809890ff83SToomas Soome 		/*
21819890ff83SToomas Soome 		 * Find difference on line, compare char with its attributes
21829890ff83SToomas Soome 		 * and colors.
21839890ff83SToomas Soome 		 */
21849890ff83SToomas Soome 		if (src[width].tc_char != dst[width].tc_char ||
2185fa9eb222SToomas Soome 		    src[width].tc_fg_color.n != dst[width].tc_fg_color.n ||
2186fa9eb222SToomas Soome 		    src[width].tc_bg_color.n != dst[width].tc_bg_color.n) {
21879890ff83SToomas Soome 			break;
21889890ff83SToomas Soome 		}
21899890ff83SToomas Soome 		width--;
21909890ff83SToomas Soome 	}
21919890ff83SToomas Soome 	return (width + 1);
21929890ff83SToomas Soome }
21939890ff83SToomas Soome 
21949890ff83SToomas Soome static void
tem_copy_area(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row)21959890ff83SToomas Soome tem_copy_area(struct tem_vt_state *tem,
21969890ff83SToomas Soome     screen_pos_t s_col, screen_pos_t s_row,
21979890ff83SToomas Soome     screen_pos_t e_col, screen_pos_t e_row,
21989890ff83SToomas Soome     screen_pos_t t_col, screen_pos_t t_row)
21999890ff83SToomas Soome {
22009890ff83SToomas Soome 	size_t soffset, toffset;
22019890ff83SToomas Soome 	term_char_t *src, *dst;
22029890ff83SToomas Soome 	int rows;
22039890ff83SToomas Soome 	int cols;
22049890ff83SToomas Soome 
22059890ff83SToomas Soome 	if (s_col < 0 || s_row < 0 ||
22069890ff83SToomas Soome 	    e_col < 0 || e_row < 0 ||
22079890ff83SToomas Soome 	    t_col < 0 || t_row < 0 ||
22089890ff83SToomas Soome 	    s_col >= tems.ts_c_dimension.width ||
22099890ff83SToomas Soome 	    e_col >= tems.ts_c_dimension.width ||
22109890ff83SToomas Soome 	    t_col >= tems.ts_c_dimension.width ||
22119890ff83SToomas Soome 	    s_row >= tems.ts_c_dimension.height ||
22129890ff83SToomas Soome 	    e_row >= tems.ts_c_dimension.height ||
22139890ff83SToomas Soome 	    t_row >= tems.ts_c_dimension.height)
22149890ff83SToomas Soome 		return;
22159890ff83SToomas Soome 
22169890ff83SToomas Soome 	if (s_row > e_row || s_col > e_col)
22179890ff83SToomas Soome 		return;
22189890ff83SToomas Soome 
22199890ff83SToomas Soome 	rows = e_row - s_row + 1;
22209890ff83SToomas Soome 	cols = e_col - s_col + 1;
22219890ff83SToomas Soome 	if (t_row + rows > tems.ts_c_dimension.height ||
22229890ff83SToomas Soome 	    t_col + cols > tems.ts_c_dimension.width)
22239890ff83SToomas Soome 		return;
22249890ff83SToomas Soome 
22259890ff83SToomas Soome 	if (tem->tvs_screen_buf == NULL) {
22269890ff83SToomas Soome 		if (tem->tvs_isactive) {
22279890ff83SToomas Soome 			tem_callback_copy(tem, s_col, s_row,
22289890ff83SToomas Soome 			    e_col, e_row, t_col, t_row);
22299890ff83SToomas Soome 		}
22309890ff83SToomas Soome 		return;
22319890ff83SToomas Soome 	}
22329890ff83SToomas Soome 
22339890ff83SToomas Soome 	soffset = s_col + s_row * tems.ts_c_dimension.width;
22349890ff83SToomas Soome 	toffset = t_col + t_row * tems.ts_c_dimension.width;
22359890ff83SToomas Soome 	src = tem->tvs_screen_buf + soffset;
22369890ff83SToomas Soome 	dst = tem->tvs_screen_buf + toffset;
22379890ff83SToomas Soome 
22389890ff83SToomas Soome 	/*
22399890ff83SToomas Soome 	 * Copy line by line. We determine the length by comparing the
22409890ff83SToomas Soome 	 * screen content from cached text in tvs_screen_buf.
22419890ff83SToomas Soome 	 */
22429890ff83SToomas Soome 	if (toffset <= soffset) {
22439890ff83SToomas Soome 		for (int i = 0; i < rows; i++) {
22449890ff83SToomas Soome 			int increment = i * tems.ts_c_dimension.width;
22459890ff83SToomas Soome 			int width;
22469890ff83SToomas Soome 
22479890ff83SToomas Soome 			width = tem_copy_width(src + increment,
22489890ff83SToomas Soome 			    dst + increment, cols);
22499890ff83SToomas Soome 			memmove(dst + increment, src + increment,
22509890ff83SToomas Soome 			    width * sizeof (term_char_t));
22519890ff83SToomas Soome 			if (tem->tvs_isactive) {
22529890ff83SToomas Soome 				tem_callback_copy(tem, s_col, s_row + i,
22539890ff83SToomas Soome 				    e_col - cols + width, s_row + i,
22549890ff83SToomas Soome 				    t_col, t_row + i);
22559890ff83SToomas Soome 			}
22569890ff83SToomas Soome 		}
22579890ff83SToomas Soome 	} else {
22589890ff83SToomas Soome 		for (int i = rows - 1; i >= 0; i--) {
22599890ff83SToomas Soome 			int increment = i * tems.ts_c_dimension.width;
22609890ff83SToomas Soome 			int width;
22619890ff83SToomas Soome 
22629890ff83SToomas Soome 			width = tem_copy_width(src + increment,
22639890ff83SToomas Soome 			    dst + increment, cols);
22649890ff83SToomas Soome 			memmove(dst + increment, src + increment,
22659890ff83SToomas Soome 			    width * sizeof (term_char_t));
22669890ff83SToomas Soome 			if (tem->tvs_isactive) {
22679890ff83SToomas Soome 				tem_callback_copy(tem, s_col, s_row + i,
22689890ff83SToomas Soome 				    e_col - cols + width, s_row + i,
22699890ff83SToomas Soome 				    t_col, t_row + i);
22709890ff83SToomas Soome 			}
22719890ff83SToomas Soome 		}
22729890ff83SToomas Soome 	}
22739890ff83SToomas Soome }
22749890ff83SToomas Soome 
22759890ff83SToomas Soome static void
tem_clear_chars(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col)22769890ff83SToomas Soome tem_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
22779890ff83SToomas Soome     screen_pos_t col)
22789890ff83SToomas Soome {
22799890ff83SToomas Soome 	if (row < 0 || row >= tems.ts_c_dimension.height ||
22809890ff83SToomas Soome 	    col < 0 || col >= tems.ts_c_dimension.width ||
22819890ff83SToomas Soome 	    count < 0)
22829890ff83SToomas Soome 		return;
22839890ff83SToomas Soome 
22849890ff83SToomas Soome 	/*
22859890ff83SToomas Soome 	 * Note that very large values of "count" could cause col+count
22869890ff83SToomas Soome 	 * to overflow, so we check "count" independently.
22879890ff83SToomas Soome 	 */
22889890ff83SToomas Soome 	if (count > tems.ts_c_dimension.width ||
22899890ff83SToomas Soome 	    col + count > tems.ts_c_dimension.width)
22909890ff83SToomas Soome 		count = tems.ts_c_dimension.width - col;
22919890ff83SToomas Soome 
22929890ff83SToomas Soome 	tem_virtual_cls(tem, count, row, col);
22939890ff83SToomas Soome 
22949890ff83SToomas Soome 	if (!tem->tvs_isactive)
22959890ff83SToomas Soome 		return;
22969890ff83SToomas Soome 
22979890ff83SToomas Soome 	tem_callback_cls(tem, count, row, col);
22989890ff83SToomas Soome }
22999890ff83SToomas Soome 
23009890ff83SToomas Soome static void
tem_text_display(struct tem_vt_state * tem __unused,term_char_t * string,int count,screen_pos_t row,screen_pos_t col)23019890ff83SToomas Soome tem_text_display(struct tem_vt_state *tem __unused, term_char_t *string,
23029890ff83SToomas Soome     int count, screen_pos_t row, screen_pos_t col)
23039890ff83SToomas Soome {
23049890ff83SToomas Soome 	struct vis_consdisplay da;
23059890ff83SToomas Soome 	int i;
23069890ff83SToomas Soome 	tem_char_t c;
2307fa9eb222SToomas Soome 	text_color_t bg, fg;
23089890ff83SToomas Soome 
23099890ff83SToomas Soome 	if (count == 0)
23109890ff83SToomas Soome 		return;
23119890ff83SToomas Soome 
23129890ff83SToomas Soome 	da.data = (unsigned char *)&c;
23139890ff83SToomas Soome 	da.width = 1;
23149890ff83SToomas Soome 	da.row = row;
23159890ff83SToomas Soome 	da.col = col;
23169890ff83SToomas Soome 
23179890ff83SToomas Soome 	for (i = 0; i < count; i++) {
2318fa9eb222SToomas Soome 		tem_get_color(tem, &fg, &bg, &string[i]);
2319fa9eb222SToomas Soome 		tem_set_color(&fg, &da.fg_color);
2320fa9eb222SToomas Soome 		tem_set_color(&bg, &da.bg_color);
23219890ff83SToomas Soome 		c = TEM_CHAR(string[i].tc_char);
23229890ff83SToomas Soome 		tems_display(&da);
23239890ff83SToomas Soome 		da.col++;
23249890ff83SToomas Soome 	}
23259890ff83SToomas Soome }
23269890ff83SToomas Soome 
23279890ff83SToomas Soome /*
23289890ff83SToomas Soome  * This function is used to mark a rectangular image area so the scrolling
23299890ff83SToomas Soome  * will know we need to copy the data from there.
23309890ff83SToomas Soome  */
23319890ff83SToomas Soome void
tem_image_display(struct tem_vt_state * tem,screen_pos_t s_row,screen_pos_t s_col,screen_pos_t e_row,screen_pos_t e_col)23329890ff83SToomas Soome tem_image_display(struct tem_vt_state *tem, screen_pos_t s_row,
23339890ff83SToomas Soome     screen_pos_t s_col, screen_pos_t e_row, screen_pos_t e_col)
23349890ff83SToomas Soome {
23359890ff83SToomas Soome 	screen_pos_t i, j;
23369890ff83SToomas Soome 	term_char_t c;
23379890ff83SToomas Soome 
23389890ff83SToomas Soome 	c.tc_char = TEM_ATTR(TEM_ATTR_IMAGE);
23399890ff83SToomas Soome 
23409890ff83SToomas Soome 	for (i = s_row; i <= e_row; i++) {
23419890ff83SToomas Soome 		for (j = s_col; j <= e_col; j++) {
23429890ff83SToomas Soome 			tem_virtual_display(tem, &c, 1, i, j);
23439890ff83SToomas Soome 		}
23449890ff83SToomas Soome 	}
23459890ff83SToomas Soome }
23469890ff83SToomas Soome 
23479890ff83SToomas Soome /*ARGSUSED*/
23489890ff83SToomas Soome static void
tem_text_copy(struct tem_vt_state * tem __unused,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row)23499890ff83SToomas Soome tem_text_copy(struct tem_vt_state *tem __unused,
23509890ff83SToomas Soome     screen_pos_t s_col, screen_pos_t s_row,
23519890ff83SToomas Soome     screen_pos_t e_col, screen_pos_t e_row,
23529890ff83SToomas Soome     screen_pos_t t_col, screen_pos_t t_row)
23539890ff83SToomas Soome {
23549890ff83SToomas Soome 	struct vis_conscopy da;
23559890ff83SToomas Soome 
23569890ff83SToomas Soome 	da.s_row = s_row;
23579890ff83SToomas Soome 	da.s_col = s_col;
23589890ff83SToomas Soome 	da.e_row = e_row;
23599890ff83SToomas Soome 	da.e_col = e_col;
23609890ff83SToomas Soome 	da.t_row = t_row;
23619890ff83SToomas Soome 	da.t_col = t_col;
23629890ff83SToomas Soome 	tems_copy(&da);
23639890ff83SToomas Soome }
23649890ff83SToomas Soome 
23659890ff83SToomas Soome static void
tem_text_cls(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col)23669890ff83SToomas Soome tem_text_cls(struct tem_vt_state *tem,
23679890ff83SToomas Soome     int count, screen_pos_t row, screen_pos_t col)
23689890ff83SToomas Soome {
23699890ff83SToomas Soome 	text_attr_t attr;
23709890ff83SToomas Soome 	term_char_t c;
23719890ff83SToomas Soome 	int i;
23729890ff83SToomas Soome 
23739890ff83SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
23749890ff83SToomas Soome 	    TEM_ATTR_SCREEN_REVERSE);
23759890ff83SToomas Soome 	c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
23769890ff83SToomas Soome 
23779890ff83SToomas Soome 	if (count > tems.ts_c_dimension.width ||
23789890ff83SToomas Soome 	    col + count > tems.ts_c_dimension.width)
23799890ff83SToomas Soome 		count = tems.ts_c_dimension.width - col;
23809890ff83SToomas Soome 
23819890ff83SToomas Soome 	for (i = 0; i < count; i++)
23829890ff83SToomas Soome 		tem_text_display(tem, &c, 1, row, col++);
23839890ff83SToomas Soome 
23849890ff83SToomas Soome }
23859890ff83SToomas Soome 
23869890ff83SToomas Soome static void
tem_pix_display(struct tem_vt_state * tem,term_char_t * string,int count,screen_pos_t row,screen_pos_t col)23879890ff83SToomas Soome tem_pix_display(struct tem_vt_state *tem,
23889890ff83SToomas Soome     term_char_t *string, int count,
23899890ff83SToomas Soome     screen_pos_t row, screen_pos_t col)
23909890ff83SToomas Soome {
23919890ff83SToomas Soome 	struct vis_consdisplay da;
23929890ff83SToomas Soome 	int	i;
23939890ff83SToomas Soome 
23949890ff83SToomas Soome 	da.data = (uint8_t *)tem->tvs_pix_data;
23959890ff83SToomas Soome 	da.width = tems.ts_font.vf_width;
23969890ff83SToomas Soome 	da.height = tems.ts_font.vf_height;
23979890ff83SToomas Soome 	da.row = (row * da.height) + tems.ts_p_offset.y;
23989890ff83SToomas Soome 	da.col = (col * da.width) + tems.ts_p_offset.x;
23999890ff83SToomas Soome 
24009890ff83SToomas Soome 	for (i = 0; i < count; i++) {
2401fa9eb222SToomas Soome 		tem_callback_bit2pix(tem, &string[i]);
24029890ff83SToomas Soome 		tems_display(&da);
24039890ff83SToomas Soome 		da.col += da.width;
24049890ff83SToomas Soome 	}
24059890ff83SToomas Soome }
24069890ff83SToomas Soome 
24079890ff83SToomas Soome static void
tem_pix_copy(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row)24089890ff83SToomas Soome tem_pix_copy(struct tem_vt_state *tem,
24099890ff83SToomas Soome     screen_pos_t s_col, screen_pos_t s_row,
24109890ff83SToomas Soome     screen_pos_t e_col, screen_pos_t e_row,
24119890ff83SToomas Soome     screen_pos_t t_col, screen_pos_t t_row)
24129890ff83SToomas Soome {
24139890ff83SToomas Soome 	struct vis_conscopy ma;
2414ffd79eb6SToomas Soome 	static bool need_clear = true;
24159890ff83SToomas Soome 
24169890ff83SToomas Soome 	if (need_clear && tem->tvs_first_line > 0) {
24179890ff83SToomas Soome 		/*
24189890ff83SToomas Soome 		 * Clear OBP output above our kernel console term
24199890ff83SToomas Soome 		 * when our kernel console term begins to scroll up,
24209890ff83SToomas Soome 		 * we hope it is user friendly.
24219890ff83SToomas Soome 		 * (Also see comments on tem_pix_clear_prom_output)
24229890ff83SToomas Soome 		 *
24239890ff83SToomas Soome 		 * This is only one time call.
24249890ff83SToomas Soome 		 */
24259890ff83SToomas Soome 		tem_pix_clear_prom_output(tem);
24269890ff83SToomas Soome 	}
2427ffd79eb6SToomas Soome 	need_clear = false;
24289890ff83SToomas Soome 
24299890ff83SToomas Soome 	ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
24309890ff83SToomas Soome 	ma.e_row = (e_row + 1) * tems.ts_font.vf_height +
24319890ff83SToomas Soome 	    tems.ts_p_offset.y - 1;
24329890ff83SToomas Soome 	ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
24339890ff83SToomas Soome 
24349890ff83SToomas Soome 	/*
24359890ff83SToomas Soome 	 * Check if we're in process of clearing OBP's columns area,
24369890ff83SToomas Soome 	 * which only happens when term scrolls up a whole line.
24379890ff83SToomas Soome 	 */
24389890ff83SToomas Soome 	if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
24399890ff83SToomas Soome 	    e_col == tems.ts_c_dimension.width - 1) {
24409890ff83SToomas Soome 		/*
24419890ff83SToomas Soome 		 * We need to clear OBP's columns area outside our kernel
24429890ff83SToomas Soome 		 * console term. So that we set ma.e_col to entire row here.
24439890ff83SToomas Soome 		 */
24449890ff83SToomas Soome 		ma.s_col = s_col * tems.ts_font.vf_width;
24459890ff83SToomas Soome 		ma.e_col = tems.ts_p_dimension.width - 1;
24469890ff83SToomas Soome 
24479890ff83SToomas Soome 		ma.t_col = t_col * tems.ts_font.vf_width;
24489890ff83SToomas Soome 	} else {
24499890ff83SToomas Soome 		ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
24509890ff83SToomas Soome 		ma.e_col = (e_col + 1) * tems.ts_font.vf_width +
24519890ff83SToomas Soome 		    tems.ts_p_offset.x - 1;
24529890ff83SToomas Soome 		ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
24539890ff83SToomas Soome 	}
24549890ff83SToomas Soome 
24559890ff83SToomas Soome 	tems_copy(&ma);
24569890ff83SToomas Soome 
24579890ff83SToomas Soome 	if (tem->tvs_first_line > 0 && t_row < s_row) {
24589890ff83SToomas Soome 		/* We have scrolled up (s_row - t_row) rows. */
24599890ff83SToomas Soome 		tem->tvs_first_line -= (s_row - t_row);
24609890ff83SToomas Soome 		if (tem->tvs_first_line <= 0) {
24619890ff83SToomas Soome 			/* All OBP rows have been cleared. */
24629890ff83SToomas Soome 			tem->tvs_first_line = 0;
24639890ff83SToomas Soome 		}
24649890ff83SToomas Soome 	}
24659890ff83SToomas Soome }
24669890ff83SToomas Soome 
24679890ff83SToomas Soome static void
tem_pix_bit2pix(struct tem_vt_state * tem,term_char_t * c)2468fa9eb222SToomas Soome tem_pix_bit2pix(struct tem_vt_state *tem, term_char_t *c)
24699890ff83SToomas Soome {
24709890ff83SToomas Soome 	text_color_t fg, bg;
24719890ff83SToomas Soome 
2472fa9eb222SToomas Soome 	tem_get_color(tem, &fg, &bg, c);
2473fa9eb222SToomas Soome 	bit_to_pix32(tem, c->tc_char, fg, bg);
24749890ff83SToomas Soome }
24759890ff83SToomas Soome 
24769890ff83SToomas Soome 
24779890ff83SToomas Soome /*
24789890ff83SToomas Soome  * This function only clears count of columns in one row
24799890ff83SToomas Soome  */
24809890ff83SToomas Soome static void
tem_pix_cls(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col)24819890ff83SToomas Soome tem_pix_cls(struct tem_vt_state *tem, int count,
24829890ff83SToomas Soome     screen_pos_t row, screen_pos_t col)
24839890ff83SToomas Soome {
24849890ff83SToomas Soome 	tem_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
2485ffd79eb6SToomas Soome 	    col, count, tems.ts_p_offset.x, false);
24869890ff83SToomas Soome }
24879890ff83SToomas Soome 
24889890ff83SToomas Soome /*
24899890ff83SToomas Soome  * This function clears OBP output above our kernel console term area
24909890ff83SToomas Soome  * because OBP's term may have a bigger terminal window than that of
24919890ff83SToomas Soome  * our kernel console term. So we need to clear OBP output garbage outside
24929890ff83SToomas Soome  * of our kernel console term at a proper time, which is when the first
24939890ff83SToomas Soome  * row output of our kernel console term scrolls at the first screen line.
24949890ff83SToomas Soome  *
24959890ff83SToomas Soome  *	_________________________________
24969890ff83SToomas Soome  *	|   _____________________	|  ---> OBP's bigger term window
24979890ff83SToomas Soome  *	|   |			|	|
24989890ff83SToomas Soome  *	|___|			|	|
24999890ff83SToomas Soome  *	| | |			|	|
25009890ff83SToomas Soome  *	| | |			|	|
25019890ff83SToomas Soome  *	|_|_|___________________|_______|
25029890ff83SToomas Soome  *	  | |			|	   ---> first line
25039890ff83SToomas Soome  *	  | |___________________|---> our kernel console term window
25049890ff83SToomas Soome  *	  |
25059890ff83SToomas Soome  *	  |---> columns area to be cleared
25069890ff83SToomas Soome  *
25079890ff83SToomas Soome  * This function only takes care of the output above our kernel console term,
25089890ff83SToomas Soome  * and tem_prom_scroll_up takes care of columns area outside of our kernel
25099890ff83SToomas Soome  * console term.
25109890ff83SToomas Soome  */
25119890ff83SToomas Soome static void
tem_pix_clear_prom_output(struct tem_vt_state * tem)25129890ff83SToomas Soome tem_pix_clear_prom_output(struct tem_vt_state *tem)
25139890ff83SToomas Soome {
25149890ff83SToomas Soome 	int	nrows, ncols, width, height, offset;
25159890ff83SToomas Soome 
25169890ff83SToomas Soome 	width = tems.ts_font.vf_width;
25179890ff83SToomas Soome 	height = tems.ts_font.vf_height;
25189890ff83SToomas Soome 	offset = tems.ts_p_offset.y % height;
25199890ff83SToomas Soome 
25209890ff83SToomas Soome 	nrows = tems.ts_p_offset.y / height;
2521726d8a6eSToomas Soome 	ncols = (tems.ts_p_dimension.width + (width - 1)) / width;
25229890ff83SToomas Soome 
25239890ff83SToomas Soome 	if (nrows > 0)
2524ffd79eb6SToomas Soome 		tem_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0, false);
25259890ff83SToomas Soome }
25269890ff83SToomas Soome 
25279890ff83SToomas Soome /*
25289890ff83SToomas Soome  * Clear the whole screen and reset the cursor to start point.
25299890ff83SToomas Soome  */
25309890ff83SToomas Soome static void
tem_cls(struct tem_vt_state * tem)25319890ff83SToomas Soome tem_cls(struct tem_vt_state *tem)
25329890ff83SToomas Soome {
25339890ff83SToomas Soome 	struct vis_consclear cl;
25349890ff83SToomas Soome 	text_color_t fg_color;
25359890ff83SToomas Soome 	text_color_t bg_color;
25369890ff83SToomas Soome 	text_attr_t attr;
25379890ff83SToomas Soome 	term_char_t c;
25389890ff83SToomas Soome 	int row;
25399890ff83SToomas Soome 
25409890ff83SToomas Soome 	for (row = 0; row < tems.ts_c_dimension.height; row++) {
25419890ff83SToomas Soome 		tem_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
25429890ff83SToomas Soome 	}
25439890ff83SToomas Soome 
25449890ff83SToomas Soome 	if (!tem->tvs_isactive)
25459890ff83SToomas Soome 		return;
25469890ff83SToomas Soome 
25479890ff83SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
25489890ff83SToomas Soome 	    TEM_ATTR_SCREEN_REVERSE);
25499890ff83SToomas Soome 	c.tc_char = TEM_ATTR(attr);
25509890ff83SToomas Soome 
2551fa9eb222SToomas Soome 	tem_get_color(tem, &fg_color, &bg_color, &c);
2552fa9eb222SToomas Soome 	tem_set_color(&bg_color, &cl.bg_color);
2553f6760972SToomas Soome 	(void) tems_cls(&cl);
25549890ff83SToomas Soome 
25559890ff83SToomas Soome 	tem->tvs_c_cursor.row = 0;
25569890ff83SToomas Soome 	tem->tvs_c_cursor.col = 0;
25579890ff83SToomas Soome 	tem_align_cursor(tem);
25589890ff83SToomas Soome }
25599890ff83SToomas Soome 
25609890ff83SToomas Soome static void
tem_back_tab(struct tem_vt_state * tem)25619890ff83SToomas Soome tem_back_tab(struct tem_vt_state *tem)
25629890ff83SToomas Soome {
25639890ff83SToomas Soome 	int	i;
25649890ff83SToomas Soome 	screen_pos_t	tabstop;
25659890ff83SToomas Soome 
25669890ff83SToomas Soome 	tabstop = 0;
25679890ff83SToomas Soome 
25689890ff83SToomas Soome 	for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
25699890ff83SToomas Soome 		if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
25709890ff83SToomas Soome 			tabstop = tem->tvs_tabs[i];
25719890ff83SToomas Soome 			break;
25729890ff83SToomas Soome 		}
25739890ff83SToomas Soome 	}
25749890ff83SToomas Soome 
25759890ff83SToomas Soome 	tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop);
25769890ff83SToomas Soome }
25779890ff83SToomas Soome 
25789890ff83SToomas Soome static void
tem_tab(struct tem_vt_state * tem)25799890ff83SToomas Soome tem_tab(struct tem_vt_state *tem)
25809890ff83SToomas Soome {
2581ba2848d4SToomas Soome 	size_t	i;
25829890ff83SToomas Soome 	screen_pos_t	tabstop;
25839890ff83SToomas Soome 
25849890ff83SToomas Soome 	tabstop = tems.ts_c_dimension.width - 1;
25859890ff83SToomas Soome 
25869890ff83SToomas Soome 	for (i = 0; i < tem->tvs_ntabs; i++) {
25879890ff83SToomas Soome 		if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
25889890ff83SToomas Soome 			tabstop = tem->tvs_tabs[i];
25899890ff83SToomas Soome 			break;
25909890ff83SToomas Soome 		}
25919890ff83SToomas Soome 	}
25929890ff83SToomas Soome 
25939890ff83SToomas Soome 	tem_mv_cursor(tem, tem->tvs_c_cursor.row, tabstop);
25949890ff83SToomas Soome }
25959890ff83SToomas Soome 
25969890ff83SToomas Soome static void
tem_set_tab(struct tem_vt_state * tem)25979890ff83SToomas Soome tem_set_tab(struct tem_vt_state *tem)
25989890ff83SToomas Soome {
2599ba2848d4SToomas Soome 	size_t	i, j;
26009890ff83SToomas Soome 
2601ba2848d4SToomas Soome 	if (tem->tvs_ntabs == tem->tvs_maxtab)
26029890ff83SToomas Soome 		return;
26039890ff83SToomas Soome 	if (tem->tvs_ntabs == 0 ||
26049890ff83SToomas Soome 	    tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
26059890ff83SToomas Soome 			tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
26069890ff83SToomas Soome 			return;
26079890ff83SToomas Soome 	}
26089890ff83SToomas Soome 	for (i = 0; i < tem->tvs_ntabs; i++) {
26099890ff83SToomas Soome 		if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
26109890ff83SToomas Soome 			return;
26119890ff83SToomas Soome 		if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
26129890ff83SToomas Soome 			for (j = tem->tvs_ntabs - 1; j >= i; j--)
26139890ff83SToomas Soome 				tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
26149890ff83SToomas Soome 			tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
26159890ff83SToomas Soome 			tem->tvs_ntabs++;
26169890ff83SToomas Soome 			return;
26179890ff83SToomas Soome 		}
26189890ff83SToomas Soome 	}
26199890ff83SToomas Soome }
26209890ff83SToomas Soome 
26219890ff83SToomas Soome static void
tem_clear_tabs(struct tem_vt_state * tem,int action)26229890ff83SToomas Soome tem_clear_tabs(struct tem_vt_state *tem, int action)
26239890ff83SToomas Soome {
2624ba2848d4SToomas Soome 	size_t	i, j;
26259890ff83SToomas Soome 
26269890ff83SToomas Soome 	switch (action) {
26279890ff83SToomas Soome 	case 3: /* clear all tabs */
26289890ff83SToomas Soome 		tem->tvs_ntabs = 0;
26299890ff83SToomas Soome 		break;
26309890ff83SToomas Soome 	case 0: /* clr tab at cursor */
26319890ff83SToomas Soome 
26329890ff83SToomas Soome 		for (i = 0; i < tem->tvs_ntabs; i++) {
26339890ff83SToomas Soome 			if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
26349890ff83SToomas Soome 				tem->tvs_ntabs--;
26359890ff83SToomas Soome 				for (j = i; j < tem->tvs_ntabs; j++)
26369890ff83SToomas Soome 					tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
26379890ff83SToomas Soome 				return;
26389890ff83SToomas Soome 			}
26399890ff83SToomas Soome 		}
26409890ff83SToomas Soome 		break;
26419890ff83SToomas Soome 	}
26429890ff83SToomas Soome }
26439890ff83SToomas Soome 
26449890ff83SToomas Soome static void
tem_mv_cursor(struct tem_vt_state * tem,int row,int col)26459890ff83SToomas Soome tem_mv_cursor(struct tem_vt_state *tem, int row, int col)
26469890ff83SToomas Soome {
26479890ff83SToomas Soome 	/*
26489890ff83SToomas Soome 	 * Sanity check and bounds enforcement.  Out of bounds requests are
26499890ff83SToomas Soome 	 * clipped to the screen boundaries.  This seems to be what SPARC
26509890ff83SToomas Soome 	 * does.
26519890ff83SToomas Soome 	 */
26529890ff83SToomas Soome 	if (row < 0)
26539890ff83SToomas Soome 		row = 0;
26549890ff83SToomas Soome 	if (row >= tems.ts_c_dimension.height)
26559890ff83SToomas Soome 		row = tems.ts_c_dimension.height - 1;
26569890ff83SToomas Soome 	if (col < 0)
26579890ff83SToomas Soome 		col = 0;
2658*d863b4c1SToomas Soome 	if (col >= tems.ts_c_dimension.width) {
2659*d863b4c1SToomas Soome 		tem->tvs_stateflags |= TVS_WRAPPED;
26609890ff83SToomas Soome 		col = tems.ts_c_dimension.width - 1;
2661*d863b4c1SToomas Soome 	} else {
2662*d863b4c1SToomas Soome 		tem->tvs_stateflags &= ~TVS_WRAPPED;
2663*d863b4c1SToomas Soome 	}
26649890ff83SToomas Soome 
26659890ff83SToomas Soome 	tem_send_data(tem);
26669890ff83SToomas Soome 	tem->tvs_c_cursor.row = (screen_pos_t)row;
26679890ff83SToomas Soome 	tem->tvs_c_cursor.col = (screen_pos_t)col;
26689890ff83SToomas Soome 	tem_align_cursor(tem);
26699890ff83SToomas Soome }
26709890ff83SToomas Soome 
26719890ff83SToomas Soome /* ARGSUSED */
26729890ff83SToomas Soome static void
tem_reset_emulator(struct tem_vt_state * tem,bool init_color)2673ffd79eb6SToomas Soome tem_reset_emulator(struct tem_vt_state *tem, bool init_color)
26749890ff83SToomas Soome {
26759890ff83SToomas Soome 	int j;
26769890ff83SToomas Soome 
26779890ff83SToomas Soome 	tem->tvs_c_cursor.row = 0;
26789890ff83SToomas Soome 	tem->tvs_c_cursor.col = 0;
26799890ff83SToomas Soome 	tem->tvs_r_cursor.row = 0;
26809890ff83SToomas Soome 	tem->tvs_r_cursor.col = 0;
26819890ff83SToomas Soome 	tem->tvs_s_cursor.row = 0;
26829890ff83SToomas Soome 	tem->tvs_s_cursor.col = 0;
26839890ff83SToomas Soome 	tem->tvs_outindex = 0;
26849890ff83SToomas Soome 	tem->tvs_state = A_STATE_START;
2685ffd79eb6SToomas Soome 	tem->tvs_gotparam = false;
26869890ff83SToomas Soome 	tem->tvs_curparam = 0;
26879890ff83SToomas Soome 	tem->tvs_paramval = 0;
26889890ff83SToomas Soome 	tem->tvs_nscroll = 1;
26899890ff83SToomas Soome 
26909890ff83SToomas Soome 	if (init_color) {
26919890ff83SToomas Soome 		/* use initial settings */
2692fa9eb222SToomas Soome 		tem->tvs_alpha = 0xff;
26939890ff83SToomas Soome 		tem->tvs_fg_color = tems.ts_init_color.fg_color;
26949890ff83SToomas Soome 		tem->tvs_bg_color = tems.ts_init_color.bg_color;
26959890ff83SToomas Soome 		tem->tvs_flags = tems.ts_init_color.a_flags;
26969890ff83SToomas Soome 	}
26979890ff83SToomas Soome 
26989890ff83SToomas Soome 	/*
26999890ff83SToomas Soome 	 * set up the initial tab stops
27009890ff83SToomas Soome 	 */
27019890ff83SToomas Soome 	tem->tvs_ntabs = 0;
27029890ff83SToomas Soome 	for (j = 8; j < tems.ts_c_dimension.width; j += 8)
27039890ff83SToomas Soome 		tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
27049890ff83SToomas Soome 
27059890ff83SToomas Soome 	for (j = 0; j < TEM_MAXPARAMS; j++)
27069890ff83SToomas Soome 		tem->tvs_params[j] = 0;
27079890ff83SToomas Soome }
27089890ff83SToomas Soome 
27099890ff83SToomas Soome static void
tem_reset_display(struct tem_vt_state * tem,bool clear_txt,bool init_color)2710ffd79eb6SToomas Soome tem_reset_display(struct tem_vt_state *tem, bool clear_txt, bool init_color)
27119890ff83SToomas Soome {
27129890ff83SToomas Soome 	tem_reset_emulator(tem, init_color);
27139890ff83SToomas Soome 
27149890ff83SToomas Soome 	if (clear_txt) {
27159890ff83SToomas Soome 		if (tem->tvs_isactive)
27169890ff83SToomas Soome 			tem_callback_cursor(tem, VIS_HIDE_CURSOR);
27179890ff83SToomas Soome 
27189890ff83SToomas Soome 		tem_cls(tem);
27199890ff83SToomas Soome 
27209890ff83SToomas Soome 		if (tem->tvs_isactive)
27219890ff83SToomas Soome 			tem_callback_cursor(tem, VIS_DISPLAY_CURSOR);
27229890ff83SToomas Soome 	}
27239890ff83SToomas Soome }
27249890ff83SToomas Soome 
27259890ff83SToomas Soome static void
tem_shift(struct tem_vt_state * tem,int count,int direction)27269890ff83SToomas Soome tem_shift(struct tem_vt_state *tem, int count, int direction)
27279890ff83SToomas Soome {
27289890ff83SToomas Soome 	int rest_of_line;
27299890ff83SToomas Soome 
27309890ff83SToomas Soome 	rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
27319890ff83SToomas Soome 	if (count > rest_of_line)
27329890ff83SToomas Soome 		count = rest_of_line;
27339890ff83SToomas Soome 
27349890ff83SToomas Soome 	if (count <= 0)
27359890ff83SToomas Soome 		return;
27369890ff83SToomas Soome 
27379890ff83SToomas Soome 	switch (direction) {
27389890ff83SToomas Soome 	case TEM_SHIFT_LEFT:
27399890ff83SToomas Soome 		if (count < rest_of_line) {
27409890ff83SToomas Soome 			tem_copy_area(tem,
27419890ff83SToomas Soome 			    tem->tvs_c_cursor.col + count,
27429890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
27439890ff83SToomas Soome 			    tems.ts_c_dimension.width - 1,
27449890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
27459890ff83SToomas Soome 			    tem->tvs_c_cursor.col,
27469890ff83SToomas Soome 			    tem->tvs_c_cursor.row);
27479890ff83SToomas Soome 		}
27489890ff83SToomas Soome 
27499890ff83SToomas Soome 		tem_clear_chars(tem, count, tem->tvs_c_cursor.row,
27509890ff83SToomas Soome 		    (tems.ts_c_dimension.width - count));
27519890ff83SToomas Soome 		break;
27529890ff83SToomas Soome 	case TEM_SHIFT_RIGHT:
27539890ff83SToomas Soome 		if (count < rest_of_line) {
27549890ff83SToomas Soome 			tem_copy_area(tem,
27559890ff83SToomas Soome 			    tem->tvs_c_cursor.col,
27569890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
27579890ff83SToomas Soome 			    tems.ts_c_dimension.width - count - 1,
27589890ff83SToomas Soome 			    tem->tvs_c_cursor.row,
27599890ff83SToomas Soome 			    tem->tvs_c_cursor.col + count,
27609890ff83SToomas Soome 			    tem->tvs_c_cursor.row);
27619890ff83SToomas Soome 		}
27629890ff83SToomas Soome 
27639890ff83SToomas Soome 		tem_clear_chars(tem, count, tem->tvs_c_cursor.row,
27649890ff83SToomas Soome 		    tem->tvs_c_cursor.col);
27659890ff83SToomas Soome 		break;
27669890ff83SToomas Soome 	}
27679890ff83SToomas Soome }
27689890ff83SToomas Soome 
27699890ff83SToomas Soome static void
tem_text_cursor(struct tem_vt_state * tem,short action)27709890ff83SToomas Soome tem_text_cursor(struct tem_vt_state *tem, short action)
27719890ff83SToomas Soome {
27729890ff83SToomas Soome 	struct vis_conscursor	ca;
27739890ff83SToomas Soome 
27749890ff83SToomas Soome 	ca.row = tem->tvs_c_cursor.row;
27759890ff83SToomas Soome 	ca.col = tem->tvs_c_cursor.col;
27769890ff83SToomas Soome 	ca.action = action;
27779890ff83SToomas Soome 
27789890ff83SToomas Soome 	tems_cursor(&ca);
27799890ff83SToomas Soome 
27809890ff83SToomas Soome 	if (action == VIS_GET_CURSOR) {
27819890ff83SToomas Soome 		tem->tvs_c_cursor.row = ca.row;
27829890ff83SToomas Soome 		tem->tvs_c_cursor.col = ca.col;
27839890ff83SToomas Soome 	}
27849890ff83SToomas Soome }
27859890ff83SToomas Soome 
27869890ff83SToomas Soome static void
tem_pix_cursor(struct tem_vt_state * tem,short action)27879890ff83SToomas Soome tem_pix_cursor(struct tem_vt_state *tem, short action)
27889890ff83SToomas Soome {
27899890ff83SToomas Soome 	struct vis_conscursor	ca;
27909890ff83SToomas Soome 	text_color_t fg, bg;
27919890ff83SToomas Soome 	term_char_t c;
27929890ff83SToomas Soome 	text_attr_t attr;
27939890ff83SToomas Soome 
27949890ff83SToomas Soome 	ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height +
27959890ff83SToomas Soome 	    tems.ts_p_offset.y;
27969890ff83SToomas Soome 	ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width +
27979890ff83SToomas Soome 	    tems.ts_p_offset.x;
27989890ff83SToomas Soome 	ca.width = tems.ts_font.vf_width;
27999890ff83SToomas Soome 	ca.height = tems.ts_font.vf_height;
28009890ff83SToomas Soome 
28019890ff83SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
28029890ff83SToomas Soome 	    TEM_ATTR_REVERSE);
28039890ff83SToomas Soome 	c.tc_char = TEM_ATTR(attr);
28049890ff83SToomas Soome 
2805fa9eb222SToomas Soome 	tem_get_color(tem, &fg, &bg, &c);
2806fa9eb222SToomas Soome 	tem_set_color(&fg, &ca.fg_color);
2807fa9eb222SToomas Soome 	tem_set_color(&bg, &ca.bg_color);
28089890ff83SToomas Soome 
28099890ff83SToomas Soome 	ca.action = action;
28109890ff83SToomas Soome 
28119890ff83SToomas Soome 	tems_cursor(&ca);
28129890ff83SToomas Soome 
28139890ff83SToomas Soome 	if (action == VIS_GET_CURSOR) {
28149890ff83SToomas Soome 		tem->tvs_c_cursor.row = 0;
28159890ff83SToomas Soome 		tem->tvs_c_cursor.col = 0;
28169890ff83SToomas Soome 
28179890ff83SToomas Soome 		if (ca.row != 0) {
28189890ff83SToomas Soome 			tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) /
28199890ff83SToomas Soome 			    tems.ts_font.vf_height;
28209890ff83SToomas Soome 		}
28219890ff83SToomas Soome 		if (ca.col != 0) {
28229890ff83SToomas Soome 			tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) /
28239890ff83SToomas Soome 			    tems.ts_font.vf_width;
28249890ff83SToomas Soome 		}
28259890ff83SToomas Soome 	}
28269890ff83SToomas Soome }
28279890ff83SToomas Soome 
28289890ff83SToomas Soome static void
bit_to_pix32(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)28299890ff83SToomas Soome bit_to_pix32(struct tem_vt_state *tem,
2830fa9eb222SToomas Soome     tem_char_t c, text_color_t fg, text_color_t bg)
28319890ff83SToomas Soome {
2832fa9eb222SToomas Soome 	uint32_t *dest;
28339890ff83SToomas Soome 
28349890ff83SToomas Soome 	dest = (uint32_t *)tem->tvs_pix_data;
2835fa9eb222SToomas Soome 	font_bit_to_pix32(&tems.ts_font, dest, c, fg.n, bg.n);
28369890ff83SToomas Soome }
28379890ff83SToomas Soome 
28389890ff83SToomas Soome /*
28399890ff83SToomas Soome  * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
28409890ff83SToomas Soome  */
28419890ff83SToomas Soome static void
tem_get_attr(struct tem_vt_state * tem,text_color_t * fg,text_color_t * bg,text_attr_t * attr,uint8_t flag)28429890ff83SToomas Soome tem_get_attr(struct tem_vt_state *tem, text_color_t *fg,
28439890ff83SToomas Soome     text_color_t *bg, text_attr_t *attr, uint8_t flag)
28449890ff83SToomas Soome {
28459890ff83SToomas Soome 	if (tem->tvs_flags & flag) {
28469890ff83SToomas Soome 		*fg = tem->tvs_bg_color;
28479890ff83SToomas Soome 		*bg = tem->tvs_fg_color;
28489890ff83SToomas Soome 	} else {
28499890ff83SToomas Soome 		*fg = tem->tvs_fg_color;
28509890ff83SToomas Soome 		*bg = tem->tvs_bg_color;
28519890ff83SToomas Soome 	}
28529890ff83SToomas Soome 
2853fa9eb222SToomas Soome 	if (attr != NULL)
2854fa9eb222SToomas Soome 		*attr = tem->tvs_flags;
28559890ff83SToomas Soome }
28569890ff83SToomas Soome 
28579890ff83SToomas Soome static void
tem_get_color(struct tem_vt_state * tem,text_color_t * fg,text_color_t * bg,term_char_t * c)2858fa9eb222SToomas Soome tem_get_color(struct tem_vt_state *tem, text_color_t *fg, text_color_t *bg,
2859fa9eb222SToomas Soome     term_char_t *c)
28609890ff83SToomas Soome {
2861e0721d5aSToomas Soome 	bool bold_font;
2862e0721d5aSToomas Soome 
2863fa9eb222SToomas Soome 	*fg = c->tc_fg_color;
2864fa9eb222SToomas Soome 	*bg = c->tc_bg_color;
286531286541SToomas Soome 
2866e0721d5aSToomas Soome 	bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0;
2867e0721d5aSToomas Soome 
2868e0721d5aSToomas Soome 	/*
2869e0721d5aSToomas Soome 	 * If we have both normal and bold font components,
2870e0721d5aSToomas Soome 	 * we use bold font for TEM_ATTR_BOLD.
2871e0721d5aSToomas Soome 	 * The bright color is traditionally used with TEM_ATTR_BOLD,
2872e0721d5aSToomas Soome 	 * in case there is no bold font.
2873e0721d5aSToomas Soome 	 */
2874fa9eb222SToomas Soome 	if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG) &&
2875fa9eb222SToomas Soome 	    c->tc_fg_color.n < XLATE_NCOLORS) {
2876fa9eb222SToomas Soome 		if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_FG) ||
2877fa9eb222SToomas Soome 		    (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BOLD) && !bold_font))
2878fa9eb222SToomas Soome 			fg->n = brt_xlate[c->tc_fg_color.n];
2879a4e6b9b6SToomas Soome 		else
2880fa9eb222SToomas Soome 			fg->n = dim_xlate[c->tc_fg_color.n];
2881a4e6b9b6SToomas Soome 	}
28829890ff83SToomas Soome 
2883fa9eb222SToomas Soome 	if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG) &&
2884fa9eb222SToomas Soome 	    c->tc_bg_color.n < XLATE_NCOLORS) {
2885fa9eb222SToomas Soome 		if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_BG))
2886fa9eb222SToomas Soome 			bg->n = brt_xlate[c->tc_bg_color.n];
2887a4e6b9b6SToomas Soome 		else
2888fa9eb222SToomas Soome 			bg->n = dim_xlate[c->tc_bg_color.n];
2889fa9eb222SToomas Soome 	}
2890fa9eb222SToomas Soome 
2891fa9eb222SToomas Soome 	if (tems.ts_display_mode == VIS_TEXT)
2892fa9eb222SToomas Soome 		return;
2893fa9eb222SToomas Soome 
2894fa9eb222SToomas Soome 	/*
2895fa9eb222SToomas Soome 	 * Translate fg and bg to RGB colors.
2896fa9eb222SToomas Soome 	 */
2897fa9eb222SToomas Soome 	if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG)) {
2898fa9eb222SToomas Soome 		fg->n = rgb_to_color(&rgb_info,
2899fa9eb222SToomas Soome 		    fg->rgb.a, fg->rgb.r, fg->rgb.g, fg->rgb.b);
2900fa9eb222SToomas Soome 	} else {
2901fa9eb222SToomas Soome 		fg->n = rgb_color_map(&rgb_info, fg->n, tem->tvs_alpha);
2902fa9eb222SToomas Soome 	}
2903fa9eb222SToomas Soome 
2904fa9eb222SToomas Soome 	if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG)) {
2905fa9eb222SToomas Soome 		bg->n = rgb_to_color(&rgb_info,
2906fa9eb222SToomas Soome 		    bg->rgb.a, bg->rgb.r, bg->rgb.g, bg->rgb.b);
2907fa9eb222SToomas Soome 	} else {
2908fa9eb222SToomas Soome 		bg->n = rgb_color_map(&rgb_info, bg->n, tem->tvs_alpha);
2909fa9eb222SToomas Soome 	}
2910fa9eb222SToomas Soome }
2911fa9eb222SToomas Soome 
2912fa9eb222SToomas Soome static void
tem_set_color(text_color_t * t,color_t * c)2913fa9eb222SToomas Soome tem_set_color(text_color_t *t, color_t *c)
2914fa9eb222SToomas Soome {
2915fa9eb222SToomas Soome 	switch (tems.ts_pdepth) {
2916fa9eb222SToomas Soome 	case 4:
2917fa9eb222SToomas Soome 		c->four = t->n & 0xFF;
2918fa9eb222SToomas Soome 		break;
2919fa9eb222SToomas Soome 	default:
2920fa9eb222SToomas Soome 		/* gfx module is expecting all pixel data in 32-bit colors */
2921fa9eb222SToomas Soome 		*(uint32_t *)c = t->n;
2922fa9eb222SToomas Soome 		break;
2923a4e6b9b6SToomas Soome 	}
29249890ff83SToomas Soome }
29259890ff83SToomas Soome 
29269890ff83SToomas Soome void
tem_get_colors(tem_vt_state_t tem_arg,text_color_t * fg,text_color_t * bg)29279890ff83SToomas Soome tem_get_colors(tem_vt_state_t tem_arg, text_color_t *fg, text_color_t *bg)
29289890ff83SToomas Soome {
29299890ff83SToomas Soome 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
29309890ff83SToomas Soome 	text_attr_t attr;
29319890ff83SToomas Soome 	term_char_t c;
29329890ff83SToomas Soome 
29339890ff83SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
29349890ff83SToomas Soome 	    TEM_ATTR_REVERSE);
29359890ff83SToomas Soome 	c.tc_char = TEM_ATTR(attr);
2936fa9eb222SToomas Soome 	tem_get_color(tem, fg, bg, &c);
29379890ff83SToomas Soome }
29389890ff83SToomas Soome 
29399890ff83SToomas Soome /*
29409890ff83SToomas Soome  * Clear a rectangle of screen for pixel mode.
29419890ff83SToomas Soome  *
29429890ff83SToomas Soome  * arguments:
29439890ff83SToomas Soome  *    row:	start row#
29449890ff83SToomas Soome  *    nrows:	the number of rows to clear
29459890ff83SToomas Soome  *    offset_y:	the offset of height in pixels to begin clear
29469890ff83SToomas Soome  *    col:	start col#
29479890ff83SToomas Soome  *    ncols:	the number of cols to clear
29489890ff83SToomas Soome  *    offset_x:	the offset of width in pixels to begin clear
29499890ff83SToomas Soome  *    scroll_up: whether this function is called during sroll up,
29509890ff83SToomas Soome  *		 which is called only once.
29519890ff83SToomas Soome  */
29529890ff83SToomas Soome static void
tem_pix_cls_range(struct tem_vt_state * tem,screen_pos_t row,int nrows,int offset_y,screen_pos_t col,int ncols,int offset_x,bool sroll_up)29539890ff83SToomas Soome tem_pix_cls_range(struct tem_vt_state *tem,
29549890ff83SToomas Soome     screen_pos_t row, int nrows, int offset_y,
29559890ff83SToomas Soome     screen_pos_t col, int ncols, int offset_x,
2956ffd79eb6SToomas Soome     bool sroll_up)
29579890ff83SToomas Soome {
29589890ff83SToomas Soome 	struct vis_consdisplay da;
29599890ff83SToomas Soome 	int	i, j;
29609890ff83SToomas Soome 	int	row_add = 0;
29619890ff83SToomas Soome 	term_char_t c;
29629890ff83SToomas Soome 	text_attr_t attr;
29639890ff83SToomas Soome 
29649890ff83SToomas Soome 	if (sroll_up)
29659890ff83SToomas Soome 		row_add = tems.ts_c_dimension.height - 1;
29669890ff83SToomas Soome 
29679890ff83SToomas Soome 	da.width = tems.ts_font.vf_width;
29689890ff83SToomas Soome 	da.height = tems.ts_font.vf_height;
29699890ff83SToomas Soome 
29709890ff83SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
29719890ff83SToomas Soome 	    TEM_ATTR_SCREEN_REVERSE);
29729890ff83SToomas Soome 	/* Make sure we will not draw underlines */
29739890ff83SToomas Soome 	c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
29749890ff83SToomas Soome 
2975fa9eb222SToomas Soome 	tem_callback_bit2pix(tem, &c);
29769890ff83SToomas Soome 	da.data = (uint8_t *)tem->tvs_pix_data;
29779890ff83SToomas Soome 
29789890ff83SToomas Soome 	for (i = 0; i < nrows; i++, row++) {
29799890ff83SToomas Soome 		da.row = (row + row_add) * da.height + offset_y;
29809890ff83SToomas Soome 		da.col = col * da.width + offset_x;
29819890ff83SToomas Soome 		for (j = 0; j < ncols; j++) {
29829890ff83SToomas Soome 			tems_display(&da);
29839890ff83SToomas Soome 			da.col += da.width;
29849890ff83SToomas Soome 		}
29859890ff83SToomas Soome 	}
29869890ff83SToomas Soome }
29879890ff83SToomas Soome 
29889890ff83SToomas Soome /*
29899890ff83SToomas Soome  * virtual screen operations
29909890ff83SToomas Soome  */
29919890ff83SToomas Soome static void
tem_virtual_display(struct tem_vt_state * tem,term_char_t * string,size_t count,screen_pos_t row,screen_pos_t col)29929890ff83SToomas Soome tem_virtual_display(struct tem_vt_state *tem, term_char_t *string,
29939890ff83SToomas Soome     size_t count, screen_pos_t row, screen_pos_t col)
29949890ff83SToomas Soome {
29959890ff83SToomas Soome 	size_t i, width;
29969890ff83SToomas Soome 	term_char_t *addr;
29979890ff83SToomas Soome 
29989890ff83SToomas Soome 	if (tem->tvs_screen_buf == NULL)
29999890ff83SToomas Soome 		return;
30009890ff83SToomas Soome 
30019890ff83SToomas Soome 	if (row < 0 || row >= tems.ts_c_dimension.height ||
30029890ff83SToomas Soome 	    col < 0 || col >= tems.ts_c_dimension.width ||
30039890ff83SToomas Soome 	    col + count > (size_t)tems.ts_c_dimension.width)
30049890ff83SToomas Soome 		return;
30059890ff83SToomas Soome 
30069890ff83SToomas Soome 	width = tems.ts_c_dimension.width;
3007726d8a6eSToomas Soome 	addr = tem->tvs_screen_buf + (row * width + col);
30089890ff83SToomas Soome 	for (i = 0; i < count; i++) {
30099890ff83SToomas Soome 		*addr++ = string[i];
30109890ff83SToomas Soome 	}
30119890ff83SToomas Soome }
30129890ff83SToomas Soome 
30139890ff83SToomas Soome static void
tem_virtual_cls(struct tem_vt_state * tem,size_t count,screen_pos_t row,screen_pos_t col)30149890ff83SToomas Soome tem_virtual_cls(struct tem_vt_state *tem, size_t count,
30159890ff83SToomas Soome     screen_pos_t row, screen_pos_t col)
30169890ff83SToomas Soome {
30179890ff83SToomas Soome 	term_char_t c;
3018fa9eb222SToomas Soome 	text_attr_t attr;
30199890ff83SToomas Soome 
3020fa9eb222SToomas Soome 	tem_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
3021fa9eb222SToomas Soome 	    TEM_ATTR_SCREEN_REVERSE);
3022fa9eb222SToomas Soome 	/* Make sure we will not draw underlines */
3023fa9eb222SToomas Soome 	c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
30249890ff83SToomas Soome 
30259890ff83SToomas Soome 	while (count > 0) {
30269890ff83SToomas Soome 		tem_virtual_display(tem, &c, 1, row, col);
30279890ff83SToomas Soome 		col++;
30289890ff83SToomas Soome 		count--;
30299890ff83SToomas Soome 	}
30309890ff83SToomas Soome }
3031