xref: /onnv-gate/usr/src/uts/common/io/tem_safe.c (revision 1253)
1*1253Slq150181 /*
2*1253Slq150181  * CDDL HEADER START
3*1253Slq150181  *
4*1253Slq150181  * The contents of this file are subject to the terms of the
5*1253Slq150181  * Common Development and Distribution License (the "License").
6*1253Slq150181  * You may not use this file except in compliance with the License.
7*1253Slq150181  *
8*1253Slq150181  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1253Slq150181  * or http://www.opensolaris.org/os/licensing.
10*1253Slq150181  * See the License for the specific language governing permissions
11*1253Slq150181  * and limitations under the License.
12*1253Slq150181  *
13*1253Slq150181  * When distributing Covered Code, include this CDDL HEADER in each
14*1253Slq150181  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1253Slq150181  * If applicable, add the following below this CDDL HEADER, with the
16*1253Slq150181  * fields enclosed by brackets "[]" replaced with your own identifying
17*1253Slq150181  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1253Slq150181  *
19*1253Slq150181  * CDDL HEADER END
20*1253Slq150181  */
21*1253Slq150181 
22*1253Slq150181 /*
23*1253Slq150181  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1253Slq150181  * Use is subject to license terms.
25*1253Slq150181  */
26*1253Slq150181 
27*1253Slq150181 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1253Slq150181 
29*1253Slq150181 /*
30*1253Slq150181  * Polled I/O safe ANSI terminal emulator module;
31*1253Slq150181  * Supporting TERM types 'sun' and 'sun-color, parsing
32*1253Slq150181  * ANSI x3.64 escape sequences, and the like.  (See wscons(7d)
33*1253Slq150181  * for more information).
34*1253Slq150181  *
35*1253Slq150181  * IMPORTANT:
36*1253Slq150181  *
37*1253Slq150181  *   The functions in this file *must* be able to function in
38*1253Slq150181  *   standalone mode, ie. on a quiesced system.   In that state,
39*1253Slq150181  *   access is single threaded, only one CPU is running.
40*1253Slq150181  *   System services are NOT available.
41*1253Slq150181  *
42*1253Slq150181  * The following restrictions pertain to every function
43*1253Slq150181  * in this file:
44*1253Slq150181  *
45*1253Slq150181  *     - CANNOT use the DDI or LDI interfaces
46*1253Slq150181  *     - CANNOT call system services
47*1253Slq150181  *     - CANNOT use mutexes
48*1253Slq150181  *     - CANNOT wait for interrupts
49*1253Slq150181  *     - CANNOT allocate memory
50*1253Slq150181  *
51*1253Slq150181  */
52*1253Slq150181 
53*1253Slq150181 #include <sys/types.h>
54*1253Slq150181 #include <sys/ascii.h>
55*1253Slq150181 #include <sys/visual_io.h>
56*1253Slq150181 #include <sys/font.h>
57*1253Slq150181 #include <sys/tem.h>
58*1253Slq150181 #include <sys/tem_impl.h>
59*1253Slq150181 #include <sys/ksynch.h>
60*1253Slq150181 #include <sys/sysmacros.h>
61*1253Slq150181 #include <sys/mutex.h>
62*1253Slq150181 
63*1253Slq150181 static void	tem_display(struct tem *,
64*1253Slq150181 			struct vis_consdisplay *,
65*1253Slq150181 			cred_t *, enum called_from);
66*1253Slq150181 static void	tem_cursor(struct tem *,
67*1253Slq150181 			struct vis_conscursor *,
68*1253Slq150181 			cred_t *, enum called_from);
69*1253Slq150181 static void	tem_control(struct tem *, uchar_t,
70*1253Slq150181 			cred_t *, enum called_from);
71*1253Slq150181 static void	tem_setparam(struct tem *, int, int);
72*1253Slq150181 static void	tem_selgraph(struct tem *);
73*1253Slq150181 static void	tem_chkparam(struct tem *, uchar_t,
74*1253Slq150181 			cred_t *, enum called_from);
75*1253Slq150181 static void	tem_getparams(struct tem *, uchar_t,
76*1253Slq150181 			cred_t *, enum called_from);
77*1253Slq150181 static void	tem_outch(struct tem *, uchar_t,
78*1253Slq150181 			cred_t *, enum called_from);
79*1253Slq150181 static void	tem_parse(struct tem *, uchar_t,
80*1253Slq150181 			cred_t *, enum called_from);
81*1253Slq150181 
82*1253Slq150181 static void	tem_new_line(struct tem *,
83*1253Slq150181 			cred_t *, enum called_from);
84*1253Slq150181 static void	tem_cr(struct tem *);
85*1253Slq150181 static void	tem_lf(struct tem *,
86*1253Slq150181 			cred_t *, enum called_from);
87*1253Slq150181 static void	tem_send_data(struct tem *, cred_t *,
88*1253Slq150181 			enum called_from);
89*1253Slq150181 static void	tem_cls(struct tem *,
90*1253Slq150181 			cred_t *, enum called_from);
91*1253Slq150181 static void	tem_tab(struct tem *,
92*1253Slq150181 			cred_t *, enum called_from);
93*1253Slq150181 static void	tem_back_tab(struct tem *,
94*1253Slq150181 			cred_t *, enum called_from);
95*1253Slq150181 static void	tem_clear_tabs(struct tem *, int);
96*1253Slq150181 static void	tem_set_tab(struct tem *);
97*1253Slq150181 static void	tem_mv_cursor(struct tem *, int, int,
98*1253Slq150181 			cred_t *, enum called_from);
99*1253Slq150181 static void	tem_shift(struct tem *, int, int,
100*1253Slq150181 			cred_t *, enum called_from);
101*1253Slq150181 static void	tem_scroll(struct tem *, int, int,
102*1253Slq150181 			int, int, cred_t *, enum called_from);
103*1253Slq150181 static void	tem_clear_chars(struct tem *tem,
104*1253Slq150181 			int count, screen_pos_t row, screen_pos_t col,
105*1253Slq150181 			cred_t *credp, enum called_from called_from);
106*1253Slq150181 static void	tem_copy_area(struct tem *tem,
107*1253Slq150181 			screen_pos_t s_col, screen_pos_t s_row,
108*1253Slq150181 			screen_pos_t e_col, screen_pos_t e_row,
109*1253Slq150181 			screen_pos_t t_col, screen_pos_t t_row,
110*1253Slq150181 			cred_t *credp, enum called_from called_from);
111*1253Slq150181 static void	tem_image_display(struct tem *, uchar_t *,
112*1253Slq150181 			int, int, screen_pos_t, screen_pos_t,
113*1253Slq150181 			cred_t *, enum called_from);
114*1253Slq150181 static void	tem_bell(struct tem *tem,
115*1253Slq150181 			enum called_from called_from);
116*1253Slq150181 static void	tem_get_color(struct tem *tem,
117*1253Slq150181 			text_color_t *fg, text_color_t *bg);
118*1253Slq150181 static void	tem_pix_clear_prom_output(struct tem *tem,
119*1253Slq150181 			cred_t *credp, enum called_from called_from);
120*1253Slq150181 
121*1253Slq150181 #ifdef _HAVE_TEM_FIRMWARE
122*1253Slq150181 #define	DEFAULT_ANSI_FOREGROUND	ANSI_COLOR_BLACK
123*1253Slq150181 #define	DEFAULT_ANSI_BACKGROUND	ANSI_COLOR_WHITE
124*1253Slq150181 #else /* _HAVE_TEM_FIRMWARE */
125*1253Slq150181 #define	DEFAULT_ANSI_FOREGROUND	ANSI_COLOR_WHITE
126*1253Slq150181 #define	DEFAULT_ANSI_BACKGROUND	ANSI_COLOR_BLACK
127*1253Slq150181 #endif
128*1253Slq150181 
129*1253Slq150181 
130*1253Slq150181 /* BEGIN CSTYLED */
131*1253Slq150181 /*                                      Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
132*1253Slq150181 static text_color_t fg_dim_xlate[] = {  1,  5,  3,  7,  2,  6,  4,  8 };
133*1253Slq150181 static text_color_t fg_brt_xlate[] = {  9, 13, 11, 15, 10, 14, 12,  0 };
134*1253Slq150181 static text_color_t bg_xlate[] = {      1,  5,  3,  7,  2,  6,  4,  0 };
135*1253Slq150181 /* END CSTYLED */
136*1253Slq150181 
137*1253Slq150181 
138*1253Slq150181 text_cmap_t cmap4_to_24 = {
139*1253Slq150181 /* BEGIN CSTYLED */
140*1253Slq150181 /* 0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
141*1253Slq150181   Wh+  Bk   Bl   Gr   Cy   Rd   Mg   Br   Wh   Bk+  Bl+  Gr+  Cy+  Rd+  Mg+  Yw */
142*1253Slq150181   0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
143*1253Slq150181   0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
144*1253Slq150181   0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
145*1253Slq150181 /* END CSTYLED */
146*1253Slq150181 };
147*1253Slq150181 
148*1253Slq150181 #define	PIX4TO32(pix4) (pixel32_t)(  \
149*1253Slq150181     cmap4_to_24.red[pix4] << 16 |  \
150*1253Slq150181     cmap4_to_24.green[pix4] << 8 | \
151*1253Slq150181     cmap4_to_24.blue[pix4])
152*1253Slq150181 
153*1253Slq150181 /*
154*1253Slq150181  * Fonts are statically linked with this module. At some point an
155*1253Slq150181  * RFE might be desireable to allow dynamic font loading.  The
156*1253Slq150181  * original intention to facilitate dynamic fonts can be seen
157*1253Slq150181  * by examining the data structures and set_font().  As much of
158*1253Slq150181  * the original code is retained but modified to be suited to
159*1253Slq150181  * traversing a list of static fonts.
160*1253Slq150181  */
161*1253Slq150181 extern struct fontlist fonts[];
162*1253Slq150181 
163*1253Slq150181 #define	DEFAULT_FONT_DATA font_data_12x22
164*1253Slq150181 
165*1253Slq150181 extern bitmap_data_t font_data_12x22;
166*1253Slq150181 extern bitmap_data_t font_data_7x14;
167*1253Slq150181 extern bitmap_data_t font_data_6x10;
168*1253Slq150181 /*
169*1253Slq150181  * Must be sorted by font size in descending order
170*1253Slq150181  */
171*1253Slq150181 struct fontlist fonts[] = {
172*1253Slq150181 	{  &font_data_12x22,	NULL  },
173*1253Slq150181 	{  &font_data_7x14,	NULL  },
174*1253Slq150181 	{  &font_data_6x10,	NULL  },
175*1253Slq150181 	{  NULL, NULL  }
176*1253Slq150181 };
177*1253Slq150181 
178*1253Slq150181 #define	INVERSE(ch) (ch ^ 0xff)
179*1253Slq150181 
180*1253Slq150181 #define	BIT_TO_PIX(tem, c, fg, bg)	{				\
181*1253Slq150181 	ASSERT((tem)->state->in_fp.f_bit2pix != NULL); 			\
182*1253Slq150181 	(void) (*(tem)->state->in_fp.f_bit2pix)((tem), (c), (fg), (bg));\
183*1253Slq150181 }
184*1253Slq150181 
185*1253Slq150181 void
186*1253Slq150181 tem_check_first_time(
187*1253Slq150181     struct tem *tem,
188*1253Slq150181     cred_t *credp,
189*1253Slq150181     enum called_from called_from)
190*1253Slq150181 {
191*1253Slq150181 	static int first_time = 1;
192*1253Slq150181 
193*1253Slq150181 	/*
194*1253Slq150181 	 * Realign the console cursor. We did this in tem_init().
195*1253Slq150181 	 * However, drivers in the console stream may emit additional
196*1253Slq150181 	 * messages before we are ready. This causes text overwrite
197*1253Slq150181 	 * on the screen. This is a workaround.
198*1253Slq150181 	 */
199*1253Slq150181 	if (first_time && tem->state->display_mode == VIS_TEXT) {
200*1253Slq150181 		tem_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
201*1253Slq150181 		tem_align_cursor(tem);
202*1253Slq150181 	}
203*1253Slq150181 	first_time = 0;
204*1253Slq150181 
205*1253Slq150181 }
206*1253Slq150181 
207*1253Slq150181 /*
208*1253Slq150181  * This entry point handles output requests from restricted contexts like
209*1253Slq150181  * kmdb, where services like mutexes are not available. This function
210*1253Slq150181  * is entered when OBP or when a kernel debugger (such as kmdb)
211*1253Slq150181  * are generating console output.  In those cases, power management
212*1253Slq150181  * concerns are handled by the abort sequence initiation (ie. when
213*1253Slq150181  * the user hits L1+A or the equivalent to enter OBP or the debugger.).
214*1253Slq150181  * It is also entered when the kernel is panicing.
215*1253Slq150181  */
216*1253Slq150181 void
217*1253Slq150181 tem_polled_write(
218*1253Slq150181     struct tem *tem,
219*1253Slq150181     uchar_t *buf,
220*1253Slq150181     int len)
221*1253Slq150181 {
222*1253Slq150181 
223*1253Slq150181 	ASSERT(tem->hdl != NULL);
224*1253Slq150181 
225*1253Slq150181 	tem_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
226*1253Slq150181 	tem_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
227*1253Slq150181 }
228*1253Slq150181 
229*1253Slq150181 
230*1253Slq150181 /*
231*1253Slq150181  * This is the main entry point into the terminal emulator.
232*1253Slq150181  *
233*1253Slq150181  * For each data message coming downstream, ANSI assumes that it is composed
234*1253Slq150181  * of ASCII characters, which are treated as a byte-stream input to the
235*1253Slq150181  * parsing state machine. All data is parsed immediately -- there is
236*1253Slq150181  * no enqueing.
237*1253Slq150181  */
238*1253Slq150181 void
239*1253Slq150181 tem_terminal_emulate(
240*1253Slq150181     struct tem *tem,
241*1253Slq150181     uchar_t *buf,
242*1253Slq150181     int len,
243*1253Slq150181     cred_t *credp,
244*1253Slq150181     enum called_from called_from)
245*1253Slq150181 {
246*1253Slq150181 	struct tem_state	*tems = tem->state;
247*1253Slq150181 
248*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
249*1253Slq150181 	    MUTEX_HELD(&tem->lock));
250*1253Slq150181 
251*1253Slq150181 	(*tems->in_fp.f_cursor)
252*1253Slq150181 	    (tem, VIS_HIDE_CURSOR, credp, called_from);
253*1253Slq150181 
254*1253Slq150181 	for (; len > 0; len--, buf++) {
255*1253Slq150181 		tem_parse(tem, *buf, credp, called_from);
256*1253Slq150181 	}
257*1253Slq150181 
258*1253Slq150181 	/*
259*1253Slq150181 	 * Send the data we just got to the framebuffer.
260*1253Slq150181 	 */
261*1253Slq150181 	tem_send_data(tem, credp, called_from);
262*1253Slq150181 
263*1253Slq150181 	(*tems->in_fp.f_cursor)
264*1253Slq150181 	    (tem, VIS_DISPLAY_CURSOR, credp, called_from);
265*1253Slq150181 }
266*1253Slq150181 
267*1253Slq150181 /*
268*1253Slq150181  * Display an rectangular image on the frame buffer using the
269*1253Slq150181  * mechanism appropriate for the system state being called
270*1253Slq150181  * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
271*1253Slq150181  */
272*1253Slq150181 static void
273*1253Slq150181 tem_display(
274*1253Slq150181 	struct tem *tem,
275*1253Slq150181 	struct vis_consdisplay *pda,
276*1253Slq150181 	cred_t *credp,
277*1253Slq150181 	enum called_from called_from)
278*1253Slq150181 {
279*1253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
280*1253Slq150181 		tem->fb_polledio->display(tem->fb_polledio->arg, pda);
281*1253Slq150181 	else
282*1253Slq150181 		tem_display_layered(tem, pda, credp);
283*1253Slq150181 }
284*1253Slq150181 
285*1253Slq150181 /*
286*1253Slq150181  * Copy a rectangle from one location to another on the frame buffer
287*1253Slq150181  * using the mechanism appropriate for the system state being called
288*1253Slq150181  * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
289*1253Slq150181  */
290*1253Slq150181 void
291*1253Slq150181 tem_copy(
292*1253Slq150181 	struct tem *tem,
293*1253Slq150181 	struct vis_conscopy *pca,
294*1253Slq150181 	cred_t *credp,
295*1253Slq150181 	enum called_from called_from)
296*1253Slq150181 {
297*1253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
298*1253Slq150181 		tem->fb_polledio->copy(tem->fb_polledio->arg, pca);
299*1253Slq150181 	else
300*1253Slq150181 		tem_copy_layered(tem, pca, credp);
301*1253Slq150181 }
302*1253Slq150181 
303*1253Slq150181 /*
304*1253Slq150181  * Display or hide a rectangular block text cursor of a specificsize
305*1253Slq150181  * at a specific location on frame buffer* using the mechanism
306*1253Slq150181  * appropriate for the system state being called from, quisced or
307*1253Slq150181  * normal (ie. use polled I/O vs. layered ioctls).
308*1253Slq150181  */
309*1253Slq150181 static void
310*1253Slq150181 tem_cursor(
311*1253Slq150181 	struct tem *tem,
312*1253Slq150181 	struct vis_conscursor *pca,
313*1253Slq150181 	cred_t *credp,
314*1253Slq150181 	enum called_from called_from)
315*1253Slq150181 {
316*1253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
317*1253Slq150181 		tem->fb_polledio->cursor(tem->fb_polledio->arg, pca);
318*1253Slq150181 	else
319*1253Slq150181 		tem_cursor_layered(tem, pca, credp);
320*1253Slq150181 }
321*1253Slq150181 
322*1253Slq150181 /*
323*1253Slq150181  * send the appropriate control message or set state based on the
324*1253Slq150181  * value of the control character ch
325*1253Slq150181  */
326*1253Slq150181 
327*1253Slq150181 static void
328*1253Slq150181 tem_control(
329*1253Slq150181 	struct tem *tem,
330*1253Slq150181 	uchar_t ch,
331*1253Slq150181 	cred_t *credp,
332*1253Slq150181 	enum called_from called_from)
333*1253Slq150181 {
334*1253Slq150181 	struct tem_state	*tems = tem->state;
335*1253Slq150181 
336*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
337*1253Slq150181 	    MUTEX_HELD(&tem->lock));
338*1253Slq150181 
339*1253Slq150181 	tems->a_state = A_STATE_START;
340*1253Slq150181 	switch (ch) {
341*1253Slq150181 	case A_BEL:
342*1253Slq150181 		tem_bell(tem, called_from);
343*1253Slq150181 		break;
344*1253Slq150181 
345*1253Slq150181 	case A_BS:
346*1253Slq150181 		tem_mv_cursor(tem,
347*1253Slq150181 		    tems->a_c_cursor.row,
348*1253Slq150181 		    tems->a_c_cursor.col - 1,
349*1253Slq150181 		    credp, called_from);
350*1253Slq150181 		break;
351*1253Slq150181 
352*1253Slq150181 	case A_HT:
353*1253Slq150181 		tem_tab(tem, credp, called_from);
354*1253Slq150181 		break;
355*1253Slq150181 
356*1253Slq150181 	case A_NL:
357*1253Slq150181 		/*
358*1253Slq150181 		 * tem_send_data(tem, credp, called_from);
359*1253Slq150181 		 * tem_new_line(tem, credp, called_from);
360*1253Slq150181 		 * break;
361*1253Slq150181 		 */
362*1253Slq150181 
363*1253Slq150181 	case A_VT:
364*1253Slq150181 		tem_send_data(tem, credp, called_from);
365*1253Slq150181 		tem_lf(tem, credp, called_from);
366*1253Slq150181 		break;
367*1253Slq150181 
368*1253Slq150181 	case A_FF:
369*1253Slq150181 		tem_send_data(tem, credp, called_from);
370*1253Slq150181 		tem_cls(tem, credp, called_from);
371*1253Slq150181 		break;
372*1253Slq150181 
373*1253Slq150181 	case A_CR:
374*1253Slq150181 		tem_send_data(tem, credp, called_from);
375*1253Slq150181 		tem_cr(tem);
376*1253Slq150181 		break;
377*1253Slq150181 
378*1253Slq150181 	case A_ESC:
379*1253Slq150181 		tems->a_state = A_STATE_ESC;
380*1253Slq150181 		break;
381*1253Slq150181 
382*1253Slq150181 	case A_CSI:
383*1253Slq150181 		{
384*1253Slq150181 			int i;
385*1253Slq150181 			tems->a_curparam = 0;
386*1253Slq150181 			tems->a_paramval = 0;
387*1253Slq150181 			tems->a_gotparam = B_FALSE;
388*1253Slq150181 			/* clear the parameters */
389*1253Slq150181 			for (i = 0; i < TEM_MAXPARAMS; i++)
390*1253Slq150181 				tems->a_params[i] = -1;
391*1253Slq150181 			tems->a_state = A_STATE_CSI;
392*1253Slq150181 		}
393*1253Slq150181 		break;
394*1253Slq150181 
395*1253Slq150181 	case A_GS:
396*1253Slq150181 		tem_back_tab(tem, credp, called_from);
397*1253Slq150181 		break;
398*1253Slq150181 
399*1253Slq150181 	default:
400*1253Slq150181 		break;
401*1253Slq150181 	}
402*1253Slq150181 }
403*1253Slq150181 
404*1253Slq150181 
405*1253Slq150181 /*
406*1253Slq150181  * if parameters [0..count - 1] are not set, set them to the value
407*1253Slq150181  * of newparam.
408*1253Slq150181  */
409*1253Slq150181 
410*1253Slq150181 static void
411*1253Slq150181 tem_setparam(struct tem *tem, int count, int newparam)
412*1253Slq150181 {
413*1253Slq150181 	int i;
414*1253Slq150181 
415*1253Slq150181 	for (i = 0; i < count; i++) {
416*1253Slq150181 		if (tem->state->a_params[i] == -1)
417*1253Slq150181 			tem->state->a_params[i] = newparam;
418*1253Slq150181 	}
419*1253Slq150181 }
420*1253Slq150181 
421*1253Slq150181 
422*1253Slq150181 /*
423*1253Slq150181  * select graphics mode based on the param vals stored in a_params
424*1253Slq150181  */
425*1253Slq150181 static void
426*1253Slq150181 tem_selgraph(struct tem *tem)
427*1253Slq150181 {
428*1253Slq150181 	struct tem_state *tems = tem->state;
429*1253Slq150181 	int curparam;
430*1253Slq150181 	int count = 0;
431*1253Slq150181 	int param;
432*1253Slq150181 
433*1253Slq150181 	curparam = tems->a_curparam;
434*1253Slq150181 	do {
435*1253Slq150181 		param = tems->a_params[count];
436*1253Slq150181 
437*1253Slq150181 		switch (param) {
438*1253Slq150181 		case -1:
439*1253Slq150181 		case 0:
440*1253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
441*1253Slq150181 				tems->a_flags |= TEM_ATTR_REVERSE;
442*1253Slq150181 			} else {
443*1253Slq150181 				tems->a_flags &= ~TEM_ATTR_REVERSE;
444*1253Slq150181 			}
445*1253Slq150181 			tems->a_flags &= ~TEM_ATTR_BOLD;
446*1253Slq150181 			tems->a_flags &= ~TEM_ATTR_BLINK;
447*1253Slq150181 			tems->fg_color = DEFAULT_ANSI_FOREGROUND;
448*1253Slq150181 			tems->bg_color = DEFAULT_ANSI_BACKGROUND;
449*1253Slq150181 			break;
450*1253Slq150181 
451*1253Slq150181 		case 1: /* Bold Intense */
452*1253Slq150181 			tems->a_flags |= TEM_ATTR_BOLD;
453*1253Slq150181 			break;
454*1253Slq150181 
455*1253Slq150181 		case 5: /* Blink */
456*1253Slq150181 			tems->a_flags |= TEM_ATTR_BLINK;
457*1253Slq150181 			break;
458*1253Slq150181 
459*1253Slq150181 		case 7: /* Reverse video */
460*1253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
461*1253Slq150181 				tems->a_flags &= ~TEM_ATTR_REVERSE;
462*1253Slq150181 			} else {
463*1253Slq150181 				tems->a_flags |= TEM_ATTR_REVERSE;
464*1253Slq150181 			}
465*1253Slq150181 			break;
466*1253Slq150181 
467*1253Slq150181 		case 30: /* black	(grey) 		foreground */
468*1253Slq150181 		case 31: /* red		(light red) 	foreground */
469*1253Slq150181 		case 32: /* green	(light green) 	foreground */
470*1253Slq150181 		case 33: /* brown	(yellow) 	foreground */
471*1253Slq150181 		case 34: /* blue	(light blue) 	foreground */
472*1253Slq150181 		case 35: /* magenta	(light magenta) foreground */
473*1253Slq150181 		case 36: /* cyan	(light cyan) 	foreground */
474*1253Slq150181 		case 37: /* white	(bright white) 	foreground */
475*1253Slq150181 			tems->fg_color = param - 30;
476*1253Slq150181 			break;
477*1253Slq150181 
478*1253Slq150181 		case 40: /* black	(grey) 		background */
479*1253Slq150181 		case 41: /* red		(light red) 	background */
480*1253Slq150181 		case 42: /* green	(light green) 	background */
481*1253Slq150181 		case 43: /* brown	(yellow) 	background */
482*1253Slq150181 		case 44: /* blue	(light blue) 	background */
483*1253Slq150181 		case 45: /* magenta	(light magenta) background */
484*1253Slq150181 		case 46: /* cyan	(light cyan) 	background */
485*1253Slq150181 		case 47: /* white	(bright white) 	background */
486*1253Slq150181 			tems->bg_color = param - 40;
487*1253Slq150181 			break;
488*1253Slq150181 
489*1253Slq150181 		default:
490*1253Slq150181 			break;
491*1253Slq150181 		}
492*1253Slq150181 		count++;
493*1253Slq150181 		curparam--;
494*1253Slq150181 
495*1253Slq150181 	} while (curparam > 0);
496*1253Slq150181 
497*1253Slq150181 
498*1253Slq150181 	tems->a_state = A_STATE_START;
499*1253Slq150181 }
500*1253Slq150181 
501*1253Slq150181 /*
502*1253Slq150181  * perform the appropriate action for the escape sequence
503*1253Slq150181  *
504*1253Slq150181  * General rule:  This code does not validate the arguments passed.
505*1253Slq150181  *                It assumes that the next lower level will do so.
506*1253Slq150181  */
507*1253Slq150181 static void
508*1253Slq150181 tem_chkparam(
509*1253Slq150181 	struct tem *tem,
510*1253Slq150181 	uchar_t ch,
511*1253Slq150181 	cred_t *credp,
512*1253Slq150181 	enum called_from called_from)
513*1253Slq150181 {
514*1253Slq150181 	struct tem_state *tems = tem->state;
515*1253Slq150181 	int	i;
516*1253Slq150181 	int	row;
517*1253Slq150181 	int	col;
518*1253Slq150181 
519*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
520*1253Slq150181 	    MUTEX_HELD(&tem->lock));
521*1253Slq150181 
522*1253Slq150181 	row = tems->a_c_cursor.row;
523*1253Slq150181 	col = tems->a_c_cursor.col;
524*1253Slq150181 
525*1253Slq150181 	switch (ch) {
526*1253Slq150181 
527*1253Slq150181 	case 'm': /* select terminal graphics mode */
528*1253Slq150181 		tem_send_data(tem, credp, called_from);
529*1253Slq150181 		tem_selgraph(tem);
530*1253Slq150181 		break;
531*1253Slq150181 
532*1253Slq150181 	case '@':		/* insert char */
533*1253Slq150181 		tem_setparam(tem, 1, 1);
534*1253Slq150181 		tem_shift(tem, tems->a_params[0], TEM_SHIFT_RIGHT,
535*1253Slq150181 		    credp, called_from);
536*1253Slq150181 		break;
537*1253Slq150181 
538*1253Slq150181 	case 'A':		/* cursor up */
539*1253Slq150181 		tem_setparam(tem, 1, 1);
540*1253Slq150181 		tem_mv_cursor(tem, row - tems->a_params[0], col,
541*1253Slq150181 		    credp, called_from);
542*1253Slq150181 		break;
543*1253Slq150181 
544*1253Slq150181 	case 'd':		/* VPA - vertical position absolute */
545*1253Slq150181 		tem_setparam(tem, 1, 1);
546*1253Slq150181 		tem_mv_cursor(tem, tems->a_params[0] - 1, col,
547*1253Slq150181 		    credp, called_from);
548*1253Slq150181 		break;
549*1253Slq150181 
550*1253Slq150181 	case 'e':		/* VPR - vertical position relative */
551*1253Slq150181 	case 'B':		/* cursor down */
552*1253Slq150181 		tem_setparam(tem, 1, 1);
553*1253Slq150181 		tem_mv_cursor(tem, row + tems->a_params[0], col,
554*1253Slq150181 		    credp, called_from);
555*1253Slq150181 		break;
556*1253Slq150181 
557*1253Slq150181 	case 'a':		/* HPR - horizontal position relative */
558*1253Slq150181 	case 'C':		/* cursor right */
559*1253Slq150181 		tem_setparam(tem, 1, 1);
560*1253Slq150181 		tem_mv_cursor(tem, row, col + tems->a_params[0],
561*1253Slq150181 		    credp, called_from);
562*1253Slq150181 		break;
563*1253Slq150181 
564*1253Slq150181 	case '`':		/* HPA - horizontal position absolute */
565*1253Slq150181 		tem_setparam(tem, 1, 1);
566*1253Slq150181 		tem_mv_cursor(tem, row, tems->a_params[0] - 1,
567*1253Slq150181 		    credp, called_from);
568*1253Slq150181 		break;
569*1253Slq150181 
570*1253Slq150181 	case 'D':		/* cursor left */
571*1253Slq150181 		tem_setparam(tem, 1, 1);
572*1253Slq150181 		tem_mv_cursor(tem, row, col - tems->a_params[0],
573*1253Slq150181 		    credp, called_from);
574*1253Slq150181 		break;
575*1253Slq150181 
576*1253Slq150181 	case 'E':		/* CNL cursor next line */
577*1253Slq150181 		tem_setparam(tem, 1, 1);
578*1253Slq150181 		tem_mv_cursor(tem, row + tems->a_params[0], 0,
579*1253Slq150181 		    credp, called_from);
580*1253Slq150181 		break;
581*1253Slq150181 
582*1253Slq150181 	case 'F':		/* CPL cursor previous line */
583*1253Slq150181 		tem_setparam(tem, 1, 1);
584*1253Slq150181 		tem_mv_cursor(tem, row - tems->a_params[0], 0,
585*1253Slq150181 		    credp, called_from);
586*1253Slq150181 		break;
587*1253Slq150181 
588*1253Slq150181 	case 'G':		/* cursor horizontal position */
589*1253Slq150181 		tem_setparam(tem, 1, 1);
590*1253Slq150181 		tem_mv_cursor(tem, row, tems->a_params[0] - 1,
591*1253Slq150181 		    credp, called_from);
592*1253Slq150181 		break;
593*1253Slq150181 
594*1253Slq150181 	case 'g':		/* clear tabs */
595*1253Slq150181 		tem_setparam(tem, 1, 0);
596*1253Slq150181 		tem_clear_tabs(tem, tems->a_params[0]);
597*1253Slq150181 		break;
598*1253Slq150181 
599*1253Slq150181 	case 'f':		/* HVP Horizontal and Vertical Position */
600*1253Slq150181 	case 'H':		/* CUP position cursor */
601*1253Slq150181 		tem_setparam(tem, 2, 1);
602*1253Slq150181 		tem_mv_cursor(tem,
603*1253Slq150181 		    tems->a_params[0] - 1,
604*1253Slq150181 		    tems->a_params[1] - 1,
605*1253Slq150181 		    credp, called_from);
606*1253Slq150181 		break;
607*1253Slq150181 
608*1253Slq150181 	case 'I':		/* CHT - Cursor Horizontal Tab */
609*1253Slq150181 		/* Not implemented */
610*1253Slq150181 		break;
611*1253Slq150181 
612*1253Slq150181 	case 'J':		/* ED - Erase in Display */
613*1253Slq150181 		tem_send_data(tem, credp, called_from);
614*1253Slq150181 		tem_setparam(tem, 1, 0);
615*1253Slq150181 		switch (tems->a_params[0]) {
616*1253Slq150181 		case 0:
617*1253Slq150181 			/* erase cursor to end of screen */
618*1253Slq150181 			/* FIRST erase cursor to end of line */
619*1253Slq150181 			tem_clear_chars(tem,
620*1253Slq150181 				tems->a_c_dimension.width -
621*1253Slq150181 				    tems->a_c_cursor.col,
622*1253Slq150181 				tems->a_c_cursor.row,
623*1253Slq150181 				tems->a_c_cursor.col, credp, called_from);
624*1253Slq150181 
625*1253Slq150181 			/* THEN erase lines below the cursor */
626*1253Slq150181 			for (row = tems->a_c_cursor.row + 1;
627*1253Slq150181 				row < tems->a_c_dimension.height;
628*1253Slq150181 				row++) {
629*1253Slq150181 				tem_clear_chars(tem,
630*1253Slq150181 				    tems->a_c_dimension.width,
631*1253Slq150181 				    row, 0, credp, called_from);
632*1253Slq150181 			}
633*1253Slq150181 			break;
634*1253Slq150181 
635*1253Slq150181 		case 1:
636*1253Slq150181 			/* erase beginning of screen to cursor */
637*1253Slq150181 			/* FIRST erase lines above the cursor */
638*1253Slq150181 			for (row = 0;
639*1253Slq150181 				row < tems->a_c_cursor.row;
640*1253Slq150181 				row++) {
641*1253Slq150181 				tem_clear_chars(tem,
642*1253Slq150181 				    tems->a_c_dimension.width,
643*1253Slq150181 				    row, 0, credp, called_from);
644*1253Slq150181 			}
645*1253Slq150181 			/* THEN erase beginning of line to cursor */
646*1253Slq150181 			tem_clear_chars(tem,
647*1253Slq150181 				tems->a_c_cursor.col + 1,
648*1253Slq150181 				tems->a_c_cursor.row,
649*1253Slq150181 				    0, credp, called_from);
650*1253Slq150181 			break;
651*1253Slq150181 
652*1253Slq150181 		case 2:
653*1253Slq150181 			/* erase whole screen */
654*1253Slq150181 			for (row = 0;
655*1253Slq150181 			    row < tems->a_c_dimension.height;
656*1253Slq150181 			    row++) {
657*1253Slq150181 				tem_clear_chars(tem,
658*1253Slq150181 				tems->a_c_dimension.width,
659*1253Slq150181 				row, 0, credp, called_from);
660*1253Slq150181 			}
661*1253Slq150181 			break;
662*1253Slq150181 		}
663*1253Slq150181 		break;
664*1253Slq150181 
665*1253Slq150181 	case 'K':		/* EL - Erase in Line */
666*1253Slq150181 		tem_send_data(tem, credp, called_from);
667*1253Slq150181 		tem_setparam(tem, 1, 0);
668*1253Slq150181 		switch (tems->a_params[0]) {
669*1253Slq150181 		case 0:
670*1253Slq150181 			/* erase cursor to end of line */
671*1253Slq150181 			tem_clear_chars(tem,
672*1253Slq150181 			    (tems->a_c_dimension.width -
673*1253Slq150181 			    tems->a_c_cursor.col),
674*1253Slq150181 			    tems->a_c_cursor.row,
675*1253Slq150181 			    tems->a_c_cursor.col,
676*1253Slq150181 			    credp, called_from);
677*1253Slq150181 			break;
678*1253Slq150181 
679*1253Slq150181 		case 1:
680*1253Slq150181 			/* erase beginning of line to cursor */
681*1253Slq150181 			tem_clear_chars(tem,
682*1253Slq150181 			    tems->a_c_cursor.col + 1,
683*1253Slq150181 			    tems->a_c_cursor.row,
684*1253Slq150181 			    0, credp, called_from);
685*1253Slq150181 			break;
686*1253Slq150181 
687*1253Slq150181 		case 2:
688*1253Slq150181 			/* erase whole line */
689*1253Slq150181 			tem_clear_chars(tem,
690*1253Slq150181 			    tems->a_c_dimension.width,
691*1253Slq150181 			    tems->a_c_cursor.row,
692*1253Slq150181 			    0, credp, called_from);
693*1253Slq150181 			break;
694*1253Slq150181 		}
695*1253Slq150181 		break;
696*1253Slq150181 
697*1253Slq150181 	case 'L':		/* insert line */
698*1253Slq150181 		tem_send_data(tem, credp, called_from);
699*1253Slq150181 		tem_setparam(tem, 1, 1);
700*1253Slq150181 		tem_scroll(tem,
701*1253Slq150181 			tems->a_c_cursor.row,
702*1253Slq150181 			tems->a_c_dimension.height - 1,
703*1253Slq150181 			tems->a_params[0], TEM_SCROLL_DOWN,
704*1253Slq150181 			    credp, called_from);
705*1253Slq150181 		break;
706*1253Slq150181 
707*1253Slq150181 	case 'M':		/* delete line */
708*1253Slq150181 		tem_send_data(tem, credp, called_from);
709*1253Slq150181 		tem_setparam(tem, 1, 1);
710*1253Slq150181 		tem_scroll(tem,
711*1253Slq150181 			tems->a_c_cursor.row,
712*1253Slq150181 			tems->a_c_dimension.height - 1,
713*1253Slq150181 			tems->a_params[0], TEM_SCROLL_UP,
714*1253Slq150181 			    credp, called_from);
715*1253Slq150181 		break;
716*1253Slq150181 
717*1253Slq150181 	case 'P':		/* DCH - delete char */
718*1253Slq150181 		tem_setparam(tem, 1, 1);
719*1253Slq150181 		tem_shift(tem, tems->a_params[0], TEM_SHIFT_LEFT,
720*1253Slq150181 		    credp, called_from);
721*1253Slq150181 		break;
722*1253Slq150181 
723*1253Slq150181 	case 'S':		/* scroll up */
724*1253Slq150181 		tem_send_data(tem, credp, called_from);
725*1253Slq150181 		tem_setparam(tem, 1, 1);
726*1253Slq150181 		tem_scroll(tem, 0,
727*1253Slq150181 			tems->a_c_dimension.height - 1,
728*1253Slq150181 			tems->a_params[0], TEM_SCROLL_UP,
729*1253Slq150181 			    credp, called_from);
730*1253Slq150181 		break;
731*1253Slq150181 
732*1253Slq150181 	case 'T':		/* scroll down */
733*1253Slq150181 		tem_send_data(tem, credp, called_from);
734*1253Slq150181 		tem_setparam(tem, 1, 1);
735*1253Slq150181 		tem_scroll(tem, 0,
736*1253Slq150181 			tems->a_c_dimension.height - 1,
737*1253Slq150181 			tems->a_params[0], TEM_SCROLL_DOWN,
738*1253Slq150181 			    credp, called_from);
739*1253Slq150181 		break;
740*1253Slq150181 
741*1253Slq150181 	case 'X':		/* erase char */
742*1253Slq150181 		tem_setparam(tem, 1, 1);
743*1253Slq150181 		tem_clear_chars(tem,
744*1253Slq150181 			tems->a_params[0],
745*1253Slq150181 			tems->a_c_cursor.row,
746*1253Slq150181 			tems->a_c_cursor.col,
747*1253Slq150181 			    credp, called_from);
748*1253Slq150181 		break;
749*1253Slq150181 
750*1253Slq150181 	case 'Z':		/* cursor backward tabulation */
751*1253Slq150181 		tem_setparam(tem, 1, 1);
752*1253Slq150181 
753*1253Slq150181 		/*
754*1253Slq150181 		 * Rule exception - We do sanity checking here.
755*1253Slq150181 		 *
756*1253Slq150181 		 * Restrict the count to a sane value to keep from
757*1253Slq150181 		 * looping for a long time.  There can't be more than one
758*1253Slq150181 		 * tab stop per column, so use that as a limit.
759*1253Slq150181 		 */
760*1253Slq150181 		if (tems->a_params[0] > tems->a_c_dimension.width)
761*1253Slq150181 			tems->a_params[0] = tems->a_c_dimension.width;
762*1253Slq150181 
763*1253Slq150181 		for (i = 0; i < tems->a_params[0]; i++)
764*1253Slq150181 			tem_back_tab(tem, credp, called_from);
765*1253Slq150181 		break;
766*1253Slq150181 	}
767*1253Slq150181 	tems->a_state = A_STATE_START;
768*1253Slq150181 }
769*1253Slq150181 
770*1253Slq150181 
771*1253Slq150181 /*
772*1253Slq150181  * Gather the parameters of an ANSI escape sequence
773*1253Slq150181  */
774*1253Slq150181 static void
775*1253Slq150181 tem_getparams(struct tem *tem, uchar_t ch,
776*1253Slq150181     cred_t *credp, enum called_from called_from)
777*1253Slq150181 {
778*1253Slq150181 	struct tem_state *tems = tem->state;
779*1253Slq150181 
780*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
781*1253Slq150181 	    MUTEX_HELD(&tem->lock));
782*1253Slq150181 
783*1253Slq150181 	if ((ch >= '0' && ch <= '9') &&
784*1253Slq150181 	    (tems->a_state != A_STATE_ESC_Q_DELM)) {
785*1253Slq150181 		tems->a_paramval =
786*1253Slq150181 		    ((tems->a_paramval * 10) + (ch - '0'));
787*1253Slq150181 		tems->a_gotparam = B_TRUE;  /* Remember got parameter */
788*1253Slq150181 		return; /* Return immediately */
789*1253Slq150181 	}
790*1253Slq150181 	switch (tems->a_state) { /* Handle letter based on state */
791*1253Slq150181 
792*1253Slq150181 	case A_STATE_ESC_Q:			  /* <ESC>Q<num> ? */
793*1253Slq150181 		tems->a_params[1] = ch;	  /* Save string delimiter */
794*1253Slq150181 		tems->a_params[2] = 0;	  /* String length 0 to start */
795*1253Slq150181 		tems->a_state = A_STATE_ESC_Q_DELM; /* Read string next */
796*1253Slq150181 		break;
797*1253Slq150181 
798*1253Slq150181 	case A_STATE_ESC_Q_DELM: /* <ESC>Q<num><delm> ? */
799*1253Slq150181 		if (ch == tems->a_params[1]) {	/* End of string? */
800*1253Slq150181 			tems->a_state = A_STATE_START;
801*1253Slq150181 			/* End of <ESC> sequence */
802*1253Slq150181 		} else if (ch == '^')
803*1253Slq150181 			/* Control char escaped with '^'? */
804*1253Slq150181 			tems->a_state = A_STATE_ESC_Q_DELM_CTRL;
805*1253Slq150181 			/* Read control character next */
806*1253Slq150181 
807*1253Slq150181 		else if (ch != '\0') {
808*1253Slq150181 			/* Not a null? Add to string */
809*1253Slq150181 			tems->a_fkey[tems->a_params[2]++] = ch;
810*1253Slq150181 			if (tems->a_params[2] >= TEM_MAXFKEY)  /* Full? */
811*1253Slq150181 				tems->a_state = A_STATE_START;
812*1253Slq150181 				/* End of <ESC> sequence */
813*1253Slq150181 		}
814*1253Slq150181 		break;
815*1253Slq150181 
816*1253Slq150181 	case A_STATE_ESC_Q_DELM_CTRL:	/* Contrl character escaped with '^' */
817*1253Slq150181 		tems->a_state = A_STATE_ESC_Q_DELM; /* rd more later */
818*1253Slq150181 		ch -= ' ';	   /* Convert to control character */
819*1253Slq150181 		if (ch != '\0') {  /* Not a null? Add to string */
820*1253Slq150181 			tems->a_fkey[tems->a_params[2]++] = ch;
821*1253Slq150181 			if (tems->a_params[2] >= TEM_MAXFKEY) /* Full? */
822*1253Slq150181 				tems->a_state = A_STATE_START;
823*1253Slq150181 				/* End of <ESC> sequence */
824*1253Slq150181 		}
825*1253Slq150181 		break;
826*1253Slq150181 
827*1253Slq150181 	default:			/* All other states */
828*1253Slq150181 		if (tems->a_gotparam) {
829*1253Slq150181 			if (tems->a_curparam >= TEM_MAXPARAMS) {
830*1253Slq150181 				/*
831*1253Slq150181 				 * Too many parameters.  Abort the
832*1253Slq150181 				 * sequence.
833*1253Slq150181 				 */
834*1253Slq150181 				tems->a_state = A_STATE_START;
835*1253Slq150181 				break;
836*1253Slq150181 			}
837*1253Slq150181 			/*
838*1253Slq150181 			 * Previous number parameter? Save and
839*1253Slq150181 			 * point to next free parameter.
840*1253Slq150181 			 */
841*1253Slq150181 			tems->a_params[tems->a_curparam] =
842*1253Slq150181 			    tems->a_paramval;
843*1253Slq150181 			tems->a_curparam++;
844*1253Slq150181 		}
845*1253Slq150181 
846*1253Slq150181 		if (ch == ';') {
847*1253Slq150181 			/* Multiple param separator? */
848*1253Slq150181 			/* Restart parameter search */
849*1253Slq150181 			tems->a_gotparam = B_FALSE;
850*1253Slq150181 			tems->a_paramval = 0; /* No parame value yet */
851*1253Slq150181 		} else if (tems->a_state == A_STATE_CSI_EQUAL ||
852*1253Slq150181 			tems->a_state == A_STATE_CSI_QMARK) {
853*1253Slq150181 			tems->a_state = A_STATE_START;
854*1253Slq150181 		} else	/* Regular letter */
855*1253Slq150181 			/* Handle escape sequence */
856*1253Slq150181 			tem_chkparam(tem, ch, credp, called_from);
857*1253Slq150181 		break;
858*1253Slq150181 	}
859*1253Slq150181 }
860*1253Slq150181 
861*1253Slq150181 /*
862*1253Slq150181  * Add character to internal buffer.
863*1253Slq150181  * When its full, send it to the next layer.
864*1253Slq150181  */
865*1253Slq150181 
866*1253Slq150181 static void
867*1253Slq150181 tem_outch(struct tem *tem, uchar_t ch,
868*1253Slq150181     cred_t *credp, enum called_from called_from)
869*1253Slq150181 {
870*1253Slq150181 
871*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
872*1253Slq150181 	    MUTEX_HELD(&tem->lock));
873*1253Slq150181 
874*1253Slq150181 	/* buffer up the character until later */
875*1253Slq150181 
876*1253Slq150181 	tem->state->a_outbuf[tem->state->a_outindex++] = ch;
877*1253Slq150181 	tem->state->a_c_cursor.col++;
878*1253Slq150181 	if (tem->state->a_c_cursor.col >= tem->state->a_c_dimension.width) {
879*1253Slq150181 		tem_send_data(tem, credp, called_from);
880*1253Slq150181 		tem_new_line(tem, credp, called_from);
881*1253Slq150181 	}
882*1253Slq150181 }
883*1253Slq150181 
884*1253Slq150181 static void
885*1253Slq150181 tem_new_line(struct tem *tem,
886*1253Slq150181     cred_t *credp, enum called_from called_from)
887*1253Slq150181 {
888*1253Slq150181 	tem_cr(tem);
889*1253Slq150181 	tem_lf(tem, credp, called_from);
890*1253Slq150181 }
891*1253Slq150181 
892*1253Slq150181 static void
893*1253Slq150181 tem_cr(struct tem *tem)
894*1253Slq150181 {
895*1253Slq150181 	tem->state->a_c_cursor.col = 0;
896*1253Slq150181 	tem_align_cursor(tem);
897*1253Slq150181 }
898*1253Slq150181 
899*1253Slq150181 static void
900*1253Slq150181 tem_lf(struct tem *tem,
901*1253Slq150181     cred_t *credp, enum called_from called_from)
902*1253Slq150181 {
903*1253Slq150181 	struct tem_state *tems = tem->state;
904*1253Slq150181 	int row;
905*1253Slq150181 
906*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
907*1253Slq150181 	    MUTEX_HELD(&tem->lock));
908*1253Slq150181 
909*1253Slq150181 	/*
910*1253Slq150181 	 * Sanity checking notes:
911*1253Slq150181 	 * . a_nscroll was validated when it was set.
912*1253Slq150181 	 * . Regardless of that, tem_scroll and tem_mv_cursor will prevent
913*1253Slq150181 	 *   anything bad from happening.
914*1253Slq150181 	 */
915*1253Slq150181 	row = tems->a_c_cursor.row + 1;
916*1253Slq150181 
917*1253Slq150181 	if (row >= tems->a_c_dimension.height) {
918*1253Slq150181 		if (tems->a_nscroll != 0) {
919*1253Slq150181 			tem_scroll(tem, 0,
920*1253Slq150181 			    tems->a_c_dimension.height - 1,
921*1253Slq150181 			    tems->a_nscroll, TEM_SCROLL_UP,
922*1253Slq150181 			    credp, called_from);
923*1253Slq150181 			row = tems->a_c_dimension.height -
924*1253Slq150181 			    tems->a_nscroll;
925*1253Slq150181 		} else {	/* no scroll */
926*1253Slq150181 			/*
927*1253Slq150181 			 * implement Esc[#r when # is zero.  This means no
928*1253Slq150181 			 * scroll but just return cursor to top of screen,
929*1253Slq150181 			 * do not clear screen.
930*1253Slq150181 			 */
931*1253Slq150181 			row = 0;
932*1253Slq150181 		}
933*1253Slq150181 	}
934*1253Slq150181 
935*1253Slq150181 	tem_mv_cursor(tem, row, tems->a_c_cursor.col,
936*1253Slq150181 		credp, called_from);
937*1253Slq150181 
938*1253Slq150181 	if (tems->a_nscroll == 0) {
939*1253Slq150181 		/* erase rest of cursor line */
940*1253Slq150181 		tem_clear_chars(tem,
941*1253Slq150181 		    tems->a_c_dimension.width -
942*1253Slq150181 		    tems->a_c_cursor.col,
943*1253Slq150181 		    tems->a_c_cursor.row,
944*1253Slq150181 		    tems->a_c_cursor.col,
945*1253Slq150181 		    credp, called_from);
946*1253Slq150181 
947*1253Slq150181 	}
948*1253Slq150181 
949*1253Slq150181 	tem_align_cursor(tem);
950*1253Slq150181 }
951*1253Slq150181 
952*1253Slq150181 static void
953*1253Slq150181 tem_send_data(struct tem *tem, cred_t *credp,
954*1253Slq150181     enum called_from called_from)
955*1253Slq150181 {
956*1253Slq150181 	struct tem_state *tems = tem->state;
957*1253Slq150181 	text_color_t fg_color;
958*1253Slq150181 	text_color_t bg_color;
959*1253Slq150181 
960*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
961*1253Slq150181 	    MUTEX_HELD(&tem->lock));
962*1253Slq150181 
963*1253Slq150181 	if (tems->a_outindex != 0) {
964*1253Slq150181 
965*1253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
966*1253Slq150181 			fg_color = ansi_fg_to_solaris(tem,
967*1253Slq150181 			    tems->bg_color);
968*1253Slq150181 			bg_color = ansi_bg_to_solaris(tem,
969*1253Slq150181 			    tems->fg_color);
970*1253Slq150181 		} else {
971*1253Slq150181 			fg_color = ansi_fg_to_solaris(tem,
972*1253Slq150181 			    tems->fg_color);
973*1253Slq150181 			bg_color = ansi_bg_to_solaris(tem,
974*1253Slq150181 			    tems->bg_color);
975*1253Slq150181 		}
976*1253Slq150181 
977*1253Slq150181 		/*
978*1253Slq150181 		 * Call the primitive to render this data.
979*1253Slq150181 		 */
980*1253Slq150181 		(*tems->in_fp.f_display)(tem,
981*1253Slq150181 			tems->a_outbuf,
982*1253Slq150181 			tems->a_outindex,
983*1253Slq150181 			tems->a_s_cursor.row,
984*1253Slq150181 			    tems->a_s_cursor.col,
985*1253Slq150181 			fg_color, bg_color,
986*1253Slq150181 			credp, called_from);
987*1253Slq150181 		tems->a_outindex = 0;
988*1253Slq150181 	}
989*1253Slq150181 	tem_align_cursor(tem);
990*1253Slq150181 }
991*1253Slq150181 
992*1253Slq150181 
993*1253Slq150181 /*
994*1253Slq150181  * We have just done something to the current output point.  Reset the start
995*1253Slq150181  * point for the buffered data in a_outbuf.  There shouldn't be any data
996*1253Slq150181  * buffered yet.
997*1253Slq150181  */
998*1253Slq150181 void
999*1253Slq150181 tem_align_cursor(struct tem *tem)
1000*1253Slq150181 {
1001*1253Slq150181 	tem->state->a_s_cursor.row = tem->state->a_c_cursor.row;
1002*1253Slq150181 	tem->state->a_s_cursor.col = tem->state->a_c_cursor.col;
1003*1253Slq150181 }
1004*1253Slq150181 
1005*1253Slq150181 
1006*1253Slq150181 
1007*1253Slq150181 /*
1008*1253Slq150181  * State machine parser based on the current state and character input
1009*1253Slq150181  * major terminations are to control character or normal character
1010*1253Slq150181  */
1011*1253Slq150181 
1012*1253Slq150181 static void
1013*1253Slq150181 tem_parse(struct tem *tem, uchar_t ch,
1014*1253Slq150181     cred_t *credp, enum called_from called_from)
1015*1253Slq150181 {
1016*1253Slq150181 	struct tem_state *tems = tem->state;
1017*1253Slq150181 	int	i;
1018*1253Slq150181 
1019*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1020*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1021*1253Slq150181 
1022*1253Slq150181 	if (tems->a_state == A_STATE_START) {	/* Normal state? */
1023*1253Slq150181 		if (ch == A_CSI || ch == A_ESC || ch < ' ') /* Control? */
1024*1253Slq150181 			tem_control(tem, ch, credp, called_from);
1025*1253Slq150181 		else
1026*1253Slq150181 			/* Display */
1027*1253Slq150181 			tem_outch(tem, ch, credp, called_from);
1028*1253Slq150181 		return;
1029*1253Slq150181 	}
1030*1253Slq150181 
1031*1253Slq150181 	/* In <ESC> sequence */
1032*1253Slq150181 	if (tems->a_state != A_STATE_ESC) {	/* Need to get parameters? */
1033*1253Slq150181 		if (tems->a_state != A_STATE_CSI) {
1034*1253Slq150181 			tem_getparams(tem, ch, credp, called_from);
1035*1253Slq150181 			return;
1036*1253Slq150181 		}
1037*1253Slq150181 
1038*1253Slq150181 		switch (ch) {
1039*1253Slq150181 		case '?':
1040*1253Slq150181 			tems->a_state = A_STATE_CSI_QMARK;
1041*1253Slq150181 			return;
1042*1253Slq150181 		case '=':
1043*1253Slq150181 			tems->a_state = A_STATE_CSI_EQUAL;
1044*1253Slq150181 			return;
1045*1253Slq150181 		case 's':
1046*1253Slq150181 			/*
1047*1253Slq150181 			 * As defined below, this sequence
1048*1253Slq150181 			 * saves the cursor.  However, Sun
1049*1253Slq150181 			 * defines ESC[s as reset.  We resolved
1050*1253Slq150181 			 * the conflict by selecting reset as it
1051*1253Slq150181 			 * is exported in the termcap file for
1052*1253Slq150181 			 * sun-mon, while the "save cursor"
1053*1253Slq150181 			 * definition does not exist anywhere in
1054*1253Slq150181 			 * /etc/termcap.
1055*1253Slq150181 			 * However, having no coherent
1056*1253Slq150181 			 * definition of reset, we have not
1057*1253Slq150181 			 * implemented it.
1058*1253Slq150181 			 */
1059*1253Slq150181 
1060*1253Slq150181 			/*
1061*1253Slq150181 			 * Original code
1062*1253Slq150181 			 * tems->a_r_cursor.row = tems->a_c_cursor.row;
1063*1253Slq150181 			 * tems->a_r_cursor.col = tems->a_c_cursor.col;
1064*1253Slq150181 			 * tems->a_state = A_STATE_START;
1065*1253Slq150181 			 */
1066*1253Slq150181 
1067*1253Slq150181 			tems->a_state = A_STATE_START;
1068*1253Slq150181 			return;
1069*1253Slq150181 		case 'u':
1070*1253Slq150181 			tem_mv_cursor(tem, tems->a_r_cursor.row,
1071*1253Slq150181 			    tems->a_r_cursor.col, credp, called_from);
1072*1253Slq150181 			tems->a_state = A_STATE_START;
1073*1253Slq150181 			return;
1074*1253Slq150181 		case 'p': 	/* sunbow */
1075*1253Slq150181 			tem_send_data(tem, credp, called_from);
1076*1253Slq150181 			/*
1077*1253Slq150181 			 * Don't set anything if we are
1078*1253Slq150181 			 * already as we want to be.
1079*1253Slq150181 			 */
1080*1253Slq150181 			if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) {
1081*1253Slq150181 				tems->a_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1082*1253Slq150181 				/*
1083*1253Slq150181 				 * If we have switched the characters to be the
1084*1253Slq150181 				 * inverse from the screen, then switch them as
1085*1253Slq150181 				 * well to keep them the inverse of the screen.
1086*1253Slq150181 				 */
1087*1253Slq150181 				if (tems->a_flags & TEM_ATTR_REVERSE) {
1088*1253Slq150181 					tems->a_flags &= ~TEM_ATTR_REVERSE;
1089*1253Slq150181 				} else {
1090*1253Slq150181 					tems->a_flags |= TEM_ATTR_REVERSE;
1091*1253Slq150181 				}
1092*1253Slq150181 			}
1093*1253Slq150181 			tem_cls(tem, credp, called_from);
1094*1253Slq150181 			tems->a_state = A_STATE_START;
1095*1253Slq150181 			return;
1096*1253Slq150181 		case 'q':  	/* sunwob */
1097*1253Slq150181 			tem_send_data(tem, credp, called_from);
1098*1253Slq150181 			/*
1099*1253Slq150181 			 * Don't set anything if we are
1100*1253Slq150181 			 * already where as we want to be.
1101*1253Slq150181 			 */
1102*1253Slq150181 			if (!(tems->a_flags & TEM_ATTR_SCREEN_REVERSE)) {
1103*1253Slq150181 				tems->a_flags |= TEM_ATTR_SCREEN_REVERSE;
1104*1253Slq150181 				/*
1105*1253Slq150181 				 * If we have switched the characters to be the
1106*1253Slq150181 				 * inverse from the screen, then switch them as
1107*1253Slq150181 				 * well to keep them the inverse of the screen.
1108*1253Slq150181 				 */
1109*1253Slq150181 				if (!(tems->a_flags & TEM_ATTR_REVERSE)) {
1110*1253Slq150181 					tems->a_flags |= TEM_ATTR_REVERSE;
1111*1253Slq150181 				} else {
1112*1253Slq150181 					tems->a_flags &= ~TEM_ATTR_REVERSE;
1113*1253Slq150181 				}
1114*1253Slq150181 			}
1115*1253Slq150181 
1116*1253Slq150181 			tem_cls(tem, credp, called_from);
1117*1253Slq150181 			tems->a_state = A_STATE_START;
1118*1253Slq150181 			return;
1119*1253Slq150181 		case 'r':	/* sunscrl */
1120*1253Slq150181 			/*
1121*1253Slq150181 			 * Rule exception:  check for validity here.
1122*1253Slq150181 			 */
1123*1253Slq150181 			tems->a_nscroll = tems->a_paramval;
1124*1253Slq150181 			if (tems->a_nscroll > tems->a_c_dimension.height)
1125*1253Slq150181 				tems->a_nscroll = tems->a_c_dimension.height;
1126*1253Slq150181 			if (tems->a_nscroll < 0)
1127*1253Slq150181 				tems->a_nscroll = 1;
1128*1253Slq150181 			tems->a_state = A_STATE_START;
1129*1253Slq150181 			return;
1130*1253Slq150181 		default:
1131*1253Slq150181 			tem_getparams(tem, ch, credp, called_from);
1132*1253Slq150181 			return;
1133*1253Slq150181 		}
1134*1253Slq150181 	}
1135*1253Slq150181 
1136*1253Slq150181 	/* Previous char was <ESC> */
1137*1253Slq150181 	if (ch == '[') {
1138*1253Slq150181 		tems->a_curparam = 0;
1139*1253Slq150181 		tems->a_paramval = 0;
1140*1253Slq150181 		tems->a_gotparam = B_FALSE;
1141*1253Slq150181 		/* clear the parameters */
1142*1253Slq150181 		for (i = 0; i < TEM_MAXPARAMS; i++)
1143*1253Slq150181 			tems->a_params[i] = -1;
1144*1253Slq150181 		tems->a_state = A_STATE_CSI;
1145*1253Slq150181 	} else if (ch == 'Q') {	/* <ESC>Q ? */
1146*1253Slq150181 		tems->a_curparam = 0;
1147*1253Slq150181 		tems->a_paramval = 0;
1148*1253Slq150181 		tems->a_gotparam = B_FALSE;
1149*1253Slq150181 		for (i = 0; i < TEM_MAXPARAMS; i++)
1150*1253Slq150181 			tems->a_params[i] = -1; /* Clr */
1151*1253Slq150181 		/* Next get params */
1152*1253Slq150181 		tems->a_state = A_STATE_ESC_Q;
1153*1253Slq150181 	} else if (ch == 'C') {	/* <ESC>C ? */
1154*1253Slq150181 		tems->a_curparam = 0;
1155*1253Slq150181 		tems->a_paramval = 0;
1156*1253Slq150181 		tems->a_gotparam = B_FALSE;
1157*1253Slq150181 		for (i = 0; i < TEM_MAXPARAMS; i++)
1158*1253Slq150181 			tems->a_params[i] = -1; /* Clr */
1159*1253Slq150181 		/* Next get params */
1160*1253Slq150181 		tems->a_state = A_STATE_ESC_C;
1161*1253Slq150181 	} else {
1162*1253Slq150181 		tems->a_state = A_STATE_START;
1163*1253Slq150181 		if (ch == 'c')
1164*1253Slq150181 			/* ESC c resets display */
1165*1253Slq150181 			tem_reset_display(tem, credp, called_from, 1);
1166*1253Slq150181 		else if (ch == 'H')
1167*1253Slq150181 			/* ESC H sets a tab */
1168*1253Slq150181 			tem_set_tab(tem);
1169*1253Slq150181 		else if (ch == '7') {
1170*1253Slq150181 			/* ESC 7 Save Cursor position */
1171*1253Slq150181 			tems->a_r_cursor.row = tems->a_c_cursor.row;
1172*1253Slq150181 			tems->a_r_cursor.col = tems->a_c_cursor.col;
1173*1253Slq150181 		} else if (ch == '8')
1174*1253Slq150181 			/* ESC 8 Restore Cursor position */
1175*1253Slq150181 			tem_mv_cursor(tem, tems->a_r_cursor.row,
1176*1253Slq150181 			    tems->a_r_cursor.col, credp, called_from);
1177*1253Slq150181 		/* check for control chars */
1178*1253Slq150181 		else if (ch < ' ')
1179*1253Slq150181 			tem_control(tem, ch, credp, called_from);
1180*1253Slq150181 		else
1181*1253Slq150181 			tem_outch(tem, ch, credp, called_from);
1182*1253Slq150181 	}
1183*1253Slq150181 }
1184*1253Slq150181 
1185*1253Slq150181 /* ARGSUSED */
1186*1253Slq150181 static void
1187*1253Slq150181 tem_bell(struct tem *tem, enum called_from called_from)
1188*1253Slq150181 {
1189*1253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
1190*1253Slq150181 		beep_polled(BEEP_CONSOLE);
1191*1253Slq150181 	else
1192*1253Slq150181 		beep(BEEP_CONSOLE);
1193*1253Slq150181 }
1194*1253Slq150181 
1195*1253Slq150181 
1196*1253Slq150181 static void
1197*1253Slq150181 tem_scroll(tem_t *tem, int start, int end, int count, int direction,
1198*1253Slq150181 	cred_t *credp, enum called_from called_from)
1199*1253Slq150181 {
1200*1253Slq150181 	struct tem_state *tems = tem->state;
1201*1253Slq150181 	int	row;
1202*1253Slq150181 	int	lines_affected;
1203*1253Slq150181 
1204*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1205*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1206*1253Slq150181 
1207*1253Slq150181 	lines_affected = end - start + 1;
1208*1253Slq150181 	if (count > lines_affected)
1209*1253Slq150181 		count = lines_affected;
1210*1253Slq150181 	if (count <= 0)
1211*1253Slq150181 		return;
1212*1253Slq150181 
1213*1253Slq150181 	switch (direction) {
1214*1253Slq150181 	case TEM_SCROLL_UP:
1215*1253Slq150181 		if (count < lines_affected) {
1216*1253Slq150181 			tem_copy_area(tem, 0, start + count,
1217*1253Slq150181 			    tems->a_c_dimension.width - 1, end,
1218*1253Slq150181 			    0, start, credp, called_from);
1219*1253Slq150181 		}
1220*1253Slq150181 		for (row = (end - count) + 1; row <= end; row++) {
1221*1253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
1222*1253Slq150181 			    row, 0, credp, called_from);
1223*1253Slq150181 		}
1224*1253Slq150181 		break;
1225*1253Slq150181 
1226*1253Slq150181 	case TEM_SCROLL_DOWN:
1227*1253Slq150181 		if (count < lines_affected) {
1228*1253Slq150181 			tem_copy_area(tem, 0, start,
1229*1253Slq150181 			    tems->a_c_dimension.width - 1,
1230*1253Slq150181 			    end - count, 0, start + count,
1231*1253Slq150181 			    credp, called_from);
1232*1253Slq150181 		}
1233*1253Slq150181 		for (row = start; row < start + count; row++) {
1234*1253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
1235*1253Slq150181 			    row, 0, credp, called_from);
1236*1253Slq150181 		}
1237*1253Slq150181 		break;
1238*1253Slq150181 	}
1239*1253Slq150181 }
1240*1253Slq150181 
1241*1253Slq150181 static void
1242*1253Slq150181 tem_copy_area(struct tem *tem,
1243*1253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
1244*1253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
1245*1253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
1246*1253Slq150181 	cred_t *credp, enum called_from called_from)
1247*1253Slq150181 {
1248*1253Slq150181 	struct tem_state *tems = tem->state;
1249*1253Slq150181 	int rows;
1250*1253Slq150181 	int cols;
1251*1253Slq150181 
1252*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1253*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1254*1253Slq150181 
1255*1253Slq150181 	if (s_col < 0 || s_row < 0 ||
1256*1253Slq150181 	    e_col < 0 || e_row < 0 ||
1257*1253Slq150181 	    t_col < 0 || t_row < 0 ||
1258*1253Slq150181 	    s_col >= tems->a_c_dimension.width ||
1259*1253Slq150181 	    e_col >= tems->a_c_dimension.width ||
1260*1253Slq150181 	    t_col >= tems->a_c_dimension.width ||
1261*1253Slq150181 	    s_row >= tems->a_c_dimension.height ||
1262*1253Slq150181 	    e_row >= tems->a_c_dimension.height ||
1263*1253Slq150181 	    t_row >= tems->a_c_dimension.height)
1264*1253Slq150181 		return;
1265*1253Slq150181 
1266*1253Slq150181 	if (s_row > e_row || s_col > e_col)
1267*1253Slq150181 		return;
1268*1253Slq150181 
1269*1253Slq150181 	rows = e_row - s_row + 1;
1270*1253Slq150181 	cols = e_col - s_col + 1;
1271*1253Slq150181 	if (t_row + rows > tems->a_c_dimension.height ||
1272*1253Slq150181 	    t_col + cols > tems->a_c_dimension.width)
1273*1253Slq150181 		return;
1274*1253Slq150181 
1275*1253Slq150181 	(*tems->in_fp.f_copy)(tem, s_col, s_row,
1276*1253Slq150181 		e_col, e_row, t_col, t_row, credp, called_from);
1277*1253Slq150181 }
1278*1253Slq150181 
1279*1253Slq150181 static void
1280*1253Slq150181 tem_clear_chars(struct tem *tem, int count, screen_pos_t row,
1281*1253Slq150181 	screen_pos_t col, cred_t *credp, enum called_from called_from)
1282*1253Slq150181 {
1283*1253Slq150181 	struct tem_state *tems = tem->state;
1284*1253Slq150181 
1285*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1286*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1287*1253Slq150181 
1288*1253Slq150181 	if (row < 0 || row >= tems->a_c_dimension.height ||
1289*1253Slq150181 	    col < 0 || col >= tems->a_c_dimension.width ||
1290*1253Slq150181 	    count < 0)
1291*1253Slq150181 		return;
1292*1253Slq150181 
1293*1253Slq150181 	/*
1294*1253Slq150181 	 * Note that very large values of "count" could cause col+count
1295*1253Slq150181 	 * to overflow, so we check "count" independently.
1296*1253Slq150181 	 */
1297*1253Slq150181 	if (count > tems->a_c_dimension.width ||
1298*1253Slq150181 	    col + count > tems->a_c_dimension.width)
1299*1253Slq150181 		count = tems->a_c_dimension.width - col;
1300*1253Slq150181 
1301*1253Slq150181 	(*tems->in_fp.f_cls)(tem, count, row, col, credp, called_from);
1302*1253Slq150181 }
1303*1253Slq150181 
1304*1253Slq150181 void
1305*1253Slq150181 tem_text_display(struct tem *tem, uchar_t *string,
1306*1253Slq150181 	int count, screen_pos_t row, screen_pos_t col,
1307*1253Slq150181 	text_color_t fg_color, text_color_t bg_color,
1308*1253Slq150181 	cred_t *credp, enum called_from called_from)
1309*1253Slq150181 {
1310*1253Slq150181 	struct vis_consdisplay da;
1311*1253Slq150181 
1312*1253Slq150181 	da.data = string;
1313*1253Slq150181 	da.width = count;
1314*1253Slq150181 	da.row = row;
1315*1253Slq150181 	da.col = col;
1316*1253Slq150181 
1317*1253Slq150181 	da.fg_color = fg_color;
1318*1253Slq150181 	da.bg_color = bg_color;
1319*1253Slq150181 
1320*1253Slq150181 	tem_display(tem, &da, credp, called_from);
1321*1253Slq150181 }
1322*1253Slq150181 
1323*1253Slq150181 /*
1324*1253Slq150181  * This function is used to blit a rectangular color image,
1325*1253Slq150181  * unperturbed on the underlying framebuffer, to render
1326*1253Slq150181  * icons and pictures.  The data is a pixel pattern that
1327*1253Slq150181  * fills a rectangle bounded to the width and height parameters.
1328*1253Slq150181  * The color pixel data must to be pre-adjusted by the caller
1329*1253Slq150181  * for the current video depth.
1330*1253Slq150181  *
1331*1253Slq150181  * This function is unused now.
1332*1253Slq150181  */
1333*1253Slq150181 void
1334*1253Slq150181 tem_image_display(struct tem *tem, uchar_t *image,
1335*1253Slq150181 	int height, int width, screen_pos_t row, screen_pos_t col,
1336*1253Slq150181 	cred_t *credp, enum called_from called_from)
1337*1253Slq150181 {
1338*1253Slq150181 	struct vis_consdisplay da;
1339*1253Slq150181 
1340*1253Slq150181 	da.data = image;
1341*1253Slq150181 	da.width = width;
1342*1253Slq150181 	da.height = height;
1343*1253Slq150181 	da.row = row;
1344*1253Slq150181 	da.col = col;
1345*1253Slq150181 
1346*1253Slq150181 	tem_display(tem, &da, credp, called_from);
1347*1253Slq150181 }
1348*1253Slq150181 
1349*1253Slq150181 
1350*1253Slq150181 void
1351*1253Slq150181 tem_text_copy(struct tem *tem,
1352*1253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
1353*1253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
1354*1253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
1355*1253Slq150181 	cred_t *credp, enum called_from called_from)
1356*1253Slq150181 {
1357*1253Slq150181 	struct vis_conscopy da;
1358*1253Slq150181 
1359*1253Slq150181 	da.s_row = s_row;
1360*1253Slq150181 	da.s_col = s_col;
1361*1253Slq150181 	da.e_row = e_row;
1362*1253Slq150181 	da.e_col = e_col;
1363*1253Slq150181 	da.t_row = t_row;
1364*1253Slq150181 	da.t_col = t_col;
1365*1253Slq150181 
1366*1253Slq150181 	tem_copy(tem, &da, credp, called_from);
1367*1253Slq150181 }
1368*1253Slq150181 
1369*1253Slq150181 void
1370*1253Slq150181 tem_text_cls(struct tem *tem,
1371*1253Slq150181 	int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1372*1253Slq150181 	enum called_from called_from)
1373*1253Slq150181 {
1374*1253Slq150181 	struct vis_consdisplay da;
1375*1253Slq150181 
1376*1253Slq150181 	da.data = tem->state->a_blank_line;
1377*1253Slq150181 	da.width = count;
1378*1253Slq150181 	da.row = row;
1379*1253Slq150181 	da.col = col;
1380*1253Slq150181 
1381*1253Slq150181 	tem_get_color(tem, &da.fg_color, &da.bg_color);
1382*1253Slq150181 	tem_display(tem, &da, credp, called_from);
1383*1253Slq150181 }
1384*1253Slq150181 
1385*1253Slq150181 
1386*1253Slq150181 
1387*1253Slq150181 void
1388*1253Slq150181 tem_pix_display(struct tem *tem,
1389*1253Slq150181 	uchar_t *string, int count,
1390*1253Slq150181 	screen_pos_t row, screen_pos_t col,
1391*1253Slq150181 	text_color_t fg_color, text_color_t bg_color,
1392*1253Slq150181 	cred_t *credp, enum called_from called_from)
1393*1253Slq150181 {
1394*1253Slq150181 	struct tem_state *tems = tem->state;
1395*1253Slq150181 	struct vis_consdisplay da;
1396*1253Slq150181 	int	i;
1397*1253Slq150181 	da.data = (uchar_t *)tems->a_pix_data;
1398*1253Slq150181 	da.width = tems->a_font.width;
1399*1253Slq150181 	da.height = tems->a_font.height;
1400*1253Slq150181 	da.row = (row * da.height) + tems->a_p_offset.y;
1401*1253Slq150181 	da.col = (col * da.width) + tems->a_p_offset.x;
1402*1253Slq150181 
1403*1253Slq150181 	for (i = 0; i < count; i++) {
1404*1253Slq150181 		BIT_TO_PIX(tem, string[i], fg_color, bg_color);
1405*1253Slq150181 		tem_display(tem, &da, credp, called_from);
1406*1253Slq150181 		da.col += da.width;
1407*1253Slq150181 	}
1408*1253Slq150181 }
1409*1253Slq150181 
1410*1253Slq150181 void
1411*1253Slq150181 tem_pix_copy(struct tem *tem,
1412*1253Slq150181 	screen_pos_t s_col, screen_pos_t s_row,
1413*1253Slq150181 	screen_pos_t e_col, screen_pos_t e_row,
1414*1253Slq150181 	screen_pos_t t_col, screen_pos_t t_row,
1415*1253Slq150181 	cred_t *credp,
1416*1253Slq150181 	enum called_from called_from)
1417*1253Slq150181 {
1418*1253Slq150181 	struct tem_state *tems = tem->state;
1419*1253Slq150181 	struct vis_conscopy ma;
1420*1253Slq150181 	static boolean_t need_clear = B_TRUE;
1421*1253Slq150181 
1422*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1423*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1424*1253Slq150181 
1425*1253Slq150181 	if (need_clear && tems->first_line > 0) {
1426*1253Slq150181 		/*
1427*1253Slq150181 		 * Clear OBP output above our kernel console term
1428*1253Slq150181 		 * when our kernel console term begins to scroll up,
1429*1253Slq150181 		 * we hope it is user friendly.
1430*1253Slq150181 		 * (Also see comments on tem_pix_clear_prom_output)
1431*1253Slq150181 		 *
1432*1253Slq150181 		 * This is only one time call.
1433*1253Slq150181 		 */
1434*1253Slq150181 		tem_pix_clear_prom_output(tem, credp, called_from);
1435*1253Slq150181 	}
1436*1253Slq150181 	need_clear = B_FALSE;
1437*1253Slq150181 
1438*1253Slq150181 	ma.s_row = s_row * tems->a_font.height + tems->a_p_offset.y;
1439*1253Slq150181 	ma.e_row = (e_row + 1) * tems->a_font.height + tems->a_p_offset.y - 1;
1440*1253Slq150181 	ma.t_row = t_row * tems->a_font.height + tems->a_p_offset.y;
1441*1253Slq150181 
1442*1253Slq150181 	/*
1443*1253Slq150181 	 * Check if we're in process of clearing OBP's columns area,
1444*1253Slq150181 	 * which only happens when term scrolls up a whole line.
1445*1253Slq150181 	 */
1446*1253Slq150181 	if (tems->first_line > 0 && t_row < s_row && t_col == 0 &&
1447*1253Slq150181 	    e_col == tems->a_c_dimension.width - 1) {
1448*1253Slq150181 		/*
1449*1253Slq150181 		 * We need to clear OBP's columns area outside our kernel
1450*1253Slq150181 		 * console term. So that we set ma.e_col to entire row here.
1451*1253Slq150181 		 */
1452*1253Slq150181 		ma.s_col = s_col * tems->a_font.width;
1453*1253Slq150181 		ma.e_col = tems->a_p_dimension.width - 1;
1454*1253Slq150181 
1455*1253Slq150181 		ma.t_col = t_col * tems->a_font.width;
1456*1253Slq150181 	} else {
1457*1253Slq150181 		ma.s_col = s_col * tems->a_font.width + tems->a_p_offset.x;
1458*1253Slq150181 		ma.e_col = (e_col + 1) * tems->a_font.width +
1459*1253Slq150181 		    tems->a_p_offset.x - 1;
1460*1253Slq150181 		ma.t_col = t_col * tems->a_font.width + tems->a_p_offset.x;
1461*1253Slq150181 	}
1462*1253Slq150181 
1463*1253Slq150181 	tem_copy(tem, &ma, credp, called_from);
1464*1253Slq150181 
1465*1253Slq150181 	if (tems->first_line > 0 && t_row < s_row) {
1466*1253Slq150181 		/* We have scrolled up (s_row - t_row) rows. */
1467*1253Slq150181 		tems->first_line -= (s_row - t_row);
1468*1253Slq150181 		if (tems->first_line <= 0) {
1469*1253Slq150181 			/* All OBP rows have been cleared. */
1470*1253Slq150181 			tems->first_line = 0;
1471*1253Slq150181 		}
1472*1253Slq150181 	}
1473*1253Slq150181 
1474*1253Slq150181 }
1475*1253Slq150181 
1476*1253Slq150181 /*
1477*1253Slq150181  * This function only clears count of columns in one row
1478*1253Slq150181  */
1479*1253Slq150181 void
1480*1253Slq150181 tem_pix_cls(struct tem *tem, int count,
1481*1253Slq150181 	screen_pos_t row, screen_pos_t col, cred_t *credp,
1482*1253Slq150181 	enum called_from called_from)
1483*1253Slq150181 {
1484*1253Slq150181 	struct tem_state *tems = tem->state;
1485*1253Slq150181 
1486*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1487*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1488*1253Slq150181 
1489*1253Slq150181 	tem_pix_cls_range(tem, row, 1, tems->a_p_offset.y,
1490*1253Slq150181 	    col, count, tems->a_p_offset.x, B_FALSE, credp, called_from);
1491*1253Slq150181 }
1492*1253Slq150181 
1493*1253Slq150181 /*
1494*1253Slq150181  * This function clears OBP output above our kernel console term area
1495*1253Slq150181  * because OBP's term may have a bigger terminal window than that of
1496*1253Slq150181  * our kernel console term. So we need to clear OBP output garbage outside
1497*1253Slq150181  * of our kernel console term at a proper time, which is when the first
1498*1253Slq150181  * row output of our kernel console term scrolls at the first screen line.
1499*1253Slq150181  *
1500*1253Slq150181  *	_________________________________
1501*1253Slq150181  *	|   _____________________	|  ---> OBP's bigger term window
1502*1253Slq150181  *	|   |			|	|
1503*1253Slq150181  *	|___|			|	|
1504*1253Slq150181  *	| | |			|	|
1505*1253Slq150181  *	| | |			|	|
1506*1253Slq150181  *	|_|_|___________________|_______|
1507*1253Slq150181  *	  | |			|	   ---> first line
1508*1253Slq150181  *	  | |___________________|---> our kernel console term window
1509*1253Slq150181  *	  |
1510*1253Slq150181  *	  |---> columns area to be cleared
1511*1253Slq150181  *
1512*1253Slq150181  * This function only takes care of the output above our kernel console term,
1513*1253Slq150181  * and tem_prom_scroll_up takes care of columns area outside of our kernel
1514*1253Slq150181  * console term.
1515*1253Slq150181  */
1516*1253Slq150181 static void
1517*1253Slq150181 tem_pix_clear_prom_output(struct tem *tem, cred_t *credp,
1518*1253Slq150181     enum called_from called_from)
1519*1253Slq150181 {
1520*1253Slq150181 	struct tem_state *tems = tem->state;
1521*1253Slq150181 	int	nrows, ncols, width, height;
1522*1253Slq150181 
1523*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1524*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1525*1253Slq150181 
1526*1253Slq150181 	width = tems->a_font.width;
1527*1253Slq150181 	height = tems->a_font.height;
1528*1253Slq150181 
1529*1253Slq150181 	nrows = (tems->a_p_offset.y + (height - 1))/ height;
1530*1253Slq150181 	ncols = (tems->a_p_dimension.width + (width - 1))/ width;
1531*1253Slq150181 
1532*1253Slq150181 	tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1533*1253Slq150181 	    B_FALSE, credp, called_from);
1534*1253Slq150181 }
1535*1253Slq150181 
1536*1253Slq150181 /*
1537*1253Slq150181  * clear the whole screen for pixel mode
1538*1253Slq150181  */
1539*1253Slq150181 static void
1540*1253Slq150181 tem_pix_clear_entire_screen(struct tem *tem, cred_t *credp,
1541*1253Slq150181     enum called_from called_from)
1542*1253Slq150181 {
1543*1253Slq150181 	struct tem_state *tems = tem->state;
1544*1253Slq150181 	int	nrows, ncols, width, height;
1545*1253Slq150181 
1546*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1547*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1548*1253Slq150181 
1549*1253Slq150181 	width = tems->a_font.width;
1550*1253Slq150181 	height = tems->a_font.height;
1551*1253Slq150181 
1552*1253Slq150181 	nrows = (tems->a_p_dimension.height + (height - 1))/ height;
1553*1253Slq150181 	ncols = (tems->a_p_dimension.width + (width - 1))/ width;
1554*1253Slq150181 
1555*1253Slq150181 	tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1556*1253Slq150181 	    B_FALSE, credp, called_from);
1557*1253Slq150181 
1558*1253Slq150181 	tems->a_c_cursor.row = 0;
1559*1253Slq150181 	tems->a_c_cursor.col = 0;
1560*1253Slq150181 	tem_align_cursor(tem);
1561*1253Slq150181 
1562*1253Slq150181 	/*
1563*1253Slq150181 	 * Since the whole screen is cleared, we don't need
1564*1253Slq150181 	 * to clear OBP output later.
1565*1253Slq150181 	 */
1566*1253Slq150181 	if (tems->first_line > 0) {
1567*1253Slq150181 		tems->first_line = 0;
1568*1253Slq150181 	}
1569*1253Slq150181 }
1570*1253Slq150181 
1571*1253Slq150181 /*
1572*1253Slq150181  * clear the whole screen
1573*1253Slq150181  */
1574*1253Slq150181 static void
1575*1253Slq150181 tem_cls(struct tem *tem,
1576*1253Slq150181     cred_t *credp, enum called_from called_from)
1577*1253Slq150181 {
1578*1253Slq150181 	struct tem_state *tems = tem->state;
1579*1253Slq150181 	int	row;
1580*1253Slq150181 
1581*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1582*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1583*1253Slq150181 
1584*1253Slq150181 	if (tems->display_mode == VIS_TEXT) {
1585*1253Slq150181 		for (row = 0; row < tems->a_c_dimension.height; row++) {
1586*1253Slq150181 			tem_clear_chars(tem, tems->a_c_dimension.width,
1587*1253Slq150181 				row, 0, credp, called_from);
1588*1253Slq150181 		}
1589*1253Slq150181 		tems->a_c_cursor.row = 0;
1590*1253Slq150181 		tems->a_c_cursor.col = 0;
1591*1253Slq150181 		tem_align_cursor(tem);
1592*1253Slq150181 		return;
1593*1253Slq150181 	}
1594*1253Slq150181 
1595*1253Slq150181 	ASSERT(tems->display_mode == VIS_PIXEL);
1596*1253Slq150181 
1597*1253Slq150181 	tem_pix_clear_entire_screen(tem, credp, called_from);
1598*1253Slq150181 }
1599*1253Slq150181 
1600*1253Slq150181 static void
1601*1253Slq150181 tem_back_tab(struct tem *tem,
1602*1253Slq150181     cred_t *credp, enum called_from called_from)
1603*1253Slq150181 {
1604*1253Slq150181 	struct tem_state *tems = tem->state;
1605*1253Slq150181 	int	i;
1606*1253Slq150181 	screen_pos_t	tabstop;
1607*1253Slq150181 
1608*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1609*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1610*1253Slq150181 
1611*1253Slq150181 	tabstop = 0;
1612*1253Slq150181 
1613*1253Slq150181 	for (i = tems->a_ntabs - 1; i >= 0; i--) {
1614*1253Slq150181 		if (tems->a_tabs[i] < tems->a_c_cursor.col) {
1615*1253Slq150181 			tabstop = tems->a_tabs[i];
1616*1253Slq150181 			break;
1617*1253Slq150181 		}
1618*1253Slq150181 	}
1619*1253Slq150181 
1620*1253Slq150181 	tem_mv_cursor(tem, tems->a_c_cursor.row,
1621*1253Slq150181 	tabstop, credp, called_from);
1622*1253Slq150181 }
1623*1253Slq150181 
1624*1253Slq150181 static void
1625*1253Slq150181 tem_tab(struct tem *tem,
1626*1253Slq150181     cred_t *credp, enum called_from called_from)
1627*1253Slq150181 {
1628*1253Slq150181 	struct tem_state *tems = tem->state;
1629*1253Slq150181 	int	i;
1630*1253Slq150181 	screen_pos_t	tabstop;
1631*1253Slq150181 
1632*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1633*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1634*1253Slq150181 
1635*1253Slq150181 	tabstop = tems->a_c_dimension.width - 1;
1636*1253Slq150181 
1637*1253Slq150181 	for (i = 0; i < tems->a_ntabs; i++) {
1638*1253Slq150181 		if (tems->a_tabs[i] > tems->a_c_cursor.col) {
1639*1253Slq150181 			tabstop = tems->a_tabs[i];
1640*1253Slq150181 			break;
1641*1253Slq150181 		}
1642*1253Slq150181 	}
1643*1253Slq150181 
1644*1253Slq150181 	tem_mv_cursor(tem, tems->a_c_cursor.row,
1645*1253Slq150181 	    tabstop, credp, called_from);
1646*1253Slq150181 }
1647*1253Slq150181 
1648*1253Slq150181 static void
1649*1253Slq150181 tem_set_tab(struct tem *tem)
1650*1253Slq150181 {
1651*1253Slq150181 	struct tem_state *tems = tem->state;
1652*1253Slq150181 	int	i;
1653*1253Slq150181 	int	j;
1654*1253Slq150181 
1655*1253Slq150181 	if (tems->a_ntabs == TEM_MAXTAB)
1656*1253Slq150181 		return;
1657*1253Slq150181 	if (tems->a_ntabs == 0 ||
1658*1253Slq150181 		tems->a_tabs[tems->a_ntabs] < tems->a_c_cursor.col) {
1659*1253Slq150181 			tems->a_tabs[tems->a_ntabs++] = tems->a_c_cursor.col;
1660*1253Slq150181 			return;
1661*1253Slq150181 	}
1662*1253Slq150181 	for (i = 0; i < tems->a_ntabs; i++) {
1663*1253Slq150181 		if (tems->a_tabs[i] == tems->a_c_cursor.col)
1664*1253Slq150181 			return;
1665*1253Slq150181 		if (tems->a_tabs[i] > tems->a_c_cursor.col) {
1666*1253Slq150181 			for (j = tems->a_ntabs - 1; j >= i; j--)
1667*1253Slq150181 				tems->a_tabs[j+ 1] = tems->a_tabs[j];
1668*1253Slq150181 			tems->a_tabs[i] = tems->a_c_cursor.col;
1669*1253Slq150181 			tems->a_ntabs++;
1670*1253Slq150181 			return;
1671*1253Slq150181 		}
1672*1253Slq150181 	}
1673*1253Slq150181 }
1674*1253Slq150181 
1675*1253Slq150181 static void
1676*1253Slq150181 tem_clear_tabs(struct tem *tem, int action)
1677*1253Slq150181 {
1678*1253Slq150181 	struct tem_state *tems = tem->state;
1679*1253Slq150181 	int	i;
1680*1253Slq150181 	int	j;
1681*1253Slq150181 
1682*1253Slq150181 	switch (action) {
1683*1253Slq150181 	case 3: /* clear all tabs */
1684*1253Slq150181 		tems->a_ntabs = 0;
1685*1253Slq150181 		break;
1686*1253Slq150181 	case 0: /* clr tab at cursor */
1687*1253Slq150181 
1688*1253Slq150181 		for (i = 0; i < tems->a_ntabs; i++) {
1689*1253Slq150181 			if (tems->a_tabs[i] == tems->a_c_cursor.col) {
1690*1253Slq150181 				tems->a_ntabs--;
1691*1253Slq150181 				for (j = i; j < tems->a_ntabs; j++)
1692*1253Slq150181 					tems->a_tabs[j] = tems->a_tabs[j + 1];
1693*1253Slq150181 				return;
1694*1253Slq150181 			}
1695*1253Slq150181 		}
1696*1253Slq150181 		break;
1697*1253Slq150181 	}
1698*1253Slq150181 }
1699*1253Slq150181 
1700*1253Slq150181 static void
1701*1253Slq150181 tem_mv_cursor(struct tem *tem, int row, int col,
1702*1253Slq150181     cred_t *credp, enum called_from called_from)
1703*1253Slq150181 {
1704*1253Slq150181 	struct tem_state *tems = tem->state;
1705*1253Slq150181 
1706*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1707*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1708*1253Slq150181 
1709*1253Slq150181 	/*
1710*1253Slq150181 	 * Sanity check and bounds enforcement.  Out of bounds requests are
1711*1253Slq150181 	 * clipped to the screen boundaries.  This seems to be what SPARC
1712*1253Slq150181 	 * does.
1713*1253Slq150181 	 */
1714*1253Slq150181 	if (row < 0)
1715*1253Slq150181 		row = 0;
1716*1253Slq150181 	if (row >= tems->a_c_dimension.height)
1717*1253Slq150181 		row = tems->a_c_dimension.height - 1;
1718*1253Slq150181 	if (col < 0)
1719*1253Slq150181 		col = 0;
1720*1253Slq150181 	if (col >= tems->a_c_dimension.width)
1721*1253Slq150181 		col = tems->a_c_dimension.width - 1;
1722*1253Slq150181 
1723*1253Slq150181 	tem_send_data(tem, credp, called_from);
1724*1253Slq150181 	tems->a_c_cursor.row = row;
1725*1253Slq150181 	tems->a_c_cursor.col = col;
1726*1253Slq150181 	tem_align_cursor(tem);
1727*1253Slq150181 }
1728*1253Slq150181 
1729*1253Slq150181 /* ARGSUSED */
1730*1253Slq150181 void
1731*1253Slq150181 tem_reset_emulator(struct tem *tem,
1732*1253Slq150181     cred_t *credp, enum called_from called_from)
1733*1253Slq150181 {
1734*1253Slq150181 	struct tem_state *tems = tem->state;
1735*1253Slq150181 	int j;
1736*1253Slq150181 
1737*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1738*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1739*1253Slq150181 
1740*1253Slq150181 	tems->a_c_cursor.row = 0;
1741*1253Slq150181 	tems->a_c_cursor.col = 0;
1742*1253Slq150181 	tems->a_r_cursor.row = 0;
1743*1253Slq150181 	tems->a_r_cursor.col = 0;
1744*1253Slq150181 	tems->a_s_cursor.row = 0;
1745*1253Slq150181 	tems->a_s_cursor.col = 0;
1746*1253Slq150181 	tems->a_outindex = 0;
1747*1253Slq150181 	tems->a_state = A_STATE_START;
1748*1253Slq150181 	tems->a_gotparam = B_FALSE;
1749*1253Slq150181 	tems->a_curparam = 0;
1750*1253Slq150181 	tems->a_paramval = 0;
1751*1253Slq150181 	tems->a_flags = 0;
1752*1253Slq150181 	tems->a_nscroll = 1;
1753*1253Slq150181 	tems->fg_color = DEFAULT_ANSI_FOREGROUND;
1754*1253Slq150181 	tems->bg_color = DEFAULT_ANSI_BACKGROUND;
1755*1253Slq150181 
1756*1253Slq150181 	/*
1757*1253Slq150181 	 * set up the initial tab stops
1758*1253Slq150181 	 */
1759*1253Slq150181 	tems->a_ntabs = 0;
1760*1253Slq150181 	for (j = 8; j < tems->a_c_dimension.width; j += 8)
1761*1253Slq150181 		tems->a_tabs[tems->a_ntabs++] = (screen_pos_t)j;
1762*1253Slq150181 
1763*1253Slq150181 	for (j = 0; j < TEM_MAXPARAMS; j++)
1764*1253Slq150181 		tems->a_params[j] = 0;
1765*1253Slq150181 }
1766*1253Slq150181 
1767*1253Slq150181 void
1768*1253Slq150181 tem_reset_display(struct tem *tem,
1769*1253Slq150181     cred_t *credp, enum called_from called_from, int clear_txt)
1770*1253Slq150181 {
1771*1253Slq150181 	struct tem_state *tems = tem->state;
1772*1253Slq150181 
1773*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1774*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1775*1253Slq150181 
1776*1253Slq150181 	tem_reset_emulator(tem, credp, called_from);
1777*1253Slq150181 	tem_reset_colormap(tem, credp, called_from);
1778*1253Slq150181 
1779*1253Slq150181 	if (clear_txt) {
1780*1253Slq150181 		(*tems->in_fp.f_cursor)(tem,
1781*1253Slq150181 		    VIS_HIDE_CURSOR, credp, called_from);
1782*1253Slq150181 
1783*1253Slq150181 		tem_cls(tem, credp, called_from);
1784*1253Slq150181 
1785*1253Slq150181 		(*tems->in_fp.f_cursor)(tem,
1786*1253Slq150181 		    VIS_DISPLAY_CURSOR, credp, called_from);
1787*1253Slq150181 	}
1788*1253Slq150181 
1789*1253Slq150181 	tems->a_initialized = 1;
1790*1253Slq150181 }
1791*1253Slq150181 
1792*1253Slq150181 
1793*1253Slq150181 static void
1794*1253Slq150181 tem_shift(
1795*1253Slq150181 	struct tem *tem,
1796*1253Slq150181 	int count,
1797*1253Slq150181 	int direction,
1798*1253Slq150181 	cred_t *credp,
1799*1253Slq150181 	enum called_from called_from)
1800*1253Slq150181 {
1801*1253Slq150181 	struct tem_state *tems = tem->state;
1802*1253Slq150181 	int rest_of_line;
1803*1253Slq150181 
1804*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1805*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1806*1253Slq150181 
1807*1253Slq150181 	rest_of_line = tems->a_c_dimension.width - tems->a_c_cursor.col;
1808*1253Slq150181 	if (count > rest_of_line)
1809*1253Slq150181 		count = rest_of_line;
1810*1253Slq150181 
1811*1253Slq150181 	if (count <= 0)
1812*1253Slq150181 		return;
1813*1253Slq150181 
1814*1253Slq150181 	switch (direction) {
1815*1253Slq150181 	case TEM_SHIFT_LEFT:
1816*1253Slq150181 		if (count < rest_of_line) {
1817*1253Slq150181 			tem_copy_area(tem,
1818*1253Slq150181 				tems->a_c_cursor.col + count,
1819*1253Slq150181 				tems->a_c_cursor.row,
1820*1253Slq150181 				tems->a_c_dimension.width - 1,
1821*1253Slq150181 				tems->a_c_cursor.row,
1822*1253Slq150181 				tems->a_c_cursor.col,
1823*1253Slq150181 				tems->a_c_cursor.row,
1824*1253Slq150181 				credp, called_from);
1825*1253Slq150181 		}
1826*1253Slq150181 
1827*1253Slq150181 		tem_clear_chars(tem, count, tems->a_c_cursor.row,
1828*1253Slq150181 			(tems->a_c_dimension.width - count), credp,
1829*1253Slq150181 			called_from);
1830*1253Slq150181 		break;
1831*1253Slq150181 	case TEM_SHIFT_RIGHT:
1832*1253Slq150181 		if (count < rest_of_line) {
1833*1253Slq150181 			tem_copy_area(tem,
1834*1253Slq150181 				tems->a_c_cursor.col,
1835*1253Slq150181 				tems->a_c_cursor.row,
1836*1253Slq150181 				tems->a_c_dimension.width - count - 1,
1837*1253Slq150181 				tems->a_c_cursor.row,
1838*1253Slq150181 				tems->a_c_cursor.col + count,
1839*1253Slq150181 				tems->a_c_cursor.row,
1840*1253Slq150181 				credp, called_from);
1841*1253Slq150181 		}
1842*1253Slq150181 
1843*1253Slq150181 		tem_clear_chars(tem, count, tems->a_c_cursor.row,
1844*1253Slq150181 			tems->a_c_cursor.col, credp, called_from);
1845*1253Slq150181 		break;
1846*1253Slq150181 	}
1847*1253Slq150181 }
1848*1253Slq150181 
1849*1253Slq150181 void
1850*1253Slq150181 tem_text_cursor(struct tem *tem, short action,
1851*1253Slq150181     cred_t *credp, enum called_from called_from)
1852*1253Slq150181 {
1853*1253Slq150181 	struct tem_state *tems = tem->state;
1854*1253Slq150181 	struct vis_conscursor	ca;
1855*1253Slq150181 
1856*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1857*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1858*1253Slq150181 
1859*1253Slq150181 	ca.row = tems->a_c_cursor.row;
1860*1253Slq150181 	ca.col = tems->a_c_cursor.col;
1861*1253Slq150181 	ca.action = action;
1862*1253Slq150181 
1863*1253Slq150181 	tem_cursor(tem, &ca, credp, called_from);
1864*1253Slq150181 
1865*1253Slq150181 	if (action == VIS_GET_CURSOR) {
1866*1253Slq150181 		tems->a_c_cursor.row = ca.row;
1867*1253Slq150181 		tems->a_c_cursor.col = ca.col;
1868*1253Slq150181 	}
1869*1253Slq150181 }
1870*1253Slq150181 
1871*1253Slq150181 
1872*1253Slq150181 void
1873*1253Slq150181 tem_pix_cursor(struct tem *tem, short action,
1874*1253Slq150181     cred_t *credp, enum called_from called_from)
1875*1253Slq150181 {
1876*1253Slq150181 	struct tem_state *tems = tem->state;
1877*1253Slq150181 	struct vis_conscursor	ca;
1878*1253Slq150181 
1879*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1880*1253Slq150181 	    MUTEX_HELD(&tem->lock));
1881*1253Slq150181 
1882*1253Slq150181 	ca.row = tems->a_c_cursor.row * tems->a_font.height +
1883*1253Slq150181 				tems->a_p_offset.y;
1884*1253Slq150181 	ca.col = tems->a_c_cursor.col * tems->a_font.width +
1885*1253Slq150181 				tems->a_p_offset.x;
1886*1253Slq150181 	ca.width = tems->a_font.width;
1887*1253Slq150181 	ca.height = tems->a_font.height;
1888*1253Slq150181 	if (tems->a_pdepth == 8 || tems->a_pdepth == 4) {
1889*1253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
1890*1253Slq150181 			ca.fg_color.mono = TEM_TEXT_WHITE;
1891*1253Slq150181 			ca.bg_color.mono = TEM_TEXT_BLACK;
1892*1253Slq150181 		} else {
1893*1253Slq150181 			ca.fg_color.mono = TEM_TEXT_BLACK;
1894*1253Slq150181 			ca.bg_color.mono = TEM_TEXT_WHITE;
1895*1253Slq150181 		}
1896*1253Slq150181 	} else if (tems->a_pdepth == 24 || tems->a_pdepth == 32) {
1897*1253Slq150181 		if (tems->a_flags & TEM_ATTR_REVERSE) {
1898*1253Slq150181 			ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
1899*1253Slq150181 			ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
1900*1253Slq150181 			ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
1901*1253Slq150181 
1902*1253Slq150181 			ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
1903*1253Slq150181 			ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
1904*1253Slq150181 			ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
1905*1253Slq150181 		} else {
1906*1253Slq150181 			ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
1907*1253Slq150181 			ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
1908*1253Slq150181 			ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
1909*1253Slq150181 
1910*1253Slq150181 			ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
1911*1253Slq150181 			ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
1912*1253Slq150181 			ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
1913*1253Slq150181 		}
1914*1253Slq150181 	}
1915*1253Slq150181 
1916*1253Slq150181 	ca.action = action;
1917*1253Slq150181 
1918*1253Slq150181 	tem_cursor(tem, &ca, credp, called_from);
1919*1253Slq150181 }
1920*1253Slq150181 
1921*1253Slq150181 #define	BORDER_PIXELS 10
1922*1253Slq150181 void
1923*1253Slq150181 set_font(struct font *f, short *rows, short *cols, short height, short width)
1924*1253Slq150181 {
1925*1253Slq150181 	bitmap_data_t	*font_selected = NULL;
1926*1253Slq150181 	struct fontlist	*fl;
1927*1253Slq150181 
1928*1253Slq150181 	/*
1929*1253Slq150181 	 * Find best font for these dimensions, or use default
1930*1253Slq150181 	 *
1931*1253Slq150181 	 * A 1 pixel border is the absolute minimum we could have
1932*1253Slq150181 	 * as a border around the text window (BORDER_PIXELS = 2),
1933*1253Slq150181 	 * however a slightly larger border not only looks better
1934*1253Slq150181 	 * but for the fonts currently statically built into the
1935*1253Slq150181 	 * emulator causes much better font selection for the
1936*1253Slq150181 	 * normal range of screen resolutions.
1937*1253Slq150181 	 */
1938*1253Slq150181 	for (fl = fonts; fl->data; fl++) {
1939*1253Slq150181 		if ((((*rows * fl->data->height) + BORDER_PIXELS) <= height) &&
1940*1253Slq150181 		    (((*cols * fl->data->width) + BORDER_PIXELS) <= width)) {
1941*1253Slq150181 			font_selected = fl->data;
1942*1253Slq150181 			break;
1943*1253Slq150181 		}
1944*1253Slq150181 	}
1945*1253Slq150181 	/*
1946*1253Slq150181 	 * The minus 2 is to make sure we have at least a 1 pixel
1947*1253Slq150181 	 * boarder around the entire screen.
1948*1253Slq150181 	 */
1949*1253Slq150181 	if (font_selected == NULL) {
1950*1253Slq150181 		if (((*rows * DEFAULT_FONT_DATA.height) > height) ||
1951*1253Slq150181 		    ((*cols * DEFAULT_FONT_DATA.width) > width)) {
1952*1253Slq150181 			*rows = (height - 2) / DEFAULT_FONT_DATA.height;
1953*1253Slq150181 			*cols = (width - 2) / DEFAULT_FONT_DATA.width;
1954*1253Slq150181 		}
1955*1253Slq150181 		font_selected = &DEFAULT_FONT_DATA;
1956*1253Slq150181 	}
1957*1253Slq150181 
1958*1253Slq150181 	f->width = font_selected->width;
1959*1253Slq150181 	f->height = font_selected->height;
1960*1253Slq150181 	bcopy((caddr_t)font_selected->encoding, (caddr_t)f->char_ptr,
1961*1253Slq150181 			sizeof (f->char_ptr));
1962*1253Slq150181 	f->image_data = font_selected->image;
1963*1253Slq150181 
1964*1253Slq150181 }
1965*1253Slq150181 
1966*1253Slq150181 /*
1967*1253Slq150181  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
1968*1253Slq150181  * for each 2 bits of input bitmap.  It inverts the input bits before
1969*1253Slq150181  * doing the output translation, for reverse video.
1970*1253Slq150181  *
1971*1253Slq150181  * Assuming foreground is 0001 and background is 0000...
1972*1253Slq150181  * An input data byte of 0x53 will output the bit pattern
1973*1253Slq150181  * 00000001 00000001 00000000 00010001.
1974*1253Slq150181  */
1975*1253Slq150181 
1976*1253Slq150181 void
1977*1253Slq150181 bit_to_pix4(
1978*1253Slq150181     struct tem *tem,
1979*1253Slq150181     uchar_t c,
1980*1253Slq150181     text_color_t fg_color,
1981*1253Slq150181     text_color_t bg_color)
1982*1253Slq150181 {
1983*1253Slq150181 	struct tem_state *tems = tem->state;
1984*1253Slq150181 	int	row;
1985*1253Slq150181 	int	byte;
1986*1253Slq150181 	int	i;
1987*1253Slq150181 	uint8_t	*cp;
1988*1253Slq150181 	uint8_t	data;
1989*1253Slq150181 	uint8_t	nibblett;
1990*1253Slq150181 	int	bytes_wide;
1991*1253Slq150181 	uint8_t *dest;
1992*1253Slq150181 
1993*1253Slq150181 	dest = (uint8_t *)tems->a_pix_data;
1994*1253Slq150181 
1995*1253Slq150181 	cp = tems->a_font.char_ptr[c];
1996*1253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
1997*1253Slq150181 
1998*1253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
1999*1253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
2000*1253Slq150181 			data = *cp++;
2001*1253Slq150181 			for (i = 0; i < 4; i++) {
2002*1253Slq150181 				nibblett = (data >> ((3-i) * 2)) & 0x3;
2003*1253Slq150181 				switch (nibblett) {
2004*1253Slq150181 				case 0x0:
2005*1253Slq150181 					*dest++ = bg_color << 4 | bg_color;
2006*1253Slq150181 					break;
2007*1253Slq150181 				case 0x1:
2008*1253Slq150181 					*dest++ = bg_color << 4 | fg_color;
2009*1253Slq150181 					break;
2010*1253Slq150181 				case 0x2:
2011*1253Slq150181 					*dest++ = fg_color << 4 | bg_color;
2012*1253Slq150181 					break;
2013*1253Slq150181 				case 0x3:
2014*1253Slq150181 					*dest++ = fg_color << 4 | fg_color;
2015*1253Slq150181 					break;
2016*1253Slq150181 				}
2017*1253Slq150181 			}
2018*1253Slq150181 		}
2019*1253Slq150181 	}
2020*1253Slq150181 }
2021*1253Slq150181 
2022*1253Slq150181 /*
2023*1253Slq150181  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
2024*1253Slq150181  * for each bit of input bitmap.  It inverts the input bits before
2025*1253Slq150181  * doing the output translation, for reverse video.
2026*1253Slq150181  *
2027*1253Slq150181  * Assuming foreground is 00000001 and background is 00000000...
2028*1253Slq150181  * An input data byte of 0x53 will output the bit pattern
2029*1253Slq150181  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
2030*1253Slq150181  */
2031*1253Slq150181 
2032*1253Slq150181 void
2033*1253Slq150181 bit_to_pix8(
2034*1253Slq150181     struct tem *tem,
2035*1253Slq150181     uchar_t c,
2036*1253Slq150181     text_color_t fg_color,
2037*1253Slq150181     text_color_t bg_color)
2038*1253Slq150181 {
2039*1253Slq150181 	struct tem_state *tems = tem->state;
2040*1253Slq150181 	int	row;
2041*1253Slq150181 	int	byte;
2042*1253Slq150181 	int	i;
2043*1253Slq150181 	uint8_t	*cp;
2044*1253Slq150181 	uint8_t	data;
2045*1253Slq150181 	int	bytes_wide;
2046*1253Slq150181 	uint8_t	mask;
2047*1253Slq150181 	int	bitsleft, nbits;
2048*1253Slq150181 	uint8_t *dest;
2049*1253Slq150181 
2050*1253Slq150181 	dest = (uint8_t *)tems->a_pix_data;
2051*1253Slq150181 
2052*1253Slq150181 	cp = tems->a_font.char_ptr[c];
2053*1253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
2054*1253Slq150181 
2055*1253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
2056*1253Slq150181 		bitsleft = tems->a_font.width;
2057*1253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
2058*1253Slq150181 			data = *cp++;
2059*1253Slq150181 			mask = 0x80;
2060*1253Slq150181 			nbits = MIN(8, bitsleft);
2061*1253Slq150181 			bitsleft -= nbits;
2062*1253Slq150181 			for (i = 0; i < nbits; i++) {
2063*1253Slq150181 				*dest++ = (data & mask ? fg_color: bg_color);
2064*1253Slq150181 				mask = mask >> 1;
2065*1253Slq150181 			}
2066*1253Slq150181 		}
2067*1253Slq150181 	}
2068*1253Slq150181 }
2069*1253Slq150181 
2070*1253Slq150181 /*
2071*1253Slq150181  * bit_to_pix24 is for 24-bit frame buffers.  It will write four output bytes
2072*1253Slq150181  * for each bit of input bitmap.  It inverts the input bits before
2073*1253Slq150181  * doing the output translation, for reverse video.  Note that each
2074*1253Slq150181  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
2075*1253Slq150181  * high-order byte set to zero.
2076*1253Slq150181  *
2077*1253Slq150181  * Assuming foreground is 00000000 11111111 11111111 11111111
2078*1253Slq150181  * and background is 00000000 00000000 00000000 00000000
2079*1253Slq150181  * An input data byte of 0x53 will output the bit pattern
2080*1253Slq150181  *
2081*1253Slq150181  * 00000000 00000000 00000000 00000000
2082*1253Slq150181  * 00000000 11111111 11111111 11111111
2083*1253Slq150181  * 00000000 00000000 00000000 00000000
2084*1253Slq150181  * 00000000 11111111 11111111 11111111
2085*1253Slq150181  * 00000000 00000000 00000000 00000000
2086*1253Slq150181  * 00000000 00000000 00000000 00000000
2087*1253Slq150181  * 00000000 11111111 11111111 11111111
2088*1253Slq150181  * 00000000 11111111 11111111 11111111
2089*1253Slq150181  *
2090*1253Slq150181  */
2091*1253Slq150181 typedef uint32_t pixel32_t;
2092*1253Slq150181 
2093*1253Slq150181 void
2094*1253Slq150181 bit_to_pix24(
2095*1253Slq150181 	struct tem *tem,
2096*1253Slq150181 	uchar_t c,
2097*1253Slq150181 	text_color_t fg_color4,
2098*1253Slq150181 	text_color_t bg_color4)
2099*1253Slq150181 {
2100*1253Slq150181 	struct tem_state *tems = tem->state;
2101*1253Slq150181 	int	row;
2102*1253Slq150181 	int	byte;
2103*1253Slq150181 	int	i;
2104*1253Slq150181 	uint8_t	*cp;
2105*1253Slq150181 	uint8_t	data;
2106*1253Slq150181 	int	bytes_wide;
2107*1253Slq150181 	int	bitsleft, nbits;
2108*1253Slq150181 
2109*1253Slq150181 	pixel32_t fg_color32, bg_color32, *destp;
2110*1253Slq150181 
2111*1253Slq150181 	ASSERT(fg_color4 < 16 && bg_color4 < 16);
2112*1253Slq150181 
2113*1253Slq150181 	fg_color32 = PIX4TO32(fg_color4);
2114*1253Slq150181 	bg_color32 = PIX4TO32(bg_color4);
2115*1253Slq150181 
2116*1253Slq150181 	destp = (pixel32_t *)tems->a_pix_data;
2117*1253Slq150181 	cp = tems->a_font.char_ptr[c];
2118*1253Slq150181 	bytes_wide = (tems->a_font.width + 7) / 8;
2119*1253Slq150181 
2120*1253Slq150181 	for (row = 0; row < tems->a_font.height; row++) {
2121*1253Slq150181 		bitsleft = tems->a_font.width;
2122*1253Slq150181 		for (byte = 0; byte < bytes_wide; byte++) {
2123*1253Slq150181 			data = *cp++;
2124*1253Slq150181 			nbits = MIN(8, bitsleft);
2125*1253Slq150181 			bitsleft -= nbits;
2126*1253Slq150181 			for (i = 0; i < nbits; i++) {
2127*1253Slq150181 			    *destp++ = ((data << i) & 0x80 ?
2128*1253Slq150181 				fg_color32 : bg_color32);
2129*1253Slq150181 			}
2130*1253Slq150181 		}
2131*1253Slq150181 	}
2132*1253Slq150181 }
2133*1253Slq150181 
2134*1253Slq150181 /* ARGSUSED */
2135*1253Slq150181 text_color_t
2136*1253Slq150181 ansi_bg_to_solaris(struct tem *tem, int ansi)
2137*1253Slq150181 {
2138*1253Slq150181 	return (bg_xlate[ansi]);
2139*1253Slq150181 }
2140*1253Slq150181 
2141*1253Slq150181 text_color_t
2142*1253Slq150181 ansi_fg_to_solaris(struct tem *tem, int ansi)
2143*1253Slq150181 {
2144*1253Slq150181 	if (tem->state->a_flags & TEM_ATTR_BOLD)
2145*1253Slq150181 	    return (fg_brt_xlate[ansi]);
2146*1253Slq150181 	else
2147*1253Slq150181 	    return (fg_dim_xlate[ansi]);
2148*1253Slq150181 }
2149*1253Slq150181 
2150*1253Slq150181 static void
2151*1253Slq150181 tem_get_color(struct tem *tem, text_color_t *fg, text_color_t *bg)
2152*1253Slq150181 {
2153*1253Slq150181 	if (tem->state->a_flags & TEM_ATTR_SCREEN_REVERSE) {
2154*1253Slq150181 		*fg = ansi_fg_to_solaris(tem,
2155*1253Slq150181 		    DEFAULT_ANSI_BACKGROUND);
2156*1253Slq150181 		*bg = ansi_bg_to_solaris(tem,
2157*1253Slq150181 		    DEFAULT_ANSI_FOREGROUND);
2158*1253Slq150181 	} else {
2159*1253Slq150181 		*fg = ansi_fg_to_solaris(tem,
2160*1253Slq150181 		    DEFAULT_ANSI_FOREGROUND);
2161*1253Slq150181 		*bg = ansi_bg_to_solaris(tem,
2162*1253Slq150181 		    DEFAULT_ANSI_BACKGROUND);
2163*1253Slq150181 	}
2164*1253Slq150181 }
2165*1253Slq150181 
2166*1253Slq150181 /*
2167*1253Slq150181  * Clear a rectangle of screen for pixel mode.
2168*1253Slq150181  *
2169*1253Slq150181  * arguments:
2170*1253Slq150181  *    row:	start row#
2171*1253Slq150181  *    nrows:	the number of rows to clear
2172*1253Slq150181  *    offset_y:	the offset of height in pixels to begin clear
2173*1253Slq150181  *    col:	start col#
2174*1253Slq150181  *    ncols:	the number of cols to clear
2175*1253Slq150181  *    offset_x:	the offset of width in pixels to begin clear
2176*1253Slq150181  *    scroll_up: whether this function is called during sroll up,
2177*1253Slq150181  *		 which is called only once.
2178*1253Slq150181  */
2179*1253Slq150181 void
2180*1253Slq150181 tem_pix_cls_range(tem_t *tem,
2181*1253Slq150181 	screen_pos_t row, int nrows, int offset_y,
2182*1253Slq150181 	screen_pos_t col, int ncols, int offset_x,
2183*1253Slq150181 	boolean_t sroll_up, cred_t *credp,
2184*1253Slq150181 	enum called_from called_from)
2185*1253Slq150181 {
2186*1253Slq150181 	struct tem_state *tems = tem->state;
2187*1253Slq150181 	struct vis_consdisplay da;
2188*1253Slq150181 	int	i, j;
2189*1253Slq150181 	int	row_add = 0;
2190*1253Slq150181 	text_color_t fg_color;
2191*1253Slq150181 	text_color_t bg_color;
2192*1253Slq150181 
2193*1253Slq150181 	ASSERT((called_from == CALLED_FROM_STANDALONE) ||
2194*1253Slq150181 	    MUTEX_HELD(&tem->lock));
2195*1253Slq150181 
2196*1253Slq150181 	if (sroll_up)
2197*1253Slq150181 		row_add = tems->a_c_dimension.height - 1;
2198*1253Slq150181 
2199*1253Slq150181 	da.width = tems->a_font.width;
2200*1253Slq150181 	da.height = tems->a_font.height;
2201*1253Slq150181 
2202*1253Slq150181 	tem_get_color(tem, &fg_color, &bg_color);
2203*1253Slq150181 
2204*1253Slq150181 	BIT_TO_PIX(tem, ' ', fg_color, bg_color);
2205*1253Slq150181 	da.data = (uchar_t *)tems->a_pix_data;
2206*1253Slq150181 
2207*1253Slq150181 	for (i = 0; i < nrows; i++, row++) {
2208*1253Slq150181 		da.row = (row + row_add) * da.height + offset_y;
2209*1253Slq150181 		da.col = col * da.width + offset_x;
2210*1253Slq150181 		for (j = 0; j < ncols; j++) {
2211*1253Slq150181 			tem_display(tem, &da, credp, called_from);
2212*1253Slq150181 			da.col += da.width;
2213*1253Slq150181 		}
2214*1253Slq150181 	}
2215*1253Slq150181 }
2216