xref: /onnv-gate/usr/src/uts/common/io/tem_safe.c (revision 3994:4fafdadace7c)
11253Slq150181 /*
21253Slq150181  * CDDL HEADER START
31253Slq150181  *
41253Slq150181  * The contents of this file are subject to the terms of the
51253Slq150181  * Common Development and Distribution License (the "License").
61253Slq150181  * You may not use this file except in compliance with the License.
71253Slq150181  *
81253Slq150181  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91253Slq150181  * or http://www.opensolaris.org/os/licensing.
101253Slq150181  * See the License for the specific language governing permissions
111253Slq150181  * and limitations under the License.
121253Slq150181  *
131253Slq150181  * When distributing Covered Code, include this CDDL HEADER in each
141253Slq150181  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151253Slq150181  * If applicable, add the following below this CDDL HEADER, with the
161253Slq150181  * fields enclosed by brackets "[]" replaced with your own identifying
171253Slq150181  * information: Portions Copyright [yyyy] [name of copyright owner]
181253Slq150181  *
191253Slq150181  * CDDL HEADER END
201253Slq150181  */
211253Slq150181 
221253Slq150181 /*
23*3994Slq150181  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
241253Slq150181  * Use is subject to license terms.
251253Slq150181  */
261253Slq150181 
271253Slq150181 #pragma ident	"%Z%%M%	%I%	%E% SMI"
281253Slq150181 
291253Slq150181 /*
301253Slq150181  * Polled I/O safe ANSI terminal emulator module;
311253Slq150181  * Supporting TERM types 'sun' and 'sun-color, parsing
321253Slq150181  * ANSI x3.64 escape sequences, and the like.  (See wscons(7d)
331253Slq150181  * for more information).
341253Slq150181  *
351253Slq150181  * IMPORTANT:
361253Slq150181  *
371253Slq150181  *   The functions in this file *must* be able to function in
381253Slq150181  *   standalone mode, ie. on a quiesced system.   In that state,
391253Slq150181  *   access is single threaded, only one CPU is running.
401253Slq150181  *   System services are NOT available.
411253Slq150181  *
421253Slq150181  * The following restrictions pertain to every function
431253Slq150181  * in this file:
441253Slq150181  *
451253Slq150181  *     - CANNOT use the DDI or LDI interfaces
461253Slq150181  *     - CANNOT call system services
471253Slq150181  *     - CANNOT use mutexes
481253Slq150181  *     - CANNOT wait for interrupts
491253Slq150181  *     - CANNOT allocate memory
501253Slq150181  *
511253Slq150181  */
521253Slq150181 
531253Slq150181 #include <sys/types.h>
541253Slq150181 #include <sys/ascii.h>
551253Slq150181 #include <sys/visual_io.h>
561253Slq150181 #include <sys/font.h>
571253Slq150181 #include <sys/tem.h>
581253Slq150181 #include <sys/tem_impl.h>
591253Slq150181 #include <sys/ksynch.h>
601253Slq150181 #include <sys/sysmacros.h>
611253Slq150181 #include <sys/mutex.h>
621253Slq150181 
631253Slq150181 static void	tem_display(struct tem *,
641253Slq150181 			struct vis_consdisplay *,
651253Slq150181 			cred_t *, enum called_from);
661253Slq150181 static void	tem_cursor(struct tem *,
671253Slq150181 			struct vis_conscursor *,
681253Slq150181 			cred_t *, enum called_from);
691253Slq150181 static void	tem_control(struct tem *, uchar_t,
701253Slq150181 			cred_t *, enum called_from);
711253Slq150181 static void	tem_setparam(struct tem *, int, int);
721253Slq150181 static void	tem_selgraph(struct tem *);
731253Slq150181 static void	tem_chkparam(struct tem *, uchar_t,
741253Slq150181 			cred_t *, enum called_from);
751253Slq150181 static void	tem_getparams(struct tem *, uchar_t,
761253Slq150181 			cred_t *, enum called_from);
771253Slq150181 static void	tem_outch(struct tem *, uchar_t,
781253Slq150181 			cred_t *, enum called_from);
791253Slq150181 static void	tem_parse(struct tem *, uchar_t,
801253Slq150181 			cred_t *, enum called_from);
811253Slq150181 
821253Slq150181 static void	tem_new_line(struct tem *,
831253Slq150181 			cred_t *, enum called_from);
841253Slq150181 static void	tem_cr(struct tem *);
851253Slq150181 static void	tem_lf(struct tem *,
861253Slq150181 			cred_t *, enum called_from);
871253Slq150181 static void	tem_send_data(struct tem *, cred_t *,
881253Slq150181 			enum called_from);
891253Slq150181 static void	tem_cls(struct tem *,
901253Slq150181 			cred_t *, enum called_from);
911253Slq150181 static void	tem_tab(struct tem *,
921253Slq150181 			cred_t *, enum called_from);
931253Slq150181 static void	tem_back_tab(struct tem *,
941253Slq150181 			cred_t *, enum called_from);
951253Slq150181 static void	tem_clear_tabs(struct tem *, int);
961253Slq150181 static void	tem_set_tab(struct tem *);
971253Slq150181 static void	tem_mv_cursor(struct tem *, int, int,
981253Slq150181 			cred_t *, enum called_from);
991253Slq150181 static void	tem_shift(struct tem *, int, int,
1001253Slq150181 			cred_t *, enum called_from);
1011253Slq150181 static void	tem_scroll(struct tem *, int, int,
1021253Slq150181 			int, int, cred_t *, enum called_from);
1031253Slq150181 static void	tem_clear_chars(struct tem *tem,
1041253Slq150181 			int count, screen_pos_t row, screen_pos_t col,
1051253Slq150181 			cred_t *credp, enum called_from called_from);
1061253Slq150181 static void	tem_copy_area(struct tem *tem,
1071253Slq150181 			screen_pos_t s_col, screen_pos_t s_row,
1081253Slq150181 			screen_pos_t e_col, screen_pos_t e_row,
1091253Slq150181 			screen_pos_t t_col, screen_pos_t t_row,
1101253Slq150181 			cred_t *credp, enum called_from called_from);
1111253Slq150181 static void	tem_image_display(struct tem *, uchar_t *,
1121253Slq150181 			int, int, screen_pos_t, screen_pos_t,
1131253Slq150181 			cred_t *, enum called_from);
1141253Slq150181 static void	tem_bell(struct tem *tem,
1151253Slq150181 			enum called_from called_from);
1161253Slq150181 static void	tem_get_color(struct tem *tem,
1171253Slq150181 			text_color_t *fg, text_color_t *bg);
1181253Slq150181 static void	tem_pix_clear_prom_output(struct tem *tem,
1191253Slq150181 			cred_t *credp, enum called_from called_from);
1201253Slq150181 
1211253Slq150181 /* BEGIN CSTYLED */
1221253Slq150181 /*                                      Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
1231253Slq150181 static text_color_t fg_dim_xlate[] = {  1,  5,  3,  7,  2,  6,  4,  8 };
1241253Slq150181 static text_color_t fg_brt_xlate[] = {  9, 13, 11, 15, 10, 14, 12,  0 };
1251253Slq150181 static text_color_t bg_xlate[] = {      1,  5,  3,  7,  2,  6,  4,  0 };
1261253Slq150181 /* END CSTYLED */
1271253Slq150181 
1281253Slq150181 
1291253Slq150181 text_cmap_t cmap4_to_24 = {
1301253Slq150181 /* BEGIN CSTYLED */
1311253Slq150181 /* 0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
1321253Slq150181   Wh+  Bk   Bl   Gr   Cy   Rd   Mg   Br   Wh   Bk+  Bl+  Gr+  Cy+  Rd+  Mg+  Yw */
1331253Slq150181   0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
1341253Slq150181   0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
1351253Slq150181   0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
1361253Slq150181 /* END CSTYLED */
1371253Slq150181 };
1381253Slq150181 
1391253Slq150181 #define	PIX4TO32(pix4) (pixel32_t)(  \
1401253Slq150181     cmap4_to_24.red[pix4] << 16 |  \
1411253Slq150181     cmap4_to_24.green[pix4] << 8 | \
1421253Slq150181     cmap4_to_24.blue[pix4])
1431253Slq150181 
1441253Slq150181 /*
1451253Slq150181  * Fonts are statically linked with this module. At some point an
1461253Slq150181  * RFE might be desireable to allow dynamic font loading.  The
1471253Slq150181  * original intention to facilitate dynamic fonts can be seen
1481253Slq150181  * by examining the data structures and set_font().  As much of
1491253Slq150181  * the original code is retained but modified to be suited to
1501253Slq150181  * traversing a list of static fonts.
1511253Slq150181  */
1521253Slq150181 extern struct fontlist fonts[];
1531253Slq150181 
1541253Slq150181 #define	DEFAULT_FONT_DATA font_data_12x22
1551253Slq150181 
1561253Slq150181 extern bitmap_data_t font_data_12x22;
1571253Slq150181 extern bitmap_data_t font_data_7x14;
1581253Slq150181 extern bitmap_data_t font_data_6x10;
1591253Slq150181 /*
1601253Slq150181  * Must be sorted by font size in descending order
1611253Slq150181  */
1621253Slq150181 struct fontlist fonts[] = {
1631253Slq150181 	{  &font_data_12x22,	NULL  },
1641253Slq150181 	{  &font_data_7x14,	NULL  },
1651253Slq150181 	{  &font_data_6x10,	NULL  },
1661253Slq150181 	{  NULL, NULL  }
1671253Slq150181 };
1681253Slq150181 
1691253Slq150181 #define	INVERSE(ch) (ch ^ 0xff)
1701253Slq150181 
1711253Slq150181 #define	BIT_TO_PIX(tem, c, fg, bg)	{				\
1721253Slq150181 	ASSERT((tem)->state->in_fp.f_bit2pix != NULL); 			\
1731253Slq150181 	(void) (*(tem)->state->in_fp.f_bit2pix)((tem), (c), (fg), (bg));\
1741253Slq150181 }
1751253Slq150181 
1761253Slq150181 void
1771253Slq150181 tem_check_first_time(
1781253Slq150181     struct tem *tem,
1791253Slq150181     cred_t *credp,
1801253Slq150181     enum called_from called_from)
1811253Slq150181 {
1821253Slq150181 	static int first_time = 1;
1831253Slq150181 
1841253Slq150181 	/*
1851253Slq150181 	 * Realign the console cursor. We did this in tem_init().
1861253Slq150181 	 * However, drivers in the console stream may emit additional
1871253Slq150181 	 * messages before we are ready. This causes text overwrite
1881253Slq150181 	 * on the screen. This is a workaround.
1891253Slq150181 	 */
1901253Slq150181 	if (first_time && tem->state->display_mode == VIS_TEXT) {
1911253Slq150181 		tem_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
1921253Slq150181 		tem_align_cursor(tem);
1931253Slq150181 	}
1941253Slq150181 	first_time = 0;
1951253Slq150181 
1961253Slq150181 }
1971253Slq150181 
1981253Slq150181 /*
1991253Slq150181  * This entry point handles output requests from restricted contexts like
2001253Slq150181  * kmdb, where services like mutexes are not available. This function
2011253Slq150181  * is entered when OBP or when a kernel debugger (such as kmdb)
2021253Slq150181  * are generating console output.  In those cases, power management
2031253Slq150181  * concerns are handled by the abort sequence initiation (ie. when
2041253Slq150181  * the user hits L1+A or the equivalent to enter OBP or the debugger.).
2051253Slq150181  * It is also entered when the kernel is panicing.
2061253Slq150181  */
2071253Slq150181 void
2081253Slq150181 tem_polled_write(
2091253Slq150181     struct tem *tem,
2101253Slq150181     uchar_t *buf,
2111253Slq150181     int len)
2121253Slq150181 {
2131253Slq150181 
2141253Slq150181 	ASSERT(tem->hdl != NULL);
2151253Slq150181 
2161253Slq150181 	tem_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
2171253Slq150181 	tem_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
2181253Slq150181 }
2191253Slq150181 
2201253Slq150181 
2211253Slq150181 /*
2221253Slq150181  * This is the main entry point into the terminal emulator.
2231253Slq150181  *
2241253Slq150181  * For each data message coming downstream, ANSI assumes that it is composed
2251253Slq150181  * of ASCII characters, which are treated as a byte-stream input to the
2261253Slq150181  * parsing state machine. All data is parsed immediately -- there is
2271253Slq150181  * no enqueing.
2281253Slq150181  */
2291253Slq150181 void
2301253Slq150181 tem_terminal_emulate(
2311253Slq150181     struct tem *tem,
2321253Slq150181     uchar_t *buf,
2331253Slq150181     int len,
2341253Slq150181     cred_t *credp,
2351253Slq150181     enum called_from called_from)
2361253Slq150181 {
2371253Slq150181 	struct tem_state	*tems = tem->state;
2381253Slq150181 
2391253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
2401253Slq150181 	    MUTEX_HELD(&tem->lock));
2411253Slq150181 
2421253Slq150181 	(*tems->in_fp.f_cursor)
2431253Slq150181 	    (tem, VIS_HIDE_CURSOR, credp, called_from);
2441253Slq150181 
2451253Slq150181 	for (; len > 0; len--, buf++) {
2461253Slq150181 		tem_parse(tem, *buf, credp, called_from);
2471253Slq150181 	}
2481253Slq150181 
2491253Slq150181 	/*
2501253Slq150181 	 * Send the data we just got to the framebuffer.
2511253Slq150181 	 */
2521253Slq150181 	tem_send_data(tem, credp, called_from);
2531253Slq150181 
2541253Slq150181 	(*tems->in_fp.f_cursor)
2551253Slq150181 	    (tem, VIS_DISPLAY_CURSOR, credp, called_from);
2561253Slq150181 }
2571253Slq150181 
2581253Slq150181 /*
2591253Slq150181  * Display an rectangular image on the frame buffer using the
2601253Slq150181  * mechanism appropriate for the system state being called
2611253Slq150181  * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
2621253Slq150181  */
2631253Slq150181 static void
2641253Slq150181 tem_display(
2651253Slq150181 	struct tem *tem,
2661253Slq150181 	struct vis_consdisplay *pda,
2671253Slq150181 	cred_t *credp,
2681253Slq150181 	enum called_from called_from)
2691253Slq150181 {
2701253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
2711253Slq150181 		tem->fb_polledio->display(tem->fb_polledio->arg, pda);
2721253Slq150181 	else
2731253Slq150181 		tem_display_layered(tem, pda, credp);
2741253Slq150181 }
2751253Slq150181 
2761253Slq150181 /*
2771253Slq150181  * Copy a rectangle from one location to another on the frame buffer
2781253Slq150181  * using the mechanism appropriate for the system state being called
2791253Slq150181  * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
2801253Slq150181  */
2811253Slq150181 void
2821253Slq150181 tem_copy(
2831253Slq150181 	struct tem *tem,
2841253Slq150181 	struct vis_conscopy *pca,
2851253Slq150181 	cred_t *credp,
2861253Slq150181 	enum called_from called_from)
2871253Slq150181 {
2881253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
2891253Slq150181 		tem->fb_polledio->copy(tem->fb_polledio->arg, pca);
2901253Slq150181 	else
2911253Slq150181 		tem_copy_layered(tem, pca, credp);
2921253Slq150181 }
2931253Slq150181 
2941253Slq150181 /*
2951253Slq150181  * Display or hide a rectangular block text cursor of a specificsize
2961253Slq150181  * at a specific location on frame buffer* using the mechanism
2971253Slq150181  * appropriate for the system state being called from, quisced or
2981253Slq150181  * normal (ie. use polled I/O vs. layered ioctls).
2991253Slq150181  */
3001253Slq150181 static void
3011253Slq150181 tem_cursor(
3021253Slq150181 	struct tem *tem,
3031253Slq150181 	struct vis_conscursor *pca,
3041253Slq150181 	cred_t *credp,
3051253Slq150181 	enum called_from called_from)
3061253Slq150181 {
3071253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
3081253Slq150181 		tem->fb_polledio->cursor(tem->fb_polledio->arg, pca);
3091253Slq150181 	else
3101253Slq150181 		tem_cursor_layered(tem, pca, credp);
3111253Slq150181 }
3121253Slq150181 
3131253Slq150181 /*
3141253Slq150181  * send the appropriate control message or set state based on the
3151253Slq150181  * value of the control character ch
3161253Slq150181  */
3171253Slq150181 
3181253Slq150181 static void
3191253Slq150181 tem_control(
3201253Slq150181 	struct tem *tem,
3211253Slq150181 	uchar_t ch,
3221253Slq150181 	cred_t *credp,
3231253Slq150181 	enum called_from called_from)
3241253Slq150181 {
3251253Slq150181 	struct tem_state	*tems = tem->state;
3261253Slq150181 
3271253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
3281253Slq150181 	    MUTEX_HELD(&tem->lock));
3291253Slq150181 
3301253Slq150181 	tems->a_state = A_STATE_START;
3311253Slq150181 	switch (ch) {
3321253Slq150181 	case A_BEL:
3331253Slq150181 		tem_bell(tem, called_from);
3341253Slq150181 		break;
3351253Slq150181 
3361253Slq150181 	case A_BS:
3371253Slq150181 		tem_mv_cursor(tem,
3381253Slq150181 		    tems->a_c_cursor.row,
3391253Slq150181 		    tems->a_c_cursor.col - 1,
3401253Slq150181 		    credp, called_from);
3411253Slq150181 		break;
3421253Slq150181 
3431253Slq150181 	case A_HT:
3441253Slq150181 		tem_tab(tem, credp, called_from);
3451253Slq150181 		break;
3461253Slq150181 
3471253Slq150181 	case A_NL:
3481253Slq150181 		/*
3491253Slq150181 		 * tem_send_data(tem, credp, called_from);
3501253Slq150181 		 * tem_new_line(tem, credp, called_from);
3511253Slq150181 		 * break;
3521253Slq150181 		 */
3531253Slq150181 
3541253Slq150181 	case A_VT:
3551253Slq150181 		tem_send_data(tem, credp, called_from);
3561253Slq150181 		tem_lf(tem, credp, called_from);
3571253Slq150181 		break;
3581253Slq150181 
3591253Slq150181 	case A_FF:
3601253Slq150181 		tem_send_data(tem, credp, called_from);
3611253Slq150181 		tem_cls(tem, credp, called_from);
3621253Slq150181 		break;
3631253Slq150181 
3641253Slq150181 	case A_CR:
3651253Slq150181 		tem_send_data(tem, credp, called_from);
3661253Slq150181 		tem_cr(tem);
3671253Slq150181 		break;
3681253Slq150181 
3691253Slq150181 	case A_ESC:
3701253Slq150181 		tems->a_state = A_STATE_ESC;
3711253Slq150181 		break;
3721253Slq150181 
3731253Slq150181 	case A_CSI:
3741253Slq150181 		{
3751253Slq150181 			int i;
3761253Slq150181 			tems->a_curparam = 0;
3771253Slq150181 			tems->a_paramval = 0;
3781253Slq150181 			tems->a_gotparam = B_FALSE;
3791253Slq150181 			/* clear the parameters */
3801253Slq150181 			for (i = 0; i < TEM_MAXPARAMS; i++)
3811253Slq150181 				tems->a_params[i] = -1;
3821253Slq150181 			tems->a_state = A_STATE_CSI;
3831253Slq150181 		}
3841253Slq150181 		break;
3851253Slq150181 
3861253Slq150181 	case A_GS:
3871253Slq150181 		tem_back_tab(tem, credp, called_from);
3881253Slq150181 		break;
3891253Slq150181 
3901253Slq150181 	default:
3911253Slq150181 		break;
3921253Slq150181 	}
3931253Slq150181 }
3941253Slq150181 
3951253Slq150181 
3961253Slq150181 /*
3971253Slq150181  * if parameters [0..count - 1] are not set, set them to the value
3981253Slq150181  * of newparam.
3991253Slq150181  */
4001253Slq150181 
4011253Slq150181 static void
4021253Slq150181 tem_setparam(struct tem *tem, int count, int newparam)
4031253Slq150181 {
4041253Slq150181 	int i;
4051253Slq150181 
4061253Slq150181 	for (i = 0; i < count; i++) {
4071253Slq150181 		if (tem->state->a_params[i] == -1)
4081253Slq150181 			tem->state->a_params[i] = newparam;
4091253Slq150181 	}
4101253Slq150181 }
4111253Slq150181 
4121253Slq150181 
4131253Slq150181 /*
4141253Slq150181  * select graphics mode based on the param vals stored in a_params
4151253Slq150181  */
4161253Slq150181 static void
4171253Slq150181 tem_selgraph(struct tem *tem)
4181253Slq150181 {
4191253Slq150181 	struct tem_state *tems = tem->state;
4201253Slq150181 	int curparam;
4211253Slq150181 	int count = 0;
4221253Slq150181 	int param;
4231253Slq150181 
4241253Slq150181 	curparam = tems->a_curparam;
4251253Slq150181 	do {
4261253Slq150181 		param = tems->a_params[count];
4271253Slq150181 
4281253Slq150181 		switch (param) {
4291253Slq150181 		case -1:
4301253Slq150181 		case 0:
4311253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
4321253Slq150181 				tems->a_flags |= TEM_ATTR_REVERSE;
4331253Slq150181 			} else {
4341253Slq150181 				tems->a_flags &= ~TEM_ATTR_REVERSE;
4351253Slq150181 			}
436*3994Slq150181 			tems->a_flags = tem->init_color.a_flags;
437*3994Slq150181 			tems->fg_color = tem->init_color.fg_color;
438*3994Slq150181 			tems->bg_color = tem->init_color.bg_color;
4391253Slq150181 			break;
4401253Slq150181 
4411253Slq150181 		case 1: /* Bold Intense */
4421253Slq150181 			tems->a_flags |= TEM_ATTR_BOLD;
4431253Slq150181 			break;
4441253Slq150181 
445*3994Slq150181 		case 2: /* Faint Intense */
446*3994Slq150181 			tems->a_flags &= ~TEM_ATTR_BOLD;
447*3994Slq150181 			break;
448*3994Slq150181 
4491253Slq150181 		case 5: /* Blink */
4501253Slq150181 			tems->a_flags |= TEM_ATTR_BLINK;
4511253Slq150181 			break;
4521253Slq150181 
4531253Slq150181 		case 7: /* Reverse video */
4541253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
4551253Slq150181 				tems->a_flags &= ~TEM_ATTR_REVERSE;
4561253Slq150181 			} else {
4571253Slq150181 				tems->a_flags |= TEM_ATTR_REVERSE;
4581253Slq150181 			}
4591253Slq150181 			break;
4601253Slq150181 
4611253Slq150181 		case 30: /* black	(grey) 		foreground */
4621253Slq150181 		case 31: /* red		(light red) 	foreground */
4631253Slq150181 		case 32: /* green	(light green) 	foreground */
4641253Slq150181 		case 33: /* brown	(yellow) 	foreground */
4651253Slq150181 		case 34: /* blue	(light blue) 	foreground */
4661253Slq150181 		case 35: /* magenta	(light magenta) foreground */
4671253Slq150181 		case 36: /* cyan	(light cyan) 	foreground */
4681253Slq150181 		case 37: /* white	(bright white) 	foreground */
4691253Slq150181 			tems->fg_color = param - 30;
4701253Slq150181 			break;
4711253Slq150181 
4721253Slq150181 		case 40: /* black	(grey) 		background */
4731253Slq150181 		case 41: /* red		(light red) 	background */
4741253Slq150181 		case 42: /* green	(light green) 	background */
4751253Slq150181 		case 43: /* brown	(yellow) 	background */
4761253Slq150181 		case 44: /* blue	(light blue) 	background */
4771253Slq150181 		case 45: /* magenta	(light magenta) background */
4781253Slq150181 		case 46: /* cyan	(light cyan) 	background */
4791253Slq150181 		case 47: /* white	(bright white) 	background */
4801253Slq150181 			tems->bg_color = param - 40;
4811253Slq150181 			break;
4821253Slq150181 
4831253Slq150181 		default:
4841253Slq150181 			break;
4851253Slq150181 		}
4861253Slq150181 		count++;
4871253Slq150181 		curparam--;
4881253Slq150181 
4891253Slq150181 	} while (curparam > 0);
4901253Slq150181 
4911253Slq150181 
4921253Slq150181 	tems->a_state = A_STATE_START;
4931253Slq150181 }
4941253Slq150181 
4951253Slq150181 /*
4961253Slq150181  * perform the appropriate action for the escape sequence
4971253Slq150181  *
4981253Slq150181  * General rule:  This code does not validate the arguments passed.
4991253Slq150181  *                It assumes that the next lower level will do so.
5001253Slq150181  */
5011253Slq150181 static void
5021253Slq150181 tem_chkparam(
5031253Slq150181 	struct tem *tem,
5041253Slq150181 	uchar_t ch,
5051253Slq150181 	cred_t *credp,
5061253Slq150181 	enum called_from called_from)
5071253Slq150181 {
5081253Slq150181 	struct tem_state *tems = tem->state;
5091253Slq150181 	int	i;
5101253Slq150181 	int	row;
5111253Slq150181 	int	col;
5121253Slq150181 
5131253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
5141253Slq150181 	    MUTEX_HELD(&tem->lock));
5151253Slq150181 
5161253Slq150181 	row = tems->a_c_cursor.row;
5171253Slq150181 	col = tems->a_c_cursor.col;
5181253Slq150181 
5191253Slq150181 	switch (ch) {
5201253Slq150181 
5211253Slq150181 	case 'm': /* select terminal graphics mode */
5221253Slq150181 		tem_send_data(tem, credp, called_from);
5231253Slq150181 		tem_selgraph(tem);
5241253Slq150181 		break;
5251253Slq150181 
5261253Slq150181 	case '@':		/* insert char */
5271253Slq150181 		tem_setparam(tem, 1, 1);
5281253Slq150181 		tem_shift(tem, tems->a_params[0], TEM_SHIFT_RIGHT,
5291253Slq150181 		    credp, called_from);
5301253Slq150181 		break;
5311253Slq150181 
5321253Slq150181 	case 'A':		/* cursor up */
5331253Slq150181 		tem_setparam(tem, 1, 1);
5341253Slq150181 		tem_mv_cursor(tem, row - tems->a_params[0], col,
5351253Slq150181 		    credp, called_from);
5361253Slq150181 		break;
5371253Slq150181 
5381253Slq150181 	case 'd':		/* VPA - vertical position absolute */
5391253Slq150181 		tem_setparam(tem, 1, 1);
5401253Slq150181 		tem_mv_cursor(tem, tems->a_params[0] - 1, col,
5411253Slq150181 		    credp, called_from);
5421253Slq150181 		break;
5431253Slq150181 
5441253Slq150181 	case 'e':		/* VPR - vertical position relative */
5451253Slq150181 	case 'B':		/* cursor down */
5461253Slq150181 		tem_setparam(tem, 1, 1);
5471253Slq150181 		tem_mv_cursor(tem, row + tems->a_params[0], col,
5481253Slq150181 		    credp, called_from);
5491253Slq150181 		break;
5501253Slq150181 
5511253Slq150181 	case 'a':		/* HPR - horizontal position relative */
5521253Slq150181 	case 'C':		/* cursor right */
5531253Slq150181 		tem_setparam(tem, 1, 1);
5541253Slq150181 		tem_mv_cursor(tem, row, col + tems->a_params[0],
5551253Slq150181 		    credp, called_from);
5561253Slq150181 		break;
5571253Slq150181 
5581253Slq150181 	case '`':		/* HPA - horizontal position absolute */
5591253Slq150181 		tem_setparam(tem, 1, 1);
5601253Slq150181 		tem_mv_cursor(tem, row, tems->a_params[0] - 1,
5611253Slq150181 		    credp, called_from);
5621253Slq150181 		break;
5631253Slq150181 
5641253Slq150181 	case 'D':		/* cursor left */
5651253Slq150181 		tem_setparam(tem, 1, 1);
5661253Slq150181 		tem_mv_cursor(tem, row, col - tems->a_params[0],
5671253Slq150181 		    credp, called_from);
5681253Slq150181 		break;
5691253Slq150181 
5701253Slq150181 	case 'E':		/* CNL cursor next line */
5711253Slq150181 		tem_setparam(tem, 1, 1);
5721253Slq150181 		tem_mv_cursor(tem, row + tems->a_params[0], 0,
5731253Slq150181 		    credp, called_from);
5741253Slq150181 		break;
5751253Slq150181 
5761253Slq150181 	case 'F':		/* CPL cursor previous line */
5771253Slq150181 		tem_setparam(tem, 1, 1);
5781253Slq150181 		tem_mv_cursor(tem, row - tems->a_params[0], 0,
5791253Slq150181 		    credp, called_from);
5801253Slq150181 		break;
5811253Slq150181 
5821253Slq150181 	case 'G':		/* cursor horizontal position */
5831253Slq150181 		tem_setparam(tem, 1, 1);
5841253Slq150181 		tem_mv_cursor(tem, row, tems->a_params[0] - 1,
5851253Slq150181 		    credp, called_from);
5861253Slq150181 		break;
5871253Slq150181 
5881253Slq150181 	case 'g':		/* clear tabs */
5891253Slq150181 		tem_setparam(tem, 1, 0);
5901253Slq150181 		tem_clear_tabs(tem, tems->a_params[0]);
5911253Slq150181 		break;
5921253Slq150181 
5931253Slq150181 	case 'f':		/* HVP Horizontal and Vertical Position */
5941253Slq150181 	case 'H':		/* CUP position cursor */
5951253Slq150181 		tem_setparam(tem, 2, 1);
5961253Slq150181 		tem_mv_cursor(tem,
5971253Slq150181 		    tems->a_params[0] - 1,
5981253Slq150181 		    tems->a_params[1] - 1,
5991253Slq150181 		    credp, called_from);
6001253Slq150181 		break;
6011253Slq150181 
6021253Slq150181 	case 'I':		/* CHT - Cursor Horizontal Tab */
6031253Slq150181 		/* Not implemented */
6041253Slq150181 		break;
6051253Slq150181 
6061253Slq150181 	case 'J':		/* ED - Erase in Display */
6071253Slq150181 		tem_send_data(tem, credp, called_from);
6081253Slq150181 		tem_setparam(tem, 1, 0);
6091253Slq150181 		switch (tems->a_params[0]) {
6101253Slq150181 		case 0:
6111253Slq150181 			/* erase cursor to end of screen */
6121253Slq150181 			/* FIRST erase cursor to end of line */
6131253Slq150181 			tem_clear_chars(tem,
6141253Slq150181 				tems->a_c_dimension.width -
6151253Slq150181 				    tems->a_c_cursor.col,
6161253Slq150181 				tems->a_c_cursor.row,
6171253Slq150181 				tems->a_c_cursor.col, credp, called_from);
6181253Slq150181 
6191253Slq150181 			/* THEN erase lines below the cursor */
6201253Slq150181 			for (row = tems->a_c_cursor.row + 1;
6211253Slq150181 				row < tems->a_c_dimension.height;
6221253Slq150181 				row++) {
6231253Slq150181 				tem_clear_chars(tem,
6241253Slq150181 				    tems->a_c_dimension.width,
6251253Slq150181 				    row, 0, credp, called_from);
6261253Slq150181 			}
6271253Slq150181 			break;
6281253Slq150181 
6291253Slq150181 		case 1:
6301253Slq150181 			/* erase beginning of screen to cursor */
6311253Slq150181 			/* FIRST erase lines above the cursor */
6321253Slq150181 			for (row = 0;
6331253Slq150181 				row < tems->a_c_cursor.row;
6341253Slq150181 				row++) {
6351253Slq150181 				tem_clear_chars(tem,
6361253Slq150181 				    tems->a_c_dimension.width,
6371253Slq150181 				    row, 0, credp, called_from);
6381253Slq150181 			}
6391253Slq150181 			/* THEN erase beginning of line to cursor */
6401253Slq150181 			tem_clear_chars(tem,
6411253Slq150181 				tems->a_c_cursor.col + 1,
6421253Slq150181 				tems->a_c_cursor.row,
6431253Slq150181 				    0, credp, called_from);
6441253Slq150181 			break;
6451253Slq150181 
6461253Slq150181 		case 2:
6471253Slq150181 			/* erase whole screen */
6481253Slq150181 			for (row = 0;
6491253Slq150181 			    row < tems->a_c_dimension.height;
6501253Slq150181 			    row++) {
6511253Slq150181 				tem_clear_chars(tem,
6521253Slq150181 				tems->a_c_dimension.width,
6531253Slq150181 				row, 0, credp, called_from);
6541253Slq150181 			}
6551253Slq150181 			break;
6561253Slq150181 		}
6571253Slq150181 		break;
6581253Slq150181 
6591253Slq150181 	case 'K':		/* EL - Erase in Line */
6601253Slq150181 		tem_send_data(tem, credp, called_from);
6611253Slq150181 		tem_setparam(tem, 1, 0);
6621253Slq150181 		switch (tems->a_params[0]) {
6631253Slq150181 		case 0:
6641253Slq150181 			/* erase cursor to end of line */
6651253Slq150181 			tem_clear_chars(tem,
6661253Slq150181 			    (tems->a_c_dimension.width -
6671253Slq150181 			    tems->a_c_cursor.col),
6681253Slq150181 			    tems->a_c_cursor.row,
6691253Slq150181 			    tems->a_c_cursor.col,
6701253Slq150181 			    credp, called_from);
6711253Slq150181 			break;
6721253Slq150181 
6731253Slq150181 		case 1:
6741253Slq150181 			/* erase beginning of line to cursor */
6751253Slq150181 			tem_clear_chars(tem,
6761253Slq150181 			    tems->a_c_cursor.col + 1,
6771253Slq150181 			    tems->a_c_cursor.row,
6781253Slq150181 			    0, credp, called_from);
6791253Slq150181 			break;
6801253Slq150181 
6811253Slq150181 		case 2:
6821253Slq150181 			/* erase whole line */
6831253Slq150181 			tem_clear_chars(tem,
6841253Slq150181 			    tems->a_c_dimension.width,
6851253Slq150181 			    tems->a_c_cursor.row,
6861253Slq150181 			    0, credp, called_from);
6871253Slq150181 			break;
6881253Slq150181 		}
6891253Slq150181 		break;
6901253Slq150181 
6911253Slq150181 	case 'L':		/* insert line */
6921253Slq150181 		tem_send_data(tem, credp, called_from);
6931253Slq150181 		tem_setparam(tem, 1, 1);
6941253Slq150181 		tem_scroll(tem,
6951253Slq150181 			tems->a_c_cursor.row,
6961253Slq150181 			tems->a_c_dimension.height - 1,
6971253Slq150181 			tems->a_params[0], TEM_SCROLL_DOWN,
6981253Slq150181 			    credp, called_from);
6991253Slq150181 		break;
7001253Slq150181 
7011253Slq150181 	case 'M':		/* delete line */
7021253Slq150181 		tem_send_data(tem, credp, called_from);
7031253Slq150181 		tem_setparam(tem, 1, 1);
7041253Slq150181 		tem_scroll(tem,
7051253Slq150181 			tems->a_c_cursor.row,
7061253Slq150181 			tems->a_c_dimension.height - 1,
7071253Slq150181 			tems->a_params[0], TEM_SCROLL_UP,
7081253Slq150181 			    credp, called_from);
7091253Slq150181 		break;
7101253Slq150181 
7111253Slq150181 	case 'P':		/* DCH - delete char */
7121253Slq150181 		tem_setparam(tem, 1, 1);
7131253Slq150181 		tem_shift(tem, tems->a_params[0], TEM_SHIFT_LEFT,
7141253Slq150181 		    credp, called_from);
7151253Slq150181 		break;
7161253Slq150181 
7171253Slq150181 	case 'S':		/* scroll up */
7181253Slq150181 		tem_send_data(tem, credp, called_from);
7191253Slq150181 		tem_setparam(tem, 1, 1);
7201253Slq150181 		tem_scroll(tem, 0,
7211253Slq150181 			tems->a_c_dimension.height - 1,
7221253Slq150181 			tems->a_params[0], TEM_SCROLL_UP,
7231253Slq150181 			    credp, called_from);
7241253Slq150181 		break;
7251253Slq150181 
7261253Slq150181 	case 'T':		/* scroll down */
7271253Slq150181 		tem_send_data(tem, credp, called_from);
7281253Slq150181 		tem_setparam(tem, 1, 1);
7291253Slq150181 		tem_scroll(tem, 0,
7301253Slq150181 			tems->a_c_dimension.height - 1,
7311253Slq150181 			tems->a_params[0], TEM_SCROLL_DOWN,
7321253Slq150181 			    credp, called_from);
7331253Slq150181 		break;
7341253Slq150181 
7351253Slq150181 	case 'X':		/* erase char */
7361253Slq150181 		tem_setparam(tem, 1, 1);
7371253Slq150181 		tem_clear_chars(tem,
7381253Slq150181 			tems->a_params[0],
7391253Slq150181 			tems->a_c_cursor.row,
7401253Slq150181 			tems->a_c_cursor.col,
7411253Slq150181 			    credp, called_from);
7421253Slq150181 		break;
7431253Slq150181 
7441253Slq150181 	case 'Z':		/* cursor backward tabulation */
7451253Slq150181 		tem_setparam(tem, 1, 1);
7461253Slq150181 
7471253Slq150181 		/*
7481253Slq150181 		 * Rule exception - We do sanity checking here.
7491253Slq150181 		 *
7501253Slq150181 		 * Restrict the count to a sane value to keep from
7511253Slq150181 		 * looping for a long time.  There can't be more than one
7521253Slq150181 		 * tab stop per column, so use that as a limit.
7531253Slq150181 		 */
7541253Slq150181 		if (tems->a_params[0] > tems->a_c_dimension.width)
7551253Slq150181 			tems->a_params[0] = tems->a_c_dimension.width;
7561253Slq150181 
7571253Slq150181 		for (i = 0; i < tems->a_params[0]; i++)
7581253Slq150181 			tem_back_tab(tem, credp, called_from);
7591253Slq150181 		break;
7601253Slq150181 	}
7611253Slq150181 	tems->a_state = A_STATE_START;
7621253Slq150181 }
7631253Slq150181 
7641253Slq150181 
7651253Slq150181 /*
7661253Slq150181  * Gather the parameters of an ANSI escape sequence
7671253Slq150181  */
7681253Slq150181 static void
7691253Slq150181 tem_getparams(struct tem *tem, uchar_t ch,
7701253Slq150181     cred_t *credp, enum called_from called_from)
7711253Slq150181 {
7721253Slq150181 	struct tem_state *tems = tem->state;
7731253Slq150181 
7741253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
7751253Slq150181 	    MUTEX_HELD(&tem->lock));
7761253Slq150181 
7772216Slt200341 	if (ch >= '0' && ch <= '9') {
7782216Slt200341 		tems->a_paramval = ((tems->a_paramval * 10) + (ch - '0'));
7791253Slq150181 		tems->a_gotparam = B_TRUE;  /* Remember got parameter */
7801253Slq150181 		return; /* Return immediately */
7812216Slt200341 	} else if (tems->a_state == A_STATE_CSI_EQUAL ||
7822216Slt200341 		tems->a_state == A_STATE_CSI_QMARK) {
7832216Slt200341 		tems->a_state = A_STATE_START;
7842216Slt200341 	} else {
7852216Slt200341 		if (tems->a_curparam < TEM_MAXPARAMS) {
7862216Slt200341 			if (tems->a_gotparam) {
7872216Slt200341 				/* get the parameter value */
7882216Slt200341 				tems->a_params[tems->a_curparam] =
7892216Slt200341 							tems->a_paramval;
7901253Slq150181 			}
7911253Slq150181 			tems->a_curparam++;
7921253Slq150181 		}
7931253Slq150181 
7941253Slq150181 		if (ch == ';') {
7951253Slq150181 			/* Restart parameter search */
7961253Slq150181 			tems->a_gotparam = B_FALSE;
7971253Slq150181 			tems->a_paramval = 0; /* No parame value yet */
7982216Slt200341 		} else {
7991253Slq150181 			/* Handle escape sequence */
8001253Slq150181 			tem_chkparam(tem, ch, credp, called_from);
8012216Slt200341 		}
8021253Slq150181 	}
8031253Slq150181 }
8041253Slq150181 
8051253Slq150181 /*
8061253Slq150181  * Add character to internal buffer.
8071253Slq150181  * When its full, send it to the next layer.
8081253Slq150181  */
8091253Slq150181 
8101253Slq150181 static void
8111253Slq150181 tem_outch(struct tem *tem, uchar_t ch,
8121253Slq150181     cred_t *credp, enum called_from called_from)
8131253Slq150181 {
8141253Slq150181 
8151253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
8161253Slq150181 	    MUTEX_HELD(&tem->lock));
8171253Slq150181 
8181253Slq150181 	/* buffer up the character until later */
8191253Slq150181 
8201253Slq150181 	tem->state->a_outbuf[tem->state->a_outindex++] = ch;
8211253Slq150181 	tem->state->a_c_cursor.col++;
8221253Slq150181 	if (tem->state->a_c_cursor.col >= tem->state->a_c_dimension.width) {
8231253Slq150181 		tem_send_data(tem, credp, called_from);
8241253Slq150181 		tem_new_line(tem, credp, called_from);
8251253Slq150181 	}
8261253Slq150181 }
8271253Slq150181 
8281253Slq150181 static void
8291253Slq150181 tem_new_line(struct tem *tem,
8301253Slq150181     cred_t *credp, enum called_from called_from)
8311253Slq150181 {
8321253Slq150181 	tem_cr(tem);
8331253Slq150181 	tem_lf(tem, credp, called_from);
8341253Slq150181 }
8351253Slq150181 
8361253Slq150181 static void
8371253Slq150181 tem_cr(struct tem *tem)
8381253Slq150181 {
8391253Slq150181 	tem->state->a_c_cursor.col = 0;
8401253Slq150181 	tem_align_cursor(tem);
8411253Slq150181 }
8421253Slq150181 
8431253Slq150181 static void
8441253Slq150181 tem_lf(struct tem *tem,
8451253Slq150181     cred_t *credp, enum called_from called_from)
8461253Slq150181 {
8471253Slq150181 	struct tem_state *tems = tem->state;
8481253Slq150181 	int row;
8491253Slq150181 
8501253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
8511253Slq150181 	    MUTEX_HELD(&tem->lock));
8521253Slq150181 
8531253Slq150181 	/*
8541253Slq150181 	 * Sanity checking notes:
8551253Slq150181 	 * . a_nscroll was validated when it was set.
8561253Slq150181 	 * . Regardless of that, tem_scroll and tem_mv_cursor will prevent
8571253Slq150181 	 *   anything bad from happening.
8581253Slq150181 	 */
8591253Slq150181 	row = tems->a_c_cursor.row + 1;
8601253Slq150181 
8611253Slq150181 	if (row >= tems->a_c_dimension.height) {
8621253Slq150181 		if (tems->a_nscroll != 0) {
8631253Slq150181 			tem_scroll(tem, 0,
8641253Slq150181 			    tems->a_c_dimension.height - 1,
8651253Slq150181 			    tems->a_nscroll, TEM_SCROLL_UP,
8661253Slq150181 			    credp, called_from);
8671253Slq150181 			row = tems->a_c_dimension.height -
8681253Slq150181 			    tems->a_nscroll;
8691253Slq150181 		} else {	/* no scroll */
8701253Slq150181 			/*
8711253Slq150181 			 * implement Esc[#r when # is zero.  This means no
8721253Slq150181 			 * scroll but just return cursor to top of screen,
8731253Slq150181 			 * do not clear screen.
8741253Slq150181 			 */
8751253Slq150181 			row = 0;
8761253Slq150181 		}
8771253Slq150181 	}
8781253Slq150181 
8791253Slq150181 	tem_mv_cursor(tem, row, tems->a_c_cursor.col,
8801253Slq150181 		credp, called_from);
8811253Slq150181 
8821253Slq150181 	if (tems->a_nscroll == 0) {
8831253Slq150181 		/* erase rest of cursor line */
8841253Slq150181 		tem_clear_chars(tem,
8851253Slq150181 		    tems->a_c_dimension.width -
8861253Slq150181 		    tems->a_c_cursor.col,
8871253Slq150181 		    tems->a_c_cursor.row,
8881253Slq150181 		    tems->a_c_cursor.col,
8891253Slq150181 		    credp, called_from);
8901253Slq150181 
8911253Slq150181 	}
8921253Slq150181 
8931253Slq150181 	tem_align_cursor(tem);
8941253Slq150181 }
8951253Slq150181 
8961253Slq150181 static void
8971253Slq150181 tem_send_data(struct tem *tem, cred_t *credp,
8981253Slq150181     enum called_from called_from)
8991253Slq150181 {
9001253Slq150181 	struct tem_state *tems = tem->state;
9011253Slq150181 	text_color_t fg_color;
9021253Slq150181 	text_color_t bg_color;
9031253Slq150181 
9041253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
9051253Slq150181 	    MUTEX_HELD(&tem->lock));
9061253Slq150181 
9071253Slq150181 	if (tems->a_outindex != 0) {
9081253Slq150181 
9091253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
9101253Slq150181 			fg_color = ansi_fg_to_solaris(tem,
9111253Slq150181 			    tems->bg_color);
9121253Slq150181 			bg_color = ansi_bg_to_solaris(tem,
9131253Slq150181 			    tems->fg_color);
9141253Slq150181 		} else {
9151253Slq150181 			fg_color = ansi_fg_to_solaris(tem,
9161253Slq150181 			    tems->fg_color);
9171253Slq150181 			bg_color = ansi_bg_to_solaris(tem,
9181253Slq150181 			    tems->bg_color);
9191253Slq150181 		}
9201253Slq150181 
9211253Slq150181 		/*
9221253Slq150181 		 * Call the primitive to render this data.
9231253Slq150181 		 */
9241253Slq150181 		(*tems->in_fp.f_display)(tem,
9251253Slq150181 			tems->a_outbuf,
9261253Slq150181 			tems->a_outindex,
9271253Slq150181 			tems->a_s_cursor.row,
9281253Slq150181 			    tems->a_s_cursor.col,
9291253Slq150181 			fg_color, bg_color,
9301253Slq150181 			credp, called_from);
9311253Slq150181 		tems->a_outindex = 0;
9321253Slq150181 	}
9331253Slq150181 	tem_align_cursor(tem);
9341253Slq150181 }
9351253Slq150181 
9361253Slq150181 
9371253Slq150181 /*
9381253Slq150181  * We have just done something to the current output point.  Reset the start
9391253Slq150181  * point for the buffered data in a_outbuf.  There shouldn't be any data
9401253Slq150181  * buffered yet.
9411253Slq150181  */
9421253Slq150181 void
9431253Slq150181 tem_align_cursor(struct tem *tem)
9441253Slq150181 {
9451253Slq150181 	tem->state->a_s_cursor.row = tem->state->a_c_cursor.row;
9461253Slq150181 	tem->state->a_s_cursor.col = tem->state->a_c_cursor.col;
9471253Slq150181 }
9481253Slq150181 
9491253Slq150181 
9501253Slq150181 
9511253Slq150181 /*
9521253Slq150181  * State machine parser based on the current state and character input
9531253Slq150181  * major terminations are to control character or normal character
9541253Slq150181  */
9551253Slq150181 
9561253Slq150181 static void
9571253Slq150181 tem_parse(struct tem *tem, uchar_t ch,
9581253Slq150181     cred_t *credp, enum called_from called_from)
9591253Slq150181 {
9601253Slq150181 	struct tem_state *tems = tem->state;
9611253Slq150181 	int	i;
9621253Slq150181 
9631253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
9641253Slq150181 	    MUTEX_HELD(&tem->lock));
9651253Slq150181 
9661253Slq150181 	if (tems->a_state == A_STATE_START) {	/* Normal state? */
9671253Slq150181 		if (ch == A_CSI || ch == A_ESC || ch < ' ') /* Control? */
9681253Slq150181 			tem_control(tem, ch, credp, called_from);
9691253Slq150181 		else
9701253Slq150181 			/* Display */
9711253Slq150181 			tem_outch(tem, ch, credp, called_from);
9721253Slq150181 		return;
9731253Slq150181 	}
9741253Slq150181 
9751253Slq150181 	/* In <ESC> sequence */
9761253Slq150181 	if (tems->a_state != A_STATE_ESC) {	/* Need to get parameters? */
9771253Slq150181 		if (tems->a_state != A_STATE_CSI) {
9781253Slq150181 			tem_getparams(tem, ch, credp, called_from);
9791253Slq150181 			return;
9801253Slq150181 		}
9811253Slq150181 
9821253Slq150181 		switch (ch) {
9831253Slq150181 		case '?':
9841253Slq150181 			tems->a_state = A_STATE_CSI_QMARK;
9851253Slq150181 			return;
9861253Slq150181 		case '=':
9871253Slq150181 			tems->a_state = A_STATE_CSI_EQUAL;
9881253Slq150181 			return;
9891253Slq150181 		case 's':
9901253Slq150181 			/*
9911253Slq150181 			 * As defined below, this sequence
9921253Slq150181 			 * saves the cursor.  However, Sun
9931253Slq150181 			 * defines ESC[s as reset.  We resolved
9941253Slq150181 			 * the conflict by selecting reset as it
9951253Slq150181 			 * is exported in the termcap file for
9961253Slq150181 			 * sun-mon, while the "save cursor"
9971253Slq150181 			 * definition does not exist anywhere in
9981253Slq150181 			 * /etc/termcap.
9991253Slq150181 			 * However, having no coherent
10001253Slq150181 			 * definition of reset, we have not
10011253Slq150181 			 * implemented it.
10021253Slq150181 			 */
10031253Slq150181 
10041253Slq150181 			/*
10051253Slq150181 			 * Original code
10061253Slq150181 			 * tems->a_r_cursor.row = tems->a_c_cursor.row;
10071253Slq150181 			 * tems->a_r_cursor.col = tems->a_c_cursor.col;
10081253Slq150181 			 * tems->a_state = A_STATE_START;
10091253Slq150181 			 */
10101253Slq150181 
10111253Slq150181 			tems->a_state = A_STATE_START;
10121253Slq150181 			return;
10131253Slq150181 		case 'u':
10141253Slq150181 			tem_mv_cursor(tem, tems->a_r_cursor.row,
10151253Slq150181 			    tems->a_r_cursor.col, credp, called_from);
10161253Slq150181 			tems->a_state = A_STATE_START;
10171253Slq150181 			return;
10181253Slq150181 		case 'p': 	/* sunbow */
10191253Slq150181 			tem_send_data(tem, credp, called_from);
10201253Slq150181 			/*
10211253Slq150181 			 * Don't set anything if we are
10221253Slq150181 			 * already as we want to be.
10231253Slq150181 			 */
10241253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
10251253Slq150181 				tems->a_flags &= ~TEM_ATTR_SCREEN_REVERSE;
10261253Slq150181 				/*
10271253Slq150181 				 * If we have switched the characters to be the
10281253Slq150181 				 * inverse from the screen, then switch them as
10291253Slq150181 				 * well to keep them the inverse of the screen.
10301253Slq150181 				 */
10311253Slq150181 				if (tems->a_flags & TEM_ATTR_REVERSE) {
10321253Slq150181 					tems->a_flags &= ~TEM_ATTR_REVERSE;
10331253Slq150181 				} else {
10341253Slq150181 					tems->a_flags |= TEM_ATTR_REVERSE;
10351253Slq150181 				}
10361253Slq150181 			}
10371253Slq150181 			tem_cls(tem, credp, called_from);
10381253Slq150181 			tems->a_state = A_STATE_START;
10391253Slq150181 			return;
10401253Slq150181 		case 'q':  	/* sunwob */
10411253Slq150181 			tem_send_data(tem, credp, called_from);
10421253Slq150181 			/*
10431253Slq150181 			 * Don't set anything if we are
10441253Slq150181 			 * already where as we want to be.
10451253Slq150181 			 */
10461253Slq150181 			if (!(tems->a_flags & TEM_ATTR_SCREEN_REVERSE)) {
10471253Slq150181 				tems->a_flags |= TEM_ATTR_SCREEN_REVERSE;
10481253Slq150181 				/*
10491253Slq150181 				 * If we have switched the characters to be the
10501253Slq150181 				 * inverse from the screen, then switch them as
10511253Slq150181 				 * well to keep them the inverse of the screen.
10521253Slq150181 				 */
10531253Slq150181 				if (!(tems->a_flags & TEM_ATTR_REVERSE)) {
10541253Slq150181 					tems->a_flags |= TEM_ATTR_REVERSE;
10551253Slq150181 				} else {
10561253Slq150181 					tems->a_flags &= ~TEM_ATTR_REVERSE;
10571253Slq150181 				}
10581253Slq150181 			}
10591253Slq150181 
10601253Slq150181 			tem_cls(tem, credp, called_from);
10611253Slq150181 			tems->a_state = A_STATE_START;
10621253Slq150181 			return;
10631253Slq150181 		case 'r':	/* sunscrl */
10641253Slq150181 			/*
10651253Slq150181 			 * Rule exception:  check for validity here.
10661253Slq150181 			 */
10671253Slq150181 			tems->a_nscroll = tems->a_paramval;
10681253Slq150181 			if (tems->a_nscroll > tems->a_c_dimension.height)
10691253Slq150181 				tems->a_nscroll = tems->a_c_dimension.height;
10701253Slq150181 			if (tems->a_nscroll < 0)
10711253Slq150181 				tems->a_nscroll = 1;
10721253Slq150181 			tems->a_state = A_STATE_START;
10731253Slq150181 			return;
10741253Slq150181 		default:
10751253Slq150181 			tem_getparams(tem, ch, credp, called_from);
10761253Slq150181 			return;
10771253Slq150181 		}
10781253Slq150181 	}
10791253Slq150181 
10801253Slq150181 	/* Previous char was <ESC> */
10811253Slq150181 	if (ch == '[') {
10821253Slq150181 		tems->a_curparam = 0;
10831253Slq150181 		tems->a_paramval = 0;
10841253Slq150181 		tems->a_gotparam = B_FALSE;
10851253Slq150181 		/* clear the parameters */
10861253Slq150181 		for (i = 0; i < TEM_MAXPARAMS; i++)
10871253Slq150181 			tems->a_params[i] = -1;
10881253Slq150181 		tems->a_state = A_STATE_CSI;
10891253Slq150181 	} else if (ch == 'Q') {	/* <ESC>Q ? */
10902216Slt200341 		tems->a_state = A_STATE_START;
10911253Slq150181 	} else if (ch == 'C') {	/* <ESC>C ? */
10922216Slt200341 		tems->a_state = A_STATE_START;
10931253Slq150181 	} else {
10941253Slq150181 		tems->a_state = A_STATE_START;
10951253Slq150181 		if (ch == 'c')
10961253Slq150181 			/* ESC c resets display */
1097*3994Slq150181 			tem_reset_display(tem, credp, called_from, 1, NULL);
10981253Slq150181 		else if (ch == 'H')
10991253Slq150181 			/* ESC H sets a tab */
11001253Slq150181 			tem_set_tab(tem);
11011253Slq150181 		else if (ch == '7') {
11021253Slq150181 			/* ESC 7 Save Cursor position */
11031253Slq150181 			tems->a_r_cursor.row = tems->a_c_cursor.row;
11041253Slq150181 			tems->a_r_cursor.col = tems->a_c_cursor.col;
11051253Slq150181 		} else if (ch == '8')
11061253Slq150181 			/* ESC 8 Restore Cursor position */
11071253Slq150181 			tem_mv_cursor(tem, tems->a_r_cursor.row,
11081253Slq150181 			    tems->a_r_cursor.col, credp, called_from);
11091253Slq150181 		/* check for control chars */
11101253Slq150181 		else if (ch < ' ')
11111253Slq150181 			tem_control(tem, ch, credp, called_from);
11121253Slq150181 		else
11131253Slq150181 			tem_outch(tem, ch, credp, called_from);
11141253Slq150181 	}
11151253Slq150181 }
11161253Slq150181 
11171253Slq150181 /* ARGSUSED */
11181253Slq150181 static void
11191253Slq150181 tem_bell(struct tem *tem, enum called_from called_from)
11201253Slq150181 {
11211253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
11221253Slq150181 		beep_polled(BEEP_CONSOLE);
11231253Slq150181 	else
11241253Slq150181 		beep(BEEP_CONSOLE);
11251253Slq150181 }
11261253Slq150181 
11271253Slq150181 
11281253Slq150181 static void
11291253Slq150181 tem_scroll(tem_t *tem, int start, int end, int count, int direction,
11301253Slq150181 	cred_t *credp, enum called_from called_from)
11311253Slq150181 {
11321253Slq150181 	struct tem_state *tems = tem->state;
11331253Slq150181 	int	row;
11341253Slq150181 	int	lines_affected;
11351253Slq150181 
11361253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
11371253Slq150181 	    MUTEX_HELD(&tem->lock));
11381253Slq150181 
11391253Slq150181 	lines_affected = end - start + 1;
11401253Slq150181 	if (count > lines_affected)
11411253Slq150181 		count = lines_affected;
11421253Slq150181 	if (count <= 0)
11431253Slq150181 		return;
11441253Slq150181 
11451253Slq150181 	switch (direction) {
11461253Slq150181 	case TEM_SCROLL_UP:
11471253Slq150181 		if (count < lines_affected) {
11481253Slq150181 			tem_copy_area(tem, 0, start + count,
11491253Slq150181 			    tems->a_c_dimension.width - 1, end,
11501253Slq150181 			    0, start, credp, called_from);
11511253Slq150181 		}
11521253Slq150181 		for (row = (end - count) + 1; row <= end; row++) {
11531253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
11541253Slq150181 			    row, 0, credp, called_from);
11551253Slq150181 		}
11561253Slq150181 		break;
11571253Slq150181 
11581253Slq150181 	case TEM_SCROLL_DOWN:
11591253Slq150181 		if (count < lines_affected) {
11601253Slq150181 			tem_copy_area(tem, 0, start,
11611253Slq150181 			    tems->a_c_dimension.width - 1,
11621253Slq150181 			    end - count, 0, start + count,
11631253Slq150181 			    credp, called_from);
11641253Slq150181 		}
11651253Slq150181 		for (row = start; row < start + count; row++) {
11661253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
11671253Slq150181 			    row, 0, credp, called_from);
11681253Slq150181 		}
11691253Slq150181 		break;
11701253Slq150181 	}
11711253Slq150181 }
11721253Slq150181 
11731253Slq150181 static void
11741253Slq150181 tem_copy_area(struct tem *tem,
11751253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
11761253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
11771253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
11781253Slq150181 	cred_t *credp, enum called_from called_from)
11791253Slq150181 {
11801253Slq150181 	struct tem_state *tems = tem->state;
11811253Slq150181 	int rows;
11821253Slq150181 	int cols;
11831253Slq150181 
11841253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
11851253Slq150181 	    MUTEX_HELD(&tem->lock));
11861253Slq150181 
11871253Slq150181 	if (s_col < 0 || s_row < 0 ||
11881253Slq150181 	    e_col < 0 || e_row < 0 ||
11891253Slq150181 	    t_col < 0 || t_row < 0 ||
11901253Slq150181 	    s_col >= tems->a_c_dimension.width ||
11911253Slq150181 	    e_col >= tems->a_c_dimension.width ||
11921253Slq150181 	    t_col >= tems->a_c_dimension.width ||
11931253Slq150181 	    s_row >= tems->a_c_dimension.height ||
11941253Slq150181 	    e_row >= tems->a_c_dimension.height ||
11951253Slq150181 	    t_row >= tems->a_c_dimension.height)
11961253Slq150181 		return;
11971253Slq150181 
11981253Slq150181 	if (s_row > e_row || s_col > e_col)
11991253Slq150181 		return;
12001253Slq150181 
12011253Slq150181 	rows = e_row - s_row + 1;
12021253Slq150181 	cols = e_col - s_col + 1;
12031253Slq150181 	if (t_row + rows > tems->a_c_dimension.height ||
12041253Slq150181 	    t_col + cols > tems->a_c_dimension.width)
12051253Slq150181 		return;
12061253Slq150181 
12071253Slq150181 	(*tems->in_fp.f_copy)(tem, s_col, s_row,
12081253Slq150181 		e_col, e_row, t_col, t_row, credp, called_from);
12091253Slq150181 }
12101253Slq150181 
12111253Slq150181 static void
12121253Slq150181 tem_clear_chars(struct tem *tem, int count, screen_pos_t row,
12131253Slq150181 	screen_pos_t col, cred_t *credp, enum called_from called_from)
12141253Slq150181 {
12151253Slq150181 	struct tem_state *tems = tem->state;
12161253Slq150181 
12171253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
12181253Slq150181 	    MUTEX_HELD(&tem->lock));
12191253Slq150181 
12201253Slq150181 	if (row < 0 || row >= tems->a_c_dimension.height ||
12211253Slq150181 	    col < 0 || col >= tems->a_c_dimension.width ||
12221253Slq150181 	    count < 0)
12231253Slq150181 		return;
12241253Slq150181 
12251253Slq150181 	/*
12261253Slq150181 	 * Note that very large values of "count" could cause col+count
12271253Slq150181 	 * to overflow, so we check "count" independently.
12281253Slq150181 	 */
12291253Slq150181 	if (count > tems->a_c_dimension.width ||
12301253Slq150181 	    col + count > tems->a_c_dimension.width)
12311253Slq150181 		count = tems->a_c_dimension.width - col;
12321253Slq150181 
12331253Slq150181 	(*tems->in_fp.f_cls)(tem, count, row, col, credp, called_from);
12341253Slq150181 }
12351253Slq150181 
12361253Slq150181 void
12371253Slq150181 tem_text_display(struct tem *tem, uchar_t *string,
12381253Slq150181 	int count, screen_pos_t row, screen_pos_t col,
12391253Slq150181 	text_color_t fg_color, text_color_t bg_color,
12401253Slq150181 	cred_t *credp, enum called_from called_from)
12411253Slq150181 {
12421253Slq150181 	struct vis_consdisplay da;
12431253Slq150181 
12441253Slq150181 	da.data = string;
12451253Slq150181 	da.width = count;
12461253Slq150181 	da.row = row;
12471253Slq150181 	da.col = col;
12481253Slq150181 
12491253Slq150181 	da.fg_color = fg_color;
12501253Slq150181 	da.bg_color = bg_color;
12511253Slq150181 
12521253Slq150181 	tem_display(tem, &da, credp, called_from);
12531253Slq150181 }
12541253Slq150181 
12551253Slq150181 /*
12561253Slq150181  * This function is used to blit a rectangular color image,
12571253Slq150181  * unperturbed on the underlying framebuffer, to render
12581253Slq150181  * icons and pictures.  The data is a pixel pattern that
12591253Slq150181  * fills a rectangle bounded to the width and height parameters.
12601253Slq150181  * The color pixel data must to be pre-adjusted by the caller
12611253Slq150181  * for the current video depth.
12621253Slq150181  *
12631253Slq150181  * This function is unused now.
12641253Slq150181  */
12651253Slq150181 void
12661253Slq150181 tem_image_display(struct tem *tem, uchar_t *image,
12671253Slq150181 	int height, int width, screen_pos_t row, screen_pos_t col,
12681253Slq150181 	cred_t *credp, enum called_from called_from)
12691253Slq150181 {
12701253Slq150181 	struct vis_consdisplay da;
12711253Slq150181 
12721253Slq150181 	da.data = image;
12731253Slq150181 	da.width = width;
12741253Slq150181 	da.height = height;
12751253Slq150181 	da.row = row;
12761253Slq150181 	da.col = col;
12771253Slq150181 
12781253Slq150181 	tem_display(tem, &da, credp, called_from);
12791253Slq150181 }
12801253Slq150181 
12811253Slq150181 
12821253Slq150181 void
12831253Slq150181 tem_text_copy(struct tem *tem,
12841253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
12851253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
12861253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
12871253Slq150181 	cred_t *credp, enum called_from called_from)
12881253Slq150181 {
12891253Slq150181 	struct vis_conscopy da;
12901253Slq150181 
12911253Slq150181 	da.s_row = s_row;
12921253Slq150181 	da.s_col = s_col;
12931253Slq150181 	da.e_row = e_row;
12941253Slq150181 	da.e_col = e_col;
12951253Slq150181 	da.t_row = t_row;
12961253Slq150181 	da.t_col = t_col;
12971253Slq150181 
12981253Slq150181 	tem_copy(tem, &da, credp, called_from);
12991253Slq150181 }
13001253Slq150181 
13011253Slq150181 void
13021253Slq150181 tem_text_cls(struct tem *tem,
13031253Slq150181 	int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
13041253Slq150181 	enum called_from called_from)
13051253Slq150181 {
13061253Slq150181 	struct vis_consdisplay da;
13071253Slq150181 
13081253Slq150181 	da.data = tem->state->a_blank_line;
13091253Slq150181 	da.width = count;
13101253Slq150181 	da.row = row;
13111253Slq150181 	da.col = col;
13121253Slq150181 
13131253Slq150181 	tem_get_color(tem, &da.fg_color, &da.bg_color);
13141253Slq150181 	tem_display(tem, &da, credp, called_from);
13151253Slq150181 }
13161253Slq150181 
13171253Slq150181 
13181253Slq150181 
13191253Slq150181 void
13201253Slq150181 tem_pix_display(struct tem *tem,
13211253Slq150181 	uchar_t *string, int count,
13221253Slq150181 	screen_pos_t row, screen_pos_t col,
13231253Slq150181 	text_color_t fg_color, text_color_t bg_color,
13241253Slq150181 	cred_t *credp, enum called_from called_from)
13251253Slq150181 {
13261253Slq150181 	struct tem_state *tems = tem->state;
13271253Slq150181 	struct vis_consdisplay da;
13281253Slq150181 	int	i;
13291253Slq150181 	da.data = (uchar_t *)tems->a_pix_data;
13301253Slq150181 	da.width = tems->a_font.width;
13311253Slq150181 	da.height = tems->a_font.height;
13321253Slq150181 	da.row = (row * da.height) + tems->a_p_offset.y;
13331253Slq150181 	da.col = (col * da.width) + tems->a_p_offset.x;
13341253Slq150181 
13351253Slq150181 	for (i = 0; i < count; i++) {
13361253Slq150181 		BIT_TO_PIX(tem, string[i], fg_color, bg_color);
13371253Slq150181 		tem_display(tem, &da, credp, called_from);
13381253Slq150181 		da.col += da.width;
13391253Slq150181 	}
13401253Slq150181 }
13411253Slq150181 
13421253Slq150181 void
13431253Slq150181 tem_pix_copy(struct tem *tem,
13441253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
13451253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
13461253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
13471253Slq150181 	cred_t *credp,
13481253Slq150181 	enum called_from called_from)
13491253Slq150181 {
13501253Slq150181 	struct tem_state *tems = tem->state;
13511253Slq150181 	struct vis_conscopy ma;
13521253Slq150181 	static boolean_t need_clear = B_TRUE;
13531253Slq150181 
13541253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
13551253Slq150181 	    MUTEX_HELD(&tem->lock));
13561253Slq150181 
13571253Slq150181 	if (need_clear && tems->first_line > 0) {
13581253Slq150181 		/*
13591253Slq150181 		 * Clear OBP output above our kernel console term
13601253Slq150181 		 * when our kernel console term begins to scroll up,
13611253Slq150181 		 * we hope it is user friendly.
13621253Slq150181 		 * (Also see comments on tem_pix_clear_prom_output)
13631253Slq150181 		 *
13641253Slq150181 		 * This is only one time call.
13651253Slq150181 		 */
13661253Slq150181 		tem_pix_clear_prom_output(tem, credp, called_from);
13671253Slq150181 	}
13681253Slq150181 	need_clear = B_FALSE;
13691253Slq150181 
13701253Slq150181 	ma.s_row = s_row * tems->a_font.height + tems->a_p_offset.y;
13711253Slq150181 	ma.e_row = (e_row + 1) * tems->a_font.height + tems->a_p_offset.y - 1;
13721253Slq150181 	ma.t_row = t_row * tems->a_font.height + tems->a_p_offset.y;
13731253Slq150181 
13741253Slq150181 	/*
13751253Slq150181 	 * Check if we're in process of clearing OBP's columns area,
13761253Slq150181 	 * which only happens when term scrolls up a whole line.
13771253Slq150181 	 */
13781253Slq150181 	if (tems->first_line > 0 && t_row < s_row && t_col == 0 &&
13791253Slq150181 	    e_col == tems->a_c_dimension.width - 1) {
13801253Slq150181 		/*
13811253Slq150181 		 * We need to clear OBP's columns area outside our kernel
13821253Slq150181 		 * console term. So that we set ma.e_col to entire row here.
13831253Slq150181 		 */
13841253Slq150181 		ma.s_col = s_col * tems->a_font.width;
13851253Slq150181 		ma.e_col = tems->a_p_dimension.width - 1;
13861253Slq150181 
13871253Slq150181 		ma.t_col = t_col * tems->a_font.width;
13881253Slq150181 	} else {
13891253Slq150181 		ma.s_col = s_col * tems->a_font.width + tems->a_p_offset.x;
13901253Slq150181 		ma.e_col = (e_col + 1) * tems->a_font.width +
13911253Slq150181 		    tems->a_p_offset.x - 1;
13921253Slq150181 		ma.t_col = t_col * tems->a_font.width + tems->a_p_offset.x;
13931253Slq150181 	}
13941253Slq150181 
13951253Slq150181 	tem_copy(tem, &ma, credp, called_from);
13961253Slq150181 
13971253Slq150181 	if (tems->first_line > 0 && t_row < s_row) {
13981253Slq150181 		/* We have scrolled up (s_row - t_row) rows. */
13991253Slq150181 		tems->first_line -= (s_row - t_row);
14001253Slq150181 		if (tems->first_line <= 0) {
14011253Slq150181 			/* All OBP rows have been cleared. */
14021253Slq150181 			tems->first_line = 0;
14031253Slq150181 		}
14041253Slq150181 	}
14051253Slq150181 
14061253Slq150181 }
14071253Slq150181 
14081253Slq150181 /*
14091253Slq150181  * This function only clears count of columns in one row
14101253Slq150181  */
14111253Slq150181 void
14121253Slq150181 tem_pix_cls(struct tem *tem, int count,
14131253Slq150181 	screen_pos_t row, screen_pos_t col, cred_t *credp,
14141253Slq150181 	enum called_from called_from)
14151253Slq150181 {
14161253Slq150181 	struct tem_state *tems = tem->state;
14171253Slq150181 
14181253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
14191253Slq150181 	    MUTEX_HELD(&tem->lock));
14201253Slq150181 
14211253Slq150181 	tem_pix_cls_range(tem, row, 1, tems->a_p_offset.y,
14221253Slq150181 	    col, count, tems->a_p_offset.x, B_FALSE, credp, called_from);
14231253Slq150181 }
14241253Slq150181 
14251253Slq150181 /*
14261253Slq150181  * This function clears OBP output above our kernel console term area
14271253Slq150181  * because OBP's term may have a bigger terminal window than that of
14281253Slq150181  * our kernel console term. So we need to clear OBP output garbage outside
14291253Slq150181  * of our kernel console term at a proper time, which is when the first
14301253Slq150181  * row output of our kernel console term scrolls at the first screen line.
14311253Slq150181  *
14321253Slq150181  *	_________________________________
14331253Slq150181  *	|   _____________________	|  ---> OBP's bigger term window
14341253Slq150181  *	|   |			|	|
14351253Slq150181  *	|___|			|	|
14361253Slq150181  *	| | |			|	|
14371253Slq150181  *	| | |			|	|
14381253Slq150181  *	|_|_|___________________|_______|
14391253Slq150181  *	  | |			|	   ---> first line
14401253Slq150181  *	  | |___________________|---> our kernel console term window
14411253Slq150181  *	  |
14421253Slq150181  *	  |---> columns area to be cleared
14431253Slq150181  *
14441253Slq150181  * This function only takes care of the output above our kernel console term,
14451253Slq150181  * and tem_prom_scroll_up takes care of columns area outside of our kernel
14461253Slq150181  * console term.
14471253Slq150181  */
14481253Slq150181 static void
14491253Slq150181 tem_pix_clear_prom_output(struct tem *tem, cred_t *credp,
14501253Slq150181     enum called_from called_from)
14511253Slq150181 {
14521253Slq150181 	struct tem_state *tems = tem->state;
14531253Slq150181 	int	nrows, ncols, width, height;
14541253Slq150181 
14551253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
14561253Slq150181 	    MUTEX_HELD(&tem->lock));
14571253Slq150181 
14581253Slq150181 	width = tems->a_font.width;
14591253Slq150181 	height = tems->a_font.height;
14601253Slq150181 
14611253Slq150181 	nrows = (tems->a_p_offset.y + (height - 1))/ height;
14621253Slq150181 	ncols = (tems->a_p_dimension.width + (width - 1))/ width;
14631253Slq150181 
14641253Slq150181 	tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
14651253Slq150181 	    B_FALSE, credp, called_from);
14661253Slq150181 }
14671253Slq150181 
14681253Slq150181 /*
14691253Slq150181  * clear the whole screen for pixel mode
14701253Slq150181  */
14711253Slq150181 static void
14721253Slq150181 tem_pix_clear_entire_screen(struct tem *tem, cred_t *credp,
14731253Slq150181     enum called_from called_from)
14741253Slq150181 {
14751253Slq150181 	struct tem_state *tems = tem->state;
14761253Slq150181 	int	nrows, ncols, width, height;
14771253Slq150181 
14781253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
14791253Slq150181 	    MUTEX_HELD(&tem->lock));
14801253Slq150181 
14811253Slq150181 	width = tems->a_font.width;
14821253Slq150181 	height = tems->a_font.height;
14831253Slq150181 
14841253Slq150181 	nrows = (tems->a_p_dimension.height + (height - 1))/ height;
14851253Slq150181 	ncols = (tems->a_p_dimension.width + (width - 1))/ width;
14861253Slq150181 
14871253Slq150181 	tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
14881253Slq150181 	    B_FALSE, credp, called_from);
14891253Slq150181 
14901253Slq150181 	tems->a_c_cursor.row = 0;
14911253Slq150181 	tems->a_c_cursor.col = 0;
14921253Slq150181 	tem_align_cursor(tem);
14931253Slq150181 
14941253Slq150181 	/*
14951253Slq150181 	 * Since the whole screen is cleared, we don't need
14961253Slq150181 	 * to clear OBP output later.
14971253Slq150181 	 */
14981253Slq150181 	if (tems->first_line > 0) {
14991253Slq150181 		tems->first_line = 0;
15001253Slq150181 	}
15011253Slq150181 }
15021253Slq150181 
15031253Slq150181 /*
15041253Slq150181  * clear the whole screen
15051253Slq150181  */
15061253Slq150181 static void
15071253Slq150181 tem_cls(struct tem *tem,
15081253Slq150181     cred_t *credp, enum called_from called_from)
15091253Slq150181 {
15101253Slq150181 	struct tem_state *tems = tem->state;
15111253Slq150181 	int	row;
15121253Slq150181 
15131253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
15141253Slq150181 	    MUTEX_HELD(&tem->lock));
15151253Slq150181 
15161253Slq150181 	if (tems->display_mode == VIS_TEXT) {
15171253Slq150181 		for (row = 0; row < tems->a_c_dimension.height; row++) {
15181253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
15191253Slq150181 				row, 0, credp, called_from);
15201253Slq150181 		}
15211253Slq150181 		tems->a_c_cursor.row = 0;
15221253Slq150181 		tems->a_c_cursor.col = 0;
15231253Slq150181 		tem_align_cursor(tem);
15241253Slq150181 		return;
15251253Slq150181 	}
15261253Slq150181 
15271253Slq150181 	ASSERT(tems->display_mode == VIS_PIXEL);
15281253Slq150181 
15291253Slq150181 	tem_pix_clear_entire_screen(tem, credp, called_from);
15301253Slq150181 }
15311253Slq150181 
15321253Slq150181 static void
15331253Slq150181 tem_back_tab(struct tem *tem,
15341253Slq150181     cred_t *credp, enum called_from called_from)
15351253Slq150181 {
15361253Slq150181 	struct tem_state *tems = tem->state;
15371253Slq150181 	int	i;
15381253Slq150181 	screen_pos_t	tabstop;
15391253Slq150181 
15401253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
15411253Slq150181 	    MUTEX_HELD(&tem->lock));
15421253Slq150181 
15431253Slq150181 	tabstop = 0;
15441253Slq150181 
15451253Slq150181 	for (i = tems->a_ntabs - 1; i >= 0; i--) {
15461253Slq150181 		if (tems->a_tabs[i] < tems->a_c_cursor.col) {
15471253Slq150181 			tabstop = tems->a_tabs[i];
15481253Slq150181 			break;
15491253Slq150181 		}
15501253Slq150181 	}
15511253Slq150181 
15521253Slq150181 	tem_mv_cursor(tem, tems->a_c_cursor.row,
15531253Slq150181 	tabstop, credp, called_from);
15541253Slq150181 }
15551253Slq150181 
15561253Slq150181 static void
15571253Slq150181 tem_tab(struct tem *tem,
15581253Slq150181     cred_t *credp, enum called_from called_from)
15591253Slq150181 {
15601253Slq150181 	struct tem_state *tems = tem->state;
15611253Slq150181 	int	i;
15621253Slq150181 	screen_pos_t	tabstop;
15631253Slq150181 
15641253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
15651253Slq150181 	    MUTEX_HELD(&tem->lock));
15661253Slq150181 
15671253Slq150181 	tabstop = tems->a_c_dimension.width - 1;
15681253Slq150181 
15691253Slq150181 	for (i = 0; i < tems->a_ntabs; i++) {
15701253Slq150181 		if (tems->a_tabs[i] > tems->a_c_cursor.col) {
15711253Slq150181 			tabstop = tems->a_tabs[i];
15721253Slq150181 			break;
15731253Slq150181 		}
15741253Slq150181 	}
15751253Slq150181 
15761253Slq150181 	tem_mv_cursor(tem, tems->a_c_cursor.row,
15771253Slq150181 	    tabstop, credp, called_from);
15781253Slq150181 }
15791253Slq150181 
15801253Slq150181 static void
15811253Slq150181 tem_set_tab(struct tem *tem)
15821253Slq150181 {
15831253Slq150181 	struct tem_state *tems = tem->state;
15841253Slq150181 	int	i;
15851253Slq150181 	int	j;
15861253Slq150181 
15871253Slq150181 	if (tems->a_ntabs == TEM_MAXTAB)
15881253Slq150181 		return;
15891253Slq150181 	if (tems->a_ntabs == 0 ||
15901253Slq150181 		tems->a_tabs[tems->a_ntabs] < tems->a_c_cursor.col) {
15911253Slq150181 			tems->a_tabs[tems->a_ntabs++] = tems->a_c_cursor.col;
15921253Slq150181 			return;
15931253Slq150181 	}
15941253Slq150181 	for (i = 0; i < tems->a_ntabs; i++) {
15951253Slq150181 		if (tems->a_tabs[i] == tems->a_c_cursor.col)
15961253Slq150181 			return;
15971253Slq150181 		if (tems->a_tabs[i] > tems->a_c_cursor.col) {
15981253Slq150181 			for (j = tems->a_ntabs - 1; j >= i; j--)
15991253Slq150181 				tems->a_tabs[j+ 1] = tems->a_tabs[j];
16001253Slq150181 			tems->a_tabs[i] = tems->a_c_cursor.col;
16011253Slq150181 			tems->a_ntabs++;
16021253Slq150181 			return;
16031253Slq150181 		}
16041253Slq150181 	}
16051253Slq150181 }
16061253Slq150181 
16071253Slq150181 static void
16081253Slq150181 tem_clear_tabs(struct tem *tem, int action)
16091253Slq150181 {
16101253Slq150181 	struct tem_state *tems = tem->state;
16111253Slq150181 	int	i;
16121253Slq150181 	int	j;
16131253Slq150181 
16141253Slq150181 	switch (action) {
16151253Slq150181 	case 3: /* clear all tabs */
16161253Slq150181 		tems->a_ntabs = 0;
16171253Slq150181 		break;
16181253Slq150181 	case 0: /* clr tab at cursor */
16191253Slq150181 
16201253Slq150181 		for (i = 0; i < tems->a_ntabs; i++) {
16211253Slq150181 			if (tems->a_tabs[i] == tems->a_c_cursor.col) {
16221253Slq150181 				tems->a_ntabs--;
16231253Slq150181 				for (j = i; j < tems->a_ntabs; j++)
16241253Slq150181 					tems->a_tabs[j] = tems->a_tabs[j + 1];
16251253Slq150181 				return;
16261253Slq150181 			}
16271253Slq150181 		}
16281253Slq150181 		break;
16291253Slq150181 	}
16301253Slq150181 }
16311253Slq150181 
16321253Slq150181 static void
16331253Slq150181 tem_mv_cursor(struct tem *tem, int row, int col,
16341253Slq150181     cred_t *credp, enum called_from called_from)
16351253Slq150181 {
16361253Slq150181 	struct tem_state *tems = tem->state;
16371253Slq150181 
16381253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
16391253Slq150181 	    MUTEX_HELD(&tem->lock));
16401253Slq150181 
16411253Slq150181 	/*
16421253Slq150181 	 * Sanity check and bounds enforcement.  Out of bounds requests are
16431253Slq150181 	 * clipped to the screen boundaries.  This seems to be what SPARC
16441253Slq150181 	 * does.
16451253Slq150181 	 */
16461253Slq150181 	if (row < 0)
16471253Slq150181 		row = 0;
16481253Slq150181 	if (row >= tems->a_c_dimension.height)
16491253Slq150181 		row = tems->a_c_dimension.height - 1;
16501253Slq150181 	if (col < 0)
16511253Slq150181 		col = 0;
16521253Slq150181 	if (col >= tems->a_c_dimension.width)
16531253Slq150181 		col = tems->a_c_dimension.width - 1;
16541253Slq150181 
16551253Slq150181 	tem_send_data(tem, credp, called_from);
16561253Slq150181 	tems->a_c_cursor.row = row;
16571253Slq150181 	tems->a_c_cursor.col = col;
16581253Slq150181 	tem_align_cursor(tem);
16591253Slq150181 }
16601253Slq150181 
16611253Slq150181 /* ARGSUSED */
16621253Slq150181 void
16631253Slq150181 tem_reset_emulator(struct tem *tem,
1664*3994Slq150181     cred_t *credp, enum called_from called_from,
1665*3994Slq150181     tem_color_t *pcolor)
16661253Slq150181 {
16671253Slq150181 	struct tem_state *tems = tem->state;
16681253Slq150181 	int j;
16691253Slq150181 
16701253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
16711253Slq150181 	    MUTEX_HELD(&tem->lock));
16721253Slq150181 
16731253Slq150181 	tems->a_c_cursor.row = 0;
16741253Slq150181 	tems->a_c_cursor.col = 0;
16751253Slq150181 	tems->a_r_cursor.row = 0;
16761253Slq150181 	tems->a_r_cursor.col = 0;
16771253Slq150181 	tems->a_s_cursor.row = 0;
16781253Slq150181 	tems->a_s_cursor.col = 0;
16791253Slq150181 	tems->a_outindex = 0;
16801253Slq150181 	tems->a_state = A_STATE_START;
16811253Slq150181 	tems->a_gotparam = B_FALSE;
16821253Slq150181 	tems->a_curparam = 0;
16831253Slq150181 	tems->a_paramval = 0;
16841253Slq150181 	tems->a_nscroll = 1;
1685*3994Slq150181 
1686*3994Slq150181 	if (pcolor != NULL) {
1687*3994Slq150181 		/* use customized settings */
1688*3994Slq150181 		tems->fg_color = pcolor->fg_color;
1689*3994Slq150181 		tems->bg_color = pcolor->bg_color;
1690*3994Slq150181 		tems->a_flags = pcolor->a_flags;
1691*3994Slq150181 	} else {
1692*3994Slq150181 		/* use initial settings */
1693*3994Slq150181 		tems->fg_color = tem->init_color.fg_color;
1694*3994Slq150181 		tems->bg_color = tem->init_color.bg_color;
1695*3994Slq150181 		tems->a_flags = tem->init_color.a_flags;
1696*3994Slq150181 	}
16971253Slq150181 
16981253Slq150181 	/*
16991253Slq150181 	 * set up the initial tab stops
17001253Slq150181 	 */
17011253Slq150181 	tems->a_ntabs = 0;
17021253Slq150181 	for (j = 8; j < tems->a_c_dimension.width; j += 8)
17031253Slq150181 		tems->a_tabs[tems->a_ntabs++] = (screen_pos_t)j;
17041253Slq150181 
17051253Slq150181 	for (j = 0; j < TEM_MAXPARAMS; j++)
17061253Slq150181 		tems->a_params[j] = 0;
17071253Slq150181 }
17081253Slq150181 
17091253Slq150181 void
17101253Slq150181 tem_reset_display(struct tem *tem,
1711*3994Slq150181     cred_t *credp, enum called_from called_from, int clear_txt,
1712*3994Slq150181     tem_color_t *pcolor)
17131253Slq150181 {
17141253Slq150181 	struct tem_state *tems = tem->state;
17151253Slq150181 
17161253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
17171253Slq150181 	    MUTEX_HELD(&tem->lock));
17181253Slq150181 
1719*3994Slq150181 	tem_reset_emulator(tem, credp, called_from, pcolor);
17201253Slq150181 	tem_reset_colormap(tem, credp, called_from);
17211253Slq150181 
17221253Slq150181 	if (clear_txt) {
17231253Slq150181 		(*tems->in_fp.f_cursor)(tem,
17241253Slq150181 		    VIS_HIDE_CURSOR, credp, called_from);
17251253Slq150181 
17261253Slq150181 		tem_cls(tem, credp, called_from);
17271253Slq150181 
17281253Slq150181 		(*tems->in_fp.f_cursor)(tem,
17291253Slq150181 		    VIS_DISPLAY_CURSOR, credp, called_from);
17301253Slq150181 	}
17311253Slq150181 
17321253Slq150181 	tems->a_initialized = 1;
17331253Slq150181 }
17341253Slq150181 
17351253Slq150181 
17361253Slq150181 static void
17371253Slq150181 tem_shift(
17381253Slq150181 	struct tem *tem,
17391253Slq150181 	int count,
17401253Slq150181 	int direction,
17411253Slq150181 	cred_t *credp,
17421253Slq150181 	enum called_from called_from)
17431253Slq150181 {
17441253Slq150181 	struct tem_state *tems = tem->state;
17451253Slq150181 	int rest_of_line;
17461253Slq150181 
17471253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
17481253Slq150181 	    MUTEX_HELD(&tem->lock));
17491253Slq150181 
17501253Slq150181 	rest_of_line = tems->a_c_dimension.width - tems->a_c_cursor.col;
17511253Slq150181 	if (count > rest_of_line)
17521253Slq150181 		count = rest_of_line;
17531253Slq150181 
17541253Slq150181 	if (count <= 0)
17551253Slq150181 		return;
17561253Slq150181 
17571253Slq150181 	switch (direction) {
17581253Slq150181 	case TEM_SHIFT_LEFT:
17591253Slq150181 		if (count < rest_of_line) {
17601253Slq150181 			tem_copy_area(tem,
17611253Slq150181 				tems->a_c_cursor.col + count,
17621253Slq150181 				tems->a_c_cursor.row,
17631253Slq150181 				tems->a_c_dimension.width - 1,
17641253Slq150181 				tems->a_c_cursor.row,
17651253Slq150181 				tems->a_c_cursor.col,
17661253Slq150181 				tems->a_c_cursor.row,
17671253Slq150181 				credp, called_from);
17681253Slq150181 		}
17691253Slq150181 
17701253Slq150181 		tem_clear_chars(tem, count, tems->a_c_cursor.row,
17711253Slq150181 			(tems->a_c_dimension.width - count), credp,
17721253Slq150181 			called_from);
17731253Slq150181 		break;
17741253Slq150181 	case TEM_SHIFT_RIGHT:
17751253Slq150181 		if (count < rest_of_line) {
17761253Slq150181 			tem_copy_area(tem,
17771253Slq150181 				tems->a_c_cursor.col,
17781253Slq150181 				tems->a_c_cursor.row,
17791253Slq150181 				tems->a_c_dimension.width - count - 1,
17801253Slq150181 				tems->a_c_cursor.row,
17811253Slq150181 				tems->a_c_cursor.col + count,
17821253Slq150181 				tems->a_c_cursor.row,
17831253Slq150181 				credp, called_from);
17841253Slq150181 		}
17851253Slq150181 
17861253Slq150181 		tem_clear_chars(tem, count, tems->a_c_cursor.row,
17871253Slq150181 			tems->a_c_cursor.col, credp, called_from);
17881253Slq150181 		break;
17891253Slq150181 	}
17901253Slq150181 }
17911253Slq150181 
17921253Slq150181 void
17931253Slq150181 tem_text_cursor(struct tem *tem, short action,
17941253Slq150181     cred_t *credp, enum called_from called_from)
17951253Slq150181 {
17961253Slq150181 	struct tem_state *tems = tem->state;
17971253Slq150181 	struct vis_conscursor	ca;
17981253Slq150181 
17991253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
18001253Slq150181 	    MUTEX_HELD(&tem->lock));
18011253Slq150181 
18021253Slq150181 	ca.row = tems->a_c_cursor.row;
18031253Slq150181 	ca.col = tems->a_c_cursor.col;
18041253Slq150181 	ca.action = action;
18051253Slq150181 
18061253Slq150181 	tem_cursor(tem, &ca, credp, called_from);
18071253Slq150181 
18081253Slq150181 	if (action == VIS_GET_CURSOR) {
18091253Slq150181 		tems->a_c_cursor.row = ca.row;
18101253Slq150181 		tems->a_c_cursor.col = ca.col;
18111253Slq150181 	}
18121253Slq150181 }
18131253Slq150181 
18141253Slq150181 
18151253Slq150181 void
18161253Slq150181 tem_pix_cursor(struct tem *tem, short action,
18171253Slq150181     cred_t *credp, enum called_from called_from)
18181253Slq150181 {
18191253Slq150181 	struct tem_state *tems = tem->state;
18201253Slq150181 	struct vis_conscursor	ca;
18211253Slq150181 
18221253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
18231253Slq150181 	    MUTEX_HELD(&tem->lock));
18241253Slq150181 
18251253Slq150181 	ca.row = tems->a_c_cursor.row * tems->a_font.height +
18261253Slq150181 				tems->a_p_offset.y;
18271253Slq150181 	ca.col = tems->a_c_cursor.col * tems->a_font.width +
18281253Slq150181 				tems->a_p_offset.x;
18291253Slq150181 	ca.width = tems->a_font.width;
18301253Slq150181 	ca.height = tems->a_font.height;
18311253Slq150181 	if (tems->a_pdepth == 8 || tems->a_pdepth == 4) {
18321253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
18331253Slq150181 			ca.fg_color.mono = TEM_TEXT_WHITE;
18341253Slq150181 			ca.bg_color.mono = TEM_TEXT_BLACK;
18351253Slq150181 		} else {
18361253Slq150181 			ca.fg_color.mono = TEM_TEXT_BLACK;
18371253Slq150181 			ca.bg_color.mono = TEM_TEXT_WHITE;
18381253Slq150181 		}
18391253Slq150181 	} else if (tems->a_pdepth == 24 || tems->a_pdepth == 32) {
18401253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
18411253Slq150181 			ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
18421253Slq150181 			ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
18431253Slq150181 			ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
18441253Slq150181 
18451253Slq150181 			ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
18461253Slq150181 			ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
18471253Slq150181 			ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
18481253Slq150181 		} else {
18491253Slq150181 			ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
18501253Slq150181 			ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
18511253Slq150181 			ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
18521253Slq150181 
18531253Slq150181 			ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
18541253Slq150181 			ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
18551253Slq150181 			ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
18561253Slq150181 		}
18571253Slq150181 	}
18581253Slq150181 
18591253Slq150181 	ca.action = action;
18601253Slq150181 
18611253Slq150181 	tem_cursor(tem, &ca, credp, called_from);
18621253Slq150181 }
18631253Slq150181 
18641253Slq150181 #define	BORDER_PIXELS 10
18651253Slq150181 void
18661253Slq150181 set_font(struct font *f, short *rows, short *cols, short height, short width)
18671253Slq150181 {
18681253Slq150181 	bitmap_data_t	*font_selected = NULL;
18691253Slq150181 	struct fontlist	*fl;
18701253Slq150181 
18711253Slq150181 	/*
18721253Slq150181 	 * Find best font for these dimensions, or use default
18731253Slq150181 	 *
18741253Slq150181 	 * A 1 pixel border is the absolute minimum we could have
18751253Slq150181 	 * as a border around the text window (BORDER_PIXELS = 2),
18761253Slq150181 	 * however a slightly larger border not only looks better
18771253Slq150181 	 * but for the fonts currently statically built into the
18781253Slq150181 	 * emulator causes much better font selection for the
18791253Slq150181 	 * normal range of screen resolutions.
18801253Slq150181 	 */
18811253Slq150181 	for (fl = fonts; fl->data; fl++) {
18821253Slq150181 		if ((((*rows * fl->data->height) + BORDER_PIXELS) <= height) &&
18831253Slq150181 		    (((*cols * fl->data->width) + BORDER_PIXELS) <= width)) {
18841253Slq150181 			font_selected = fl->data;
18851253Slq150181 			break;
18861253Slq150181 		}
18871253Slq150181 	}
18881253Slq150181 	/*
18891253Slq150181 	 * The minus 2 is to make sure we have at least a 1 pixel
18901253Slq150181 	 * boarder around the entire screen.
18911253Slq150181 	 */
18921253Slq150181 	if (font_selected == NULL) {
18931253Slq150181 		if (((*rows * DEFAULT_FONT_DATA.height) > height) ||
18941253Slq150181 		    ((*cols * DEFAULT_FONT_DATA.width) > width)) {
18951253Slq150181 			*rows = (height - 2) / DEFAULT_FONT_DATA.height;
18961253Slq150181 			*cols = (width - 2) / DEFAULT_FONT_DATA.width;
18971253Slq150181 		}
18981253Slq150181 		font_selected = &DEFAULT_FONT_DATA;
18991253Slq150181 	}
19001253Slq150181 
19011253Slq150181 	f->width = font_selected->width;
19021253Slq150181 	f->height = font_selected->height;
19031253Slq150181 	bcopy((caddr_t)font_selected->encoding, (caddr_t)f->char_ptr,
19041253Slq150181 			sizeof (f->char_ptr));
19051253Slq150181 	f->image_data = font_selected->image;
19061253Slq150181 
19071253Slq150181 }
19081253Slq150181 
19091253Slq150181 /*
19101253Slq150181  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
19111253Slq150181  * for each 2 bits of input bitmap.  It inverts the input bits before
19121253Slq150181  * doing the output translation, for reverse video.
19131253Slq150181  *
19141253Slq150181  * Assuming foreground is 0001 and background is 0000...
19151253Slq150181  * An input data byte of 0x53 will output the bit pattern
19161253Slq150181  * 00000001 00000001 00000000 00010001.
19171253Slq150181  */
19181253Slq150181 
19191253Slq150181 void
19201253Slq150181 bit_to_pix4(
19211253Slq150181     struct tem *tem,
19221253Slq150181     uchar_t c,
19231253Slq150181     text_color_t fg_color,
19241253Slq150181     text_color_t bg_color)
19251253Slq150181 {
19261253Slq150181 	struct tem_state *tems = tem->state;
19271253Slq150181 	int	row;
19281253Slq150181 	int	byte;
19291253Slq150181 	int	i;
19301253Slq150181 	uint8_t	*cp;
19311253Slq150181 	uint8_t	data;
19321253Slq150181 	uint8_t	nibblett;
19331253Slq150181 	int	bytes_wide;
19341253Slq150181 	uint8_t *dest;
19351253Slq150181 
19361253Slq150181 	dest = (uint8_t *)tems->a_pix_data;
19371253Slq150181 
19381253Slq150181 	cp = tems->a_font.char_ptr[c];
19391253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
19401253Slq150181 
19411253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
19421253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
19431253Slq150181 			data = *cp++;
19441253Slq150181 			for (i = 0; i < 4; i++) {
19451253Slq150181 				nibblett = (data >> ((3-i) * 2)) & 0x3;
19461253Slq150181 				switch (nibblett) {
19471253Slq150181 				case 0x0:
19481253Slq150181 					*dest++ = bg_color << 4 | bg_color;
19491253Slq150181 					break;
19501253Slq150181 				case 0x1:
19511253Slq150181 					*dest++ = bg_color << 4 | fg_color;
19521253Slq150181 					break;
19531253Slq150181 				case 0x2:
19541253Slq150181 					*dest++ = fg_color << 4 | bg_color;
19551253Slq150181 					break;
19561253Slq150181 				case 0x3:
19571253Slq150181 					*dest++ = fg_color << 4 | fg_color;
19581253Slq150181 					break;
19591253Slq150181 				}
19601253Slq150181 			}
19611253Slq150181 		}
19621253Slq150181 	}
19631253Slq150181 }
19641253Slq150181 
19651253Slq150181 /*
19661253Slq150181  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
19671253Slq150181  * for each bit of input bitmap.  It inverts the input bits before
19681253Slq150181  * doing the output translation, for reverse video.
19691253Slq150181  *
19701253Slq150181  * Assuming foreground is 00000001 and background is 00000000...
19711253Slq150181  * An input data byte of 0x53 will output the bit pattern
19721253Slq150181  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
19731253Slq150181  */
19741253Slq150181 
19751253Slq150181 void
19761253Slq150181 bit_to_pix8(
19771253Slq150181     struct tem *tem,
19781253Slq150181     uchar_t c,
19791253Slq150181     text_color_t fg_color,
19801253Slq150181     text_color_t bg_color)
19811253Slq150181 {
19821253Slq150181 	struct tem_state *tems = tem->state;
19831253Slq150181 	int	row;
19841253Slq150181 	int	byte;
19851253Slq150181 	int	i;
19861253Slq150181 	uint8_t	*cp;
19871253Slq150181 	uint8_t	data;
19881253Slq150181 	int	bytes_wide;
19891253Slq150181 	uint8_t	mask;
19901253Slq150181 	int	bitsleft, nbits;
19911253Slq150181 	uint8_t *dest;
19921253Slq150181 
19931253Slq150181 	dest = (uint8_t *)tems->a_pix_data;
19941253Slq150181 
19951253Slq150181 	cp = tems->a_font.char_ptr[c];
19961253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
19971253Slq150181 
19981253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
19991253Slq150181 		bitsleft = tems->a_font.width;
20001253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
20011253Slq150181 			data = *cp++;
20021253Slq150181 			mask = 0x80;
20031253Slq150181 			nbits = MIN(8, bitsleft);
20041253Slq150181 			bitsleft -= nbits;
20051253Slq150181 			for (i = 0; i < nbits; i++) {
20061253Slq150181 				*dest++ = (data & mask ? fg_color: bg_color);
20071253Slq150181 				mask = mask >> 1;
20081253Slq150181 			}
20091253Slq150181 		}
20101253Slq150181 	}
20111253Slq150181 }
20121253Slq150181 
20131253Slq150181 /*
20141253Slq150181  * bit_to_pix24 is for 24-bit frame buffers.  It will write four output bytes
20151253Slq150181  * for each bit of input bitmap.  It inverts the input bits before
20161253Slq150181  * doing the output translation, for reverse video.  Note that each
20171253Slq150181  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
20181253Slq150181  * high-order byte set to zero.
20191253Slq150181  *
20201253Slq150181  * Assuming foreground is 00000000 11111111 11111111 11111111
20211253Slq150181  * and background is 00000000 00000000 00000000 00000000
20221253Slq150181  * An input data byte of 0x53 will output the bit pattern
20231253Slq150181  *
20241253Slq150181  * 00000000 00000000 00000000 00000000
20251253Slq150181  * 00000000 11111111 11111111 11111111
20261253Slq150181  * 00000000 00000000 00000000 00000000
20271253Slq150181  * 00000000 11111111 11111111 11111111
20281253Slq150181  * 00000000 00000000 00000000 00000000
20291253Slq150181  * 00000000 00000000 00000000 00000000
20301253Slq150181  * 00000000 11111111 11111111 11111111
20311253Slq150181  * 00000000 11111111 11111111 11111111
20321253Slq150181  *
20331253Slq150181  */
20341253Slq150181 typedef uint32_t pixel32_t;
20351253Slq150181 
20361253Slq150181 void
20371253Slq150181 bit_to_pix24(
20381253Slq150181 	struct tem *tem,
20391253Slq150181 	uchar_t c,
20401253Slq150181 	text_color_t fg_color4,
20411253Slq150181 	text_color_t bg_color4)
20421253Slq150181 {
20431253Slq150181 	struct tem_state *tems = tem->state;
20441253Slq150181 	int	row;
20451253Slq150181 	int	byte;
20461253Slq150181 	int	i;
20471253Slq150181 	uint8_t	*cp;
20481253Slq150181 	uint8_t	data;
20491253Slq150181 	int	bytes_wide;
20501253Slq150181 	int	bitsleft, nbits;
20511253Slq150181 
20521253Slq150181 	pixel32_t fg_color32, bg_color32, *destp;
20531253Slq150181 
20541253Slq150181 	ASSERT(fg_color4 < 16 && bg_color4 < 16);
20551253Slq150181 
20561253Slq150181 	fg_color32 = PIX4TO32(fg_color4);
20571253Slq150181 	bg_color32 = PIX4TO32(bg_color4);
20581253Slq150181 
20591253Slq150181 	destp = (pixel32_t *)tems->a_pix_data;
20601253Slq150181 	cp = tems->a_font.char_ptr[c];
20611253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
20621253Slq150181 
20631253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
20641253Slq150181 		bitsleft = tems->a_font.width;
20651253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
20661253Slq150181 			data = *cp++;
20671253Slq150181 			nbits = MIN(8, bitsleft);
20681253Slq150181 			bitsleft -= nbits;
20691253Slq150181 			for (i = 0; i < nbits; i++) {
20701253Slq150181 			    *destp++ = ((data << i) & 0x80 ?
20711253Slq150181 				fg_color32 : bg_color32);
20721253Slq150181 			}
20731253Slq150181 		}
20741253Slq150181 	}
20751253Slq150181 }
20761253Slq150181 
20771253Slq150181 /* ARGSUSED */
20781253Slq150181 text_color_t
20791253Slq150181 ansi_bg_to_solaris(struct tem *tem, int ansi)
20801253Slq150181 {
20811253Slq150181 	return (bg_xlate[ansi]);
20821253Slq150181 }
20831253Slq150181 
20841253Slq150181 text_color_t
20851253Slq150181 ansi_fg_to_solaris(struct tem *tem, int ansi)
20861253Slq150181 {
20871253Slq150181 	if (tem->state->a_flags & TEM_ATTR_BOLD)
20881253Slq150181 	    return (fg_brt_xlate[ansi]);
20891253Slq150181 	else
20901253Slq150181 	    return (fg_dim_xlate[ansi]);
20911253Slq150181 }
20921253Slq150181 
20931253Slq150181 static void
20941253Slq150181 tem_get_color(struct tem *tem, text_color_t *fg, text_color_t *bg)
20951253Slq150181 {
20961253Slq150181 	if (tem->state->a_flags & TEM_ATTR_SCREEN_REVERSE) {
20971253Slq150181 		*fg = ansi_fg_to_solaris(tem,
20981253Slq150181 		    DEFAULT_ANSI_BACKGROUND);
20991253Slq150181 		*bg = ansi_bg_to_solaris(tem,
21001253Slq150181 		    DEFAULT_ANSI_FOREGROUND);
21011253Slq150181 	} else {
21021253Slq150181 		*fg = ansi_fg_to_solaris(tem,
21031253Slq150181 		    DEFAULT_ANSI_FOREGROUND);
21041253Slq150181 		*bg = ansi_bg_to_solaris(tem,
21051253Slq150181 		    DEFAULT_ANSI_BACKGROUND);
21061253Slq150181 	}
21071253Slq150181 }
21081253Slq150181 
21091253Slq150181 /*
21101253Slq150181  * Clear a rectangle of screen for pixel mode.
21111253Slq150181  *
21121253Slq150181  * arguments:
21131253Slq150181  *    row:	start row#
21141253Slq150181  *    nrows:	the number of rows to clear
21151253Slq150181  *    offset_y:	the offset of height in pixels to begin clear
21161253Slq150181  *    col:	start col#
21171253Slq150181  *    ncols:	the number of cols to clear
21181253Slq150181  *    offset_x:	the offset of width in pixels to begin clear
21191253Slq150181  *    scroll_up: whether this function is called during sroll up,
21201253Slq150181  *		 which is called only once.
21211253Slq150181  */
21221253Slq150181 void
21231253Slq150181 tem_pix_cls_range(tem_t *tem,
21241253Slq150181 	screen_pos_t row, int nrows, int offset_y,
21251253Slq150181 	screen_pos_t col, int ncols, int offset_x,
21261253Slq150181 	boolean_t sroll_up, cred_t *credp,
21271253Slq150181 	enum called_from called_from)
21281253Slq150181 {
21291253Slq150181 	struct tem_state *tems = tem->state;
21301253Slq150181 	struct vis_consdisplay da;
21311253Slq150181 	int	i, j;
21321253Slq150181 	int	row_add = 0;
21331253Slq150181 	text_color_t fg_color;
21341253Slq150181 	text_color_t bg_color;
21351253Slq150181 
21361253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
21371253Slq150181 	    MUTEX_HELD(&tem->lock));
21381253Slq150181 
21391253Slq150181 	if (sroll_up)
21401253Slq150181 		row_add = tems->a_c_dimension.height - 1;
21411253Slq150181 
21421253Slq150181 	da.width = tems->a_font.width;
21431253Slq150181 	da.height = tems->a_font.height;
21441253Slq150181 
21451253Slq150181 	tem_get_color(tem, &fg_color, &bg_color);
21461253Slq150181 
21471253Slq150181 	BIT_TO_PIX(tem, ' ', fg_color, bg_color);
21481253Slq150181 	da.data = (uchar_t *)tems->a_pix_data;
21491253Slq150181 
21501253Slq150181 	for (i = 0; i < nrows; i++, row++) {
21511253Slq150181 		da.row = (row + row_add) * da.height + offset_y;
21521253Slq150181 		da.col = col * da.width + offset_x;
21531253Slq150181 		for (j = 0; j < ncols; j++) {
21541253Slq150181 			tem_display(tem, &da, credp, called_from);
21551253Slq150181 			da.col += da.width;
21561253Slq150181 		}
21571253Slq150181 	}
21581253Slq150181 }
2159