xref: /onnv-gate/usr/src/uts/common/io/tem.c (revision 7688:2757e6e1bb2a)
11253Slq150181 /*
21253Slq150181  * CDDL HEADER START
31253Slq150181  *
41253Slq150181  * The contents of this file are subject to the terms of the
51253Slq150181  * Common Development and Distribution License (the "License").
61253Slq150181  * You may not use this file except in compliance with the License.
71253Slq150181  *
81253Slq150181  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91253Slq150181  * or http://www.opensolaris.org/os/licensing.
101253Slq150181  * See the License for the specific language governing permissions
111253Slq150181  * and limitations under the License.
121253Slq150181  *
131253Slq150181  * When distributing Covered Code, include this CDDL HEADER in each
141253Slq150181  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151253Slq150181  * If applicable, add the following below this CDDL HEADER, with the
161253Slq150181  * fields enclosed by brackets "[]" replaced with your own identifying
171253Slq150181  * information: Portions Copyright [yyyy] [name of copyright owner]
181253Slq150181  *
191253Slq150181  * CDDL HEADER END
201253Slq150181  */
211253Slq150181 
221253Slq150181 /*
237335SLipeng.Sang@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241253Slq150181  * Use is subject to license terms.
251253Slq150181  */
261253Slq150181 
271253Slq150181 /*
281253Slq150181  * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
291253Slq150181  * the like.
30*7688SAaron.Zang@Sun.COM  *
31*7688SAaron.Zang@Sun.COM  * How Virtual Terminal Emulator Works:
32*7688SAaron.Zang@Sun.COM  *
33*7688SAaron.Zang@Sun.COM  * Every virtual terminal is associated with a tem_vt_state structure
34*7688SAaron.Zang@Sun.COM  * and maintains a virtual screen buffer in tvs_screen_buf, which contains
35*7688SAaron.Zang@Sun.COM  * all the characters which should be shown on the physical screen when
36*7688SAaron.Zang@Sun.COM  * the terminal is activated.  There are also two other buffers, tvs_fg_buf
37*7688SAaron.Zang@Sun.COM  * and tvs_bg_buf, which track the foreground and background colors of the
38*7688SAaron.Zang@Sun.COM  * on screen characters
39*7688SAaron.Zang@Sun.COM  *
40*7688SAaron.Zang@Sun.COM  * Data written to a virtual terminal is composed of characters which
41*7688SAaron.Zang@Sun.COM  * should be displayed on the screen when this virtual terminal is
42*7688SAaron.Zang@Sun.COM  * activated, fg/bg colors of these characters, and other control
43*7688SAaron.Zang@Sun.COM  * information (escape sequence, etc).
44*7688SAaron.Zang@Sun.COM  *
45*7688SAaron.Zang@Sun.COM  * When data is passed to a virtual terminal it first is parsed for
46*7688SAaron.Zang@Sun.COM  * control information by tem_safe_parse().  Subsequently the character
47*7688SAaron.Zang@Sun.COM  * and color data are written to tvs_screen_buf, tvs_fg_buf, and
48*7688SAaron.Zang@Sun.COM  * tvs_bg_buf.  They are saved in these buffers in order to refresh
49*7688SAaron.Zang@Sun.COM  * the screen when this terminal is activated.  If the terminal is
50*7688SAaron.Zang@Sun.COM  * currently active, the data (characters and colors) are also written
51*7688SAaron.Zang@Sun.COM  * to the physical screen by invoking a callback function,
52*7688SAaron.Zang@Sun.COM  * tem_safe_text_callbacks() or tem_safe_pix_callbacks().
53*7688SAaron.Zang@Sun.COM  *
54*7688SAaron.Zang@Sun.COM  * When rendering data to the framebuffer, if the framebuffer is in
55*7688SAaron.Zang@Sun.COM  * VIS_PIXEL mode, the character data will first be converted to pixel
56*7688SAaron.Zang@Sun.COM  * data using tem_safe_pix_bit2pix(), and then the pixels get displayed
57*7688SAaron.Zang@Sun.COM  * on the physical screen.  We only store the character and color data in
58*7688SAaron.Zang@Sun.COM  * tem_vt_state since the bit2pix conversion only happens when actually
59*7688SAaron.Zang@Sun.COM  * rendering to the physical framebuffer.
601253Slq150181  */
611253Slq150181 
62*7688SAaron.Zang@Sun.COM 
631253Slq150181 #include <sys/types.h>
641253Slq150181 #include <sys/file.h>
651253Slq150181 #include <sys/conf.h>
661253Slq150181 #include <sys/errno.h>
671253Slq150181 #include <sys/open.h>
681253Slq150181 #include <sys/cred.h>
691253Slq150181 #include <sys/kmem.h>
701253Slq150181 #include <sys/ascii.h>
711253Slq150181 #include <sys/consdev.h>
721253Slq150181 #include <sys/font.h>
731253Slq150181 #include <sys/fbio.h>
741253Slq150181 #include <sys/conf.h>
751253Slq150181 #include <sys/modctl.h>
761253Slq150181 #include <sys/strsubr.h>
771253Slq150181 #include <sys/stat.h>
781253Slq150181 #include <sys/visual_io.h>
791253Slq150181 #include <sys/mutex.h>
801253Slq150181 #include <sys/param.h>
811253Slq150181 #include <sys/debug.h>
821253Slq150181 #include <sys/cmn_err.h>
831253Slq150181 #include <sys/console.h>
841253Slq150181 #include <sys/ddi.h>
851253Slq150181 #include <sys/sunddi.h>
861253Slq150181 #include <sys/sunldi.h>
871253Slq150181 #include <sys/tem_impl.h>
881253Slq150181 #ifdef _HAVE_TEM_FIRMWARE
891253Slq150181 #include <sys/promif.h>
901253Slq150181 #endif /* _HAVE_TEM_FIRMWARE */
917335SLipeng.Sang@Sun.COM #include <sys/consplat.h>
92*7688SAaron.Zang@Sun.COM #include <sys/kd.h>
93*7688SAaron.Zang@Sun.COM #include <sys/sysmacros.h>
94*7688SAaron.Zang@Sun.COM #include <sys/note.h>
95*7688SAaron.Zang@Sun.COM #include <sys/t_lock.h>
961253Slq150181 
97*7688SAaron.Zang@Sun.COM /* Terminal emulator internal helper functions */
98*7688SAaron.Zang@Sun.COM static void	tems_setup_terminal(struct vis_devinit *, size_t, size_t);
99*7688SAaron.Zang@Sun.COM static void	tems_modechange_callback(struct vis_modechg_arg *,
100*7688SAaron.Zang@Sun.COM 		struct vis_devinit *);
101*7688SAaron.Zang@Sun.COM 
102*7688SAaron.Zang@Sun.COM static void	tems_reset_colormap(cred_t *, enum called_from);
103*7688SAaron.Zang@Sun.COM 
104*7688SAaron.Zang@Sun.COM static void	tem_free_buf(struct tem_vt_state *);
105*7688SAaron.Zang@Sun.COM static void	tem_internal_init(struct tem_vt_state *, cred_t *, boolean_t,
106*7688SAaron.Zang@Sun.COM 		    boolean_t);
107*7688SAaron.Zang@Sun.COM static void	tems_get_initial_color(tem_color_t *pcolor);
1081253Slq150181 
1091253Slq150181 /*
1101253Slq150181  * Globals
1111253Slq150181  */
112*7688SAaron.Zang@Sun.COM static ldi_ident_t	term_li = NULL;
113*7688SAaron.Zang@Sun.COM tem_state_t	tems;	/* common term info */
114*7688SAaron.Zang@Sun.COM _NOTE(MUTEX_PROTECTS_DATA(tems.ts_lock, tems))
1151253Slq150181 
1161253Slq150181 extern struct mod_ops mod_miscops;
1171253Slq150181 
1181253Slq150181 static struct modlmisc	modlmisc = {
1191253Slq150181 	&mod_miscops,	/* modops */
1201253Slq150181 	"ANSI Terminal Emulator", /* name */
1211253Slq150181 };
1221253Slq150181 
1231253Slq150181 static struct modlinkage modlinkage = {
1241253Slq150181 	MODREV_1, (void *)&modlmisc, NULL
1251253Slq150181 };
1261253Slq150181 
1271253Slq150181 int
_init(void)1281253Slq150181 _init(void)
1291253Slq150181 {
1301253Slq150181 	int ret;
1311253Slq150181 	ret = mod_install(&modlinkage);
1321253Slq150181 	if (ret != 0)
1331253Slq150181 		return (ret);
1341253Slq150181 	ret = ldi_ident_from_mod(&modlinkage, &term_li);
1351253Slq150181 	if (ret != 0) {
1361253Slq150181 		(void) mod_remove(&modlinkage);
1371253Slq150181 		return (ret);
1381253Slq150181 	}
139*7688SAaron.Zang@Sun.COM 
140*7688SAaron.Zang@Sun.COM 	mutex_init(&tems.ts_lock, (char *)NULL, MUTEX_DRIVER, NULL);
141*7688SAaron.Zang@Sun.COM 	list_create(&tems.ts_list, sizeof (struct tem_vt_state),
142*7688SAaron.Zang@Sun.COM 	    offsetof(struct tem_vt_state, tvs_list_node));
143*7688SAaron.Zang@Sun.COM 	tems.ts_active = NULL;
144*7688SAaron.Zang@Sun.COM 
1451253Slq150181 	return (0);
1461253Slq150181 }
1471253Slq150181 
1481253Slq150181 int
_fini()1491253Slq150181 _fini()
1501253Slq150181 {
1511253Slq150181 	int ret;
1521253Slq150181 
1531253Slq150181 	ret = mod_remove(&modlinkage);
1541253Slq150181 	if (ret == 0) {
1551253Slq150181 		ldi_ident_release(term_li);
1561253Slq150181 		term_li = NULL;
1571253Slq150181 	}
1581253Slq150181 	return (ret);
1591253Slq150181 }
1601253Slq150181 
1611253Slq150181 int
_info(struct modinfo * modinfop)1621253Slq150181 _info(struct modinfo *modinfop)
1631253Slq150181 {
1641253Slq150181 	return (mod_info(&modlinkage, modinfop));
1651253Slq150181 }
1661253Slq150181 
167*7688SAaron.Zang@Sun.COM static void
tem_add(struct tem_vt_state * tem)168*7688SAaron.Zang@Sun.COM tem_add(struct tem_vt_state *tem)
1691253Slq150181 {
170*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
1711253Slq150181 
172*7688SAaron.Zang@Sun.COM 	list_insert_head(&tems.ts_list, tem);
1731253Slq150181 }
1741253Slq150181 
1751253Slq150181 static void
tem_rm(struct tem_vt_state * tem)176*7688SAaron.Zang@Sun.COM tem_rm(struct tem_vt_state *tem)
1771253Slq150181 {
178*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
1791253Slq150181 
180*7688SAaron.Zang@Sun.COM 	list_remove(&tems.ts_list, tem);
1811253Slq150181 }
1821253Slq150181 
1831253Slq150181 /*
1841253Slq150181  * This is the main entry point to the module.  It handles output requests
1851253Slq150181  * during normal system operation, when (e.g.) mutexes are available.
1861253Slq150181  */
1871253Slq150181 void
tem_write(tem_vt_state_t tem_arg,uchar_t * buf,ssize_t len,cred_t * credp)188*7688SAaron.Zang@Sun.COM tem_write(tem_vt_state_t tem_arg, uchar_t *buf, ssize_t len, cred_t *credp)
1891253Slq150181 {
190*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
191*7688SAaron.Zang@Sun.COM 
192*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
193*7688SAaron.Zang@Sun.COM 	mutex_enter(&tem->tvs_lock);
194*7688SAaron.Zang@Sun.COM 
195*7688SAaron.Zang@Sun.COM 	if (!tem->tvs_initialized) {
196*7688SAaron.Zang@Sun.COM 		mutex_exit(&tem->tvs_lock);
197*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
198*7688SAaron.Zang@Sun.COM 		return;
199*7688SAaron.Zang@Sun.COM 	}
200*7688SAaron.Zang@Sun.COM 
201*7688SAaron.Zang@Sun.COM 	tem_safe_check_first_time(tem, credp, CALLED_FROM_NORMAL);
202*7688SAaron.Zang@Sun.COM 	tem_safe_terminal_emulate(tem, buf, len, credp, CALLED_FROM_NORMAL);
203*7688SAaron.Zang@Sun.COM 
204*7688SAaron.Zang@Sun.COM 	mutex_exit(&tem->tvs_lock);
205*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
206*7688SAaron.Zang@Sun.COM }
207*7688SAaron.Zang@Sun.COM 
208*7688SAaron.Zang@Sun.COM static void
tem_internal_init(struct tem_vt_state * ptem,cred_t * credp,boolean_t init_color,boolean_t clear_screen)209*7688SAaron.Zang@Sun.COM tem_internal_init(struct tem_vt_state *ptem, cred_t *credp,
210*7688SAaron.Zang@Sun.COM     boolean_t init_color, boolean_t clear_screen)
211*7688SAaron.Zang@Sun.COM {
212*7688SAaron.Zang@Sun.COM 	int i, j;
213*7688SAaron.Zang@Sun.COM 	int width, height;
214*7688SAaron.Zang@Sun.COM 	int total;
215*7688SAaron.Zang@Sun.COM 	text_color_t fg;
216*7688SAaron.Zang@Sun.COM 	text_color_t bg;
217*7688SAaron.Zang@Sun.COM 	size_t	tc_size = sizeof (text_color_t);
218*7688SAaron.Zang@Sun.COM 
219*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&ptem->tvs_lock));
2201253Slq150181 
221*7688SAaron.Zang@Sun.COM 	if (tems.ts_display_mode == VIS_PIXEL) {
222*7688SAaron.Zang@Sun.COM 		ptem->tvs_pix_data_size = tems.ts_pix_data_size;
223*7688SAaron.Zang@Sun.COM 		ptem->tvs_pix_data =
224*7688SAaron.Zang@Sun.COM 		    kmem_alloc(ptem->tvs_pix_data_size, KM_SLEEP);
225*7688SAaron.Zang@Sun.COM 	}
226*7688SAaron.Zang@Sun.COM 
227*7688SAaron.Zang@Sun.COM 	ptem->tvs_outbuf_size = tems.ts_c_dimension.width;
228*7688SAaron.Zang@Sun.COM 	ptem->tvs_outbuf =
229*7688SAaron.Zang@Sun.COM 	    (unsigned char *)kmem_alloc(ptem->tvs_outbuf_size, KM_SLEEP);
230*7688SAaron.Zang@Sun.COM 
231*7688SAaron.Zang@Sun.COM 	width = tems.ts_c_dimension.width;
232*7688SAaron.Zang@Sun.COM 	height = tems.ts_c_dimension.height;
233*7688SAaron.Zang@Sun.COM 	ptem->tvs_screen_buf_size = width * height;
234*7688SAaron.Zang@Sun.COM 	ptem->tvs_screen_buf =
235*7688SAaron.Zang@Sun.COM 	    (unsigned char *)kmem_alloc(width * height, KM_SLEEP);
2361253Slq150181 
237*7688SAaron.Zang@Sun.COM 	total = width * height * tc_size;
238*7688SAaron.Zang@Sun.COM 	ptem->tvs_fg_buf = (text_color_t *)kmem_alloc(total, KM_SLEEP);
239*7688SAaron.Zang@Sun.COM 	ptem->tvs_bg_buf = (text_color_t *)kmem_alloc(total, KM_SLEEP);
240*7688SAaron.Zang@Sun.COM 	ptem->tvs_color_buf_size = total;
241*7688SAaron.Zang@Sun.COM 
242*7688SAaron.Zang@Sun.COM 	tem_safe_reset_display(ptem, credp, CALLED_FROM_NORMAL,
243*7688SAaron.Zang@Sun.COM 	    clear_screen, init_color);
2441253Slq150181 
245*7688SAaron.Zang@Sun.COM 	tem_safe_get_color(ptem, &fg, &bg, TEM_ATTR_SCREEN_REVERSE);
246*7688SAaron.Zang@Sun.COM 	for (i = 0; i < height; i++)
247*7688SAaron.Zang@Sun.COM 		for (j = 0; j < width; j++) {
248*7688SAaron.Zang@Sun.COM 			ptem->tvs_screen_buf[i * width + j] = ' ';
249*7688SAaron.Zang@Sun.COM 			ptem->tvs_fg_buf[(i * width +j) * tc_size] = fg;
250*7688SAaron.Zang@Sun.COM 			ptem->tvs_bg_buf[(i * width +j) * tc_size] = bg;
251*7688SAaron.Zang@Sun.COM 
252*7688SAaron.Zang@Sun.COM 		}
253*7688SAaron.Zang@Sun.COM 
254*7688SAaron.Zang@Sun.COM 	ptem->tvs_initialized  = 1;
2551253Slq150181 }
2561253Slq150181 
2571253Slq150181 int
tem_initialized(tem_vt_state_t tem_arg)258*7688SAaron.Zang@Sun.COM tem_initialized(tem_vt_state_t tem_arg)
259*7688SAaron.Zang@Sun.COM {
260*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *ptem = (struct tem_vt_state *)tem_arg;
261*7688SAaron.Zang@Sun.COM 	int ret;
262*7688SAaron.Zang@Sun.COM 
263*7688SAaron.Zang@Sun.COM 	mutex_enter(&ptem->tvs_lock);
264*7688SAaron.Zang@Sun.COM 	ret = ptem->tvs_initialized;
265*7688SAaron.Zang@Sun.COM 	mutex_exit(&ptem->tvs_lock);
266*7688SAaron.Zang@Sun.COM 
267*7688SAaron.Zang@Sun.COM 	return (ret);
268*7688SAaron.Zang@Sun.COM }
269*7688SAaron.Zang@Sun.COM 
270*7688SAaron.Zang@Sun.COM tem_vt_state_t
tem_init(cred_t * credp)271*7688SAaron.Zang@Sun.COM tem_init(cred_t *credp)
272*7688SAaron.Zang@Sun.COM {
273*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *ptem;
274*7688SAaron.Zang@Sun.COM 
275*7688SAaron.Zang@Sun.COM 	ptem = kmem_zalloc(sizeof (struct tem_vt_state), KM_SLEEP);
276*7688SAaron.Zang@Sun.COM 	mutex_init(&ptem->tvs_lock, (char *)NULL, MUTEX_DRIVER, NULL);
277*7688SAaron.Zang@Sun.COM 
278*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
279*7688SAaron.Zang@Sun.COM 	mutex_enter(&ptem->tvs_lock);
280*7688SAaron.Zang@Sun.COM 
281*7688SAaron.Zang@Sun.COM 	ptem->tvs_isactive = B_FALSE;
282*7688SAaron.Zang@Sun.COM 	ptem->tvs_fbmode = KD_TEXT;
283*7688SAaron.Zang@Sun.COM 
284*7688SAaron.Zang@Sun.COM 	/*
285*7688SAaron.Zang@Sun.COM 	 * A tem is regarded as initialized only after tem_internal_init(),
286*7688SAaron.Zang@Sun.COM 	 * will be set at the end of tem_internal_init().
287*7688SAaron.Zang@Sun.COM 	 */
288*7688SAaron.Zang@Sun.COM 	ptem->tvs_initialized = 0;
289*7688SAaron.Zang@Sun.COM 
290*7688SAaron.Zang@Sun.COM 
291*7688SAaron.Zang@Sun.COM 	if (!tems.ts_initialized) {
292*7688SAaron.Zang@Sun.COM 		/*
293*7688SAaron.Zang@Sun.COM 		 * Only happens during early console configuration.
294*7688SAaron.Zang@Sun.COM 		 */
295*7688SAaron.Zang@Sun.COM 		tem_add(ptem);
296*7688SAaron.Zang@Sun.COM 		mutex_exit(&ptem->tvs_lock);
297*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
298*7688SAaron.Zang@Sun.COM 		return ((tem_vt_state_t)ptem);
299*7688SAaron.Zang@Sun.COM 	}
300*7688SAaron.Zang@Sun.COM 
301*7688SAaron.Zang@Sun.COM 	tem_internal_init(ptem, credp, B_TRUE, B_FALSE);
302*7688SAaron.Zang@Sun.COM 	tem_add(ptem);
303*7688SAaron.Zang@Sun.COM 	mutex_exit(&ptem->tvs_lock);
304*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
305*7688SAaron.Zang@Sun.COM 
306*7688SAaron.Zang@Sun.COM 	return ((tem_vt_state_t)ptem);
307*7688SAaron.Zang@Sun.COM }
308*7688SAaron.Zang@Sun.COM 
309*7688SAaron.Zang@Sun.COM /*
310*7688SAaron.Zang@Sun.COM  * re-init the tem after video mode has changed and tems_info has
311*7688SAaron.Zang@Sun.COM  * been re-inited. The lock is already held.
312*7688SAaron.Zang@Sun.COM  */
313*7688SAaron.Zang@Sun.COM static void
tem_reinit(struct tem_vt_state * tem,boolean_t reset_display)314*7688SAaron.Zang@Sun.COM tem_reinit(struct tem_vt_state *tem, boolean_t reset_display)
3151253Slq150181 {
316*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock));
317*7688SAaron.Zang@Sun.COM 
318*7688SAaron.Zang@Sun.COM 	tem_free_buf(tem); /* only free virtual buffers */
319*7688SAaron.Zang@Sun.COM 
320*7688SAaron.Zang@Sun.COM 	/* reserve color */
321*7688SAaron.Zang@Sun.COM 	tem_internal_init(tem, kcred, B_FALSE, reset_display);
322*7688SAaron.Zang@Sun.COM }
323*7688SAaron.Zang@Sun.COM 
324*7688SAaron.Zang@Sun.COM static void
tem_free_buf(struct tem_vt_state * tem)325*7688SAaron.Zang@Sun.COM tem_free_buf(struct tem_vt_state *tem)
326*7688SAaron.Zang@Sun.COM {
327*7688SAaron.Zang@Sun.COM 	ASSERT(tem != NULL && MUTEX_HELD(&tem->tvs_lock));
328*7688SAaron.Zang@Sun.COM 
329*7688SAaron.Zang@Sun.COM 	if (tem->tvs_outbuf != NULL)
330*7688SAaron.Zang@Sun.COM 		kmem_free(tem->tvs_outbuf, tem->tvs_outbuf_size);
331*7688SAaron.Zang@Sun.COM 	if (tem->tvs_pix_data != NULL)
332*7688SAaron.Zang@Sun.COM 		kmem_free(tem->tvs_pix_data, tem->tvs_pix_data_size);
333*7688SAaron.Zang@Sun.COM 	if (tem->tvs_screen_buf != NULL)
334*7688SAaron.Zang@Sun.COM 		kmem_free(tem->tvs_screen_buf, tem->tvs_screen_buf_size);
335*7688SAaron.Zang@Sun.COM 	if (tem->tvs_fg_buf != NULL)
336*7688SAaron.Zang@Sun.COM 		kmem_free(tem->tvs_fg_buf, tem->tvs_color_buf_size);
337*7688SAaron.Zang@Sun.COM 	if (tem->tvs_bg_buf != NULL)
338*7688SAaron.Zang@Sun.COM 		kmem_free(tem->tvs_bg_buf, tem->tvs_color_buf_size);
339*7688SAaron.Zang@Sun.COM }
340*7688SAaron.Zang@Sun.COM 
341*7688SAaron.Zang@Sun.COM void
tem_destroy(tem_vt_state_t tem_arg,cred_t * credp)342*7688SAaron.Zang@Sun.COM tem_destroy(tem_vt_state_t tem_arg, cred_t *credp)
343*7688SAaron.Zang@Sun.COM {
344*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
345*7688SAaron.Zang@Sun.COM 
346*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
347*7688SAaron.Zang@Sun.COM 	mutex_enter(&tem->tvs_lock);
348*7688SAaron.Zang@Sun.COM 
349*7688SAaron.Zang@Sun.COM 	if (tem->tvs_isactive && tem->tvs_fbmode == KD_TEXT)
350*7688SAaron.Zang@Sun.COM 		tem_safe_blank_screen(tem, credp, CALLED_FROM_NORMAL);
351*7688SAaron.Zang@Sun.COM 
352*7688SAaron.Zang@Sun.COM 	tem_free_buf(tem);
353*7688SAaron.Zang@Sun.COM 	tem_rm(tem);
354*7688SAaron.Zang@Sun.COM 
355*7688SAaron.Zang@Sun.COM 	if (tems.ts_active == tem)
356*7688SAaron.Zang@Sun.COM 		tems.ts_active = NULL;
357*7688SAaron.Zang@Sun.COM 
358*7688SAaron.Zang@Sun.COM 	mutex_exit(&tem->tvs_lock);
359*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
360*7688SAaron.Zang@Sun.COM 
361*7688SAaron.Zang@Sun.COM 	kmem_free(tem, sizeof (struct tem_vt_state));
362*7688SAaron.Zang@Sun.COM }
363*7688SAaron.Zang@Sun.COM 
364*7688SAaron.Zang@Sun.COM static int
tems_failed(cred_t * credp,boolean_t finish_ioctl)365*7688SAaron.Zang@Sun.COM tems_failed(cred_t *credp, boolean_t finish_ioctl)
366*7688SAaron.Zang@Sun.COM {
367*7688SAaron.Zang@Sun.COM 	int	lyr_rval;
368*7688SAaron.Zang@Sun.COM 
369*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock));
370*7688SAaron.Zang@Sun.COM 
371*7688SAaron.Zang@Sun.COM 	if (finish_ioctl)
372*7688SAaron.Zang@Sun.COM 		(void) ldi_ioctl(tems.ts_hdl, VIS_DEVFINI, 0,
373*7688SAaron.Zang@Sun.COM 		    FWRITE|FKIOCTL, credp, &lyr_rval);
374*7688SAaron.Zang@Sun.COM 
375*7688SAaron.Zang@Sun.COM 	(void) ldi_close(tems.ts_hdl, NULL, credp);
376*7688SAaron.Zang@Sun.COM 	tems.ts_hdl = NULL;
377*7688SAaron.Zang@Sun.COM 	return (ENXIO);
378*7688SAaron.Zang@Sun.COM }
379*7688SAaron.Zang@Sun.COM 
380*7688SAaron.Zang@Sun.COM /*
381*7688SAaron.Zang@Sun.COM  * only called once during boot
382*7688SAaron.Zang@Sun.COM  */
383*7688SAaron.Zang@Sun.COM int
tem_info_init(char * pathname,cred_t * credp)384*7688SAaron.Zang@Sun.COM tem_info_init(char *pathname, cred_t *credp)
385*7688SAaron.Zang@Sun.COM {
386*7688SAaron.Zang@Sun.COM 	int			lyr_rval, ret;
387*7688SAaron.Zang@Sun.COM 	struct vis_devinit	temargs;
388*7688SAaron.Zang@Sun.COM 	char			*pathbuf;
3891253Slq150181 	size_t height = 0;
3901253Slq150181 	size_t width = 0;
391*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *p;
392*7688SAaron.Zang@Sun.COM 
393*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
3941253Slq150181 
395*7688SAaron.Zang@Sun.COM 	if (tems.ts_initialized) {
396*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
397*7688SAaron.Zang@Sun.COM 		return (0);
398*7688SAaron.Zang@Sun.COM 	}
3991253Slq150181 
4001253Slq150181 	/*
4011253Slq150181 	 * Open the layered device using the devfs physical device name
4021253Slq150181 	 * after adding the /devices prefix.
4031253Slq150181 	 */
4041253Slq150181 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
4051253Slq150181 	(void) strcpy(pathbuf, "/devices");
4061253Slq150181 	if (i_ddi_prompath_to_devfspath(pathname,
4071253Slq150181 	    pathbuf + strlen("/devices")) != DDI_SUCCESS) {
408*7688SAaron.Zang@Sun.COM 		cmn_err(CE_WARN, "terminal-emulator:  path conversion error");
4091253Slq150181 		kmem_free(pathbuf, MAXPATHLEN);
410*7688SAaron.Zang@Sun.COM 
411*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
4121253Slq150181 		return (ENXIO);
4131253Slq150181 	}
414*7688SAaron.Zang@Sun.COM 	if (ldi_open_by_name(pathbuf, FWRITE, credp,
415*7688SAaron.Zang@Sun.COM 	    &tems.ts_hdl, term_li) != 0) {
416*7688SAaron.Zang@Sun.COM 		cmn_err(CE_WARN, "terminal-emulator:  device path open error");
4171253Slq150181 		kmem_free(pathbuf, MAXPATHLEN);
418*7688SAaron.Zang@Sun.COM 
419*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
4201253Slq150181 		return (ENXIO);
4211253Slq150181 	}
4221253Slq150181 	kmem_free(pathbuf, MAXPATHLEN);
4231253Slq150181 
424*7688SAaron.Zang@Sun.COM 	temargs.modechg_cb  = (vis_modechg_cb_t)tems_modechange_callback;
425*7688SAaron.Zang@Sun.COM 	temargs.modechg_arg = NULL;
4261253Slq150181 
4271253Slq150181 	/*
4281253Slq150181 	 * Initialize the console and get the device parameters
4291253Slq150181 	 */
430*7688SAaron.Zang@Sun.COM 	if (ldi_ioctl(tems.ts_hdl, VIS_DEVINIT,
431*7688SAaron.Zang@Sun.COM 	    (intptr_t)&temargs, FWRITE|FKIOCTL, credp, &lyr_rval) != 0) {
4321253Slq150181 		cmn_err(CE_WARN, "terminal emulator: Compatible fb not found");
433*7688SAaron.Zang@Sun.COM 		ret = tems_failed(credp, B_FALSE);
434*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
435*7688SAaron.Zang@Sun.COM 		return (ret);
4361253Slq150181 	}
4371253Slq150181 
4381253Slq150181 	/* Make sure the fb driver and terminal emulator versions match */
439*7688SAaron.Zang@Sun.COM 	if (temargs.version != VIS_CONS_REV) {
4401253Slq150181 		cmn_err(CE_WARN,
4411253Slq150181 		    "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
442*7688SAaron.Zang@Sun.COM 		    "of console fb driver not supported", temargs.version);
443*7688SAaron.Zang@Sun.COM 		ret = tems_failed(credp, B_TRUE);
444*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
445*7688SAaron.Zang@Sun.COM 		return (ret);
4461253Slq150181 	}
4471253Slq150181 
448*7688SAaron.Zang@Sun.COM 	if ((tems.ts_fb_polledio = temargs.polledio) == NULL) {
4491253Slq150181 		cmn_err(CE_WARN, "terminal emulator: fb doesn't support polled "
4501253Slq150181 		    "I/O");
451*7688SAaron.Zang@Sun.COM 		ret = tems_failed(credp, B_TRUE);
452*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
453*7688SAaron.Zang@Sun.COM 		return (ret);
4541253Slq150181 	}
4551253Slq150181 
4561253Slq150181 	/* other sanity checks */
457*7688SAaron.Zang@Sun.COM 	if (!((temargs.depth == 4) || (temargs.depth == 8) ||
458*7688SAaron.Zang@Sun.COM 	    (temargs.depth == 24) || (temargs.depth == 32))) {
4591253Slq150181 		cmn_err(CE_WARN, "terminal emulator: unsupported depth");
460*7688SAaron.Zang@Sun.COM 		ret = tems_failed(credp, B_TRUE);
461*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
462*7688SAaron.Zang@Sun.COM 		return (ret);
4631253Slq150181 	}
4641253Slq150181 
465*7688SAaron.Zang@Sun.COM 	if ((temargs.mode != VIS_TEXT) && (temargs.mode != VIS_PIXEL)) {
466*7688SAaron.Zang@Sun.COM 		cmn_err(CE_WARN, "terminal emulator: unsupported mode");
467*7688SAaron.Zang@Sun.COM 		ret = tems_failed(credp, B_TRUE);
468*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
469*7688SAaron.Zang@Sun.COM 		return (ret);
4701253Slq150181 	}
4711253Slq150181 
472*7688SAaron.Zang@Sun.COM 	if ((temargs.mode == VIS_PIXEL) && plat_stdout_is_framebuffer())
473*7688SAaron.Zang@Sun.COM 		plat_tem_get_prom_size(&height, &width);
4743994Slq150181 
4753994Slq150181 	/*
476*7688SAaron.Zang@Sun.COM 	 * Initialize the common terminal emulator info
4771253Slq150181 	 */
478*7688SAaron.Zang@Sun.COM 	tems_setup_terminal(&temargs, height, width);
479*7688SAaron.Zang@Sun.COM 
480*7688SAaron.Zang@Sun.COM 	tems_reset_colormap(credp, CALLED_FROM_NORMAL);
481*7688SAaron.Zang@Sun.COM 	tems_get_initial_color(&tems.ts_init_color);
482*7688SAaron.Zang@Sun.COM 
483*7688SAaron.Zang@Sun.COM 	tems.ts_initialized = 1; /* initialization flag */
484*7688SAaron.Zang@Sun.COM 
485*7688SAaron.Zang@Sun.COM 	for (p = list_head(&tems.ts_list); p != NULL;
486*7688SAaron.Zang@Sun.COM 	    p = list_next(&tems.ts_list, p)) {
487*7688SAaron.Zang@Sun.COM 		mutex_enter(&p->tvs_lock);
488*7688SAaron.Zang@Sun.COM 		tem_internal_init(p, credp, B_TRUE, B_FALSE);
489*7688SAaron.Zang@Sun.COM 		if (temargs.mode == VIS_PIXEL)
490*7688SAaron.Zang@Sun.COM 			tem_pix_align(p, credp, CALLED_FROM_NORMAL);
491*7688SAaron.Zang@Sun.COM 		mutex_exit(&p->tvs_lock);
492*7688SAaron.Zang@Sun.COM 	}
493*7688SAaron.Zang@Sun.COM 
494*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
495*7688SAaron.Zang@Sun.COM 	return (0);
496*7688SAaron.Zang@Sun.COM }
497*7688SAaron.Zang@Sun.COM 
498*7688SAaron.Zang@Sun.COM #define	TEMS_DEPTH_DIFF		0x01
499*7688SAaron.Zang@Sun.COM #define	TEMS_DIMENSION_DIFF	0x02
500*7688SAaron.Zang@Sun.COM 
501*7688SAaron.Zang@Sun.COM static uchar_t
tems_check_videomode(struct vis_devinit * tp)502*7688SAaron.Zang@Sun.COM tems_check_videomode(struct vis_devinit *tp)
503*7688SAaron.Zang@Sun.COM {
504*7688SAaron.Zang@Sun.COM 	uchar_t result = 0;
505*7688SAaron.Zang@Sun.COM 
506*7688SAaron.Zang@Sun.COM 	if (tems.ts_pdepth != tp->depth)
507*7688SAaron.Zang@Sun.COM 		result |= TEMS_DEPTH_DIFF;
508*7688SAaron.Zang@Sun.COM 
509*7688SAaron.Zang@Sun.COM 	if (tp->mode == VIS_TEXT) {
510*7688SAaron.Zang@Sun.COM 		if (tems.ts_c_dimension.width != tp->width ||
511*7688SAaron.Zang@Sun.COM 		    tems.ts_c_dimension.height != tp->height)
512*7688SAaron.Zang@Sun.COM 			result |= TEMS_DIMENSION_DIFF;
513*7688SAaron.Zang@Sun.COM 	} else {
514*7688SAaron.Zang@Sun.COM 		if (tems.ts_p_dimension.width != tp->width ||
515*7688SAaron.Zang@Sun.COM 		    tems.ts_p_dimension.height != tp->height)
516*7688SAaron.Zang@Sun.COM 			result |= TEMS_DIMENSION_DIFF;
517*7688SAaron.Zang@Sun.COM 	}
518*7688SAaron.Zang@Sun.COM 
519*7688SAaron.Zang@Sun.COM 	return (result);
520*7688SAaron.Zang@Sun.COM }
521*7688SAaron.Zang@Sun.COM 
522*7688SAaron.Zang@Sun.COM static void
tems_setup_terminal(struct vis_devinit * tp,size_t height,size_t width)523*7688SAaron.Zang@Sun.COM tems_setup_terminal(struct vis_devinit *tp, size_t height, size_t width)
524*7688SAaron.Zang@Sun.COM {
525*7688SAaron.Zang@Sun.COM 	int i;
526*7688SAaron.Zang@Sun.COM 	int old_blank_buf_size = tems.ts_c_dimension.width;
527*7688SAaron.Zang@Sun.COM 
528*7688SAaron.Zang@Sun.COM 	ASSERT(MUTEX_HELD(&tems.ts_lock));
529*7688SAaron.Zang@Sun.COM 
530*7688SAaron.Zang@Sun.COM 	tems.ts_pdepth = tp->depth;
531*7688SAaron.Zang@Sun.COM 	tems.ts_linebytes = tp->linebytes;
532*7688SAaron.Zang@Sun.COM 	tems.ts_display_mode = tp->mode;
533*7688SAaron.Zang@Sun.COM 
534*7688SAaron.Zang@Sun.COM 	switch (tp->mode) {
535*7688SAaron.Zang@Sun.COM 	case VIS_TEXT:
536*7688SAaron.Zang@Sun.COM 		tems.ts_p_dimension.width = 0;
537*7688SAaron.Zang@Sun.COM 		tems.ts_p_dimension.height = 0;
538*7688SAaron.Zang@Sun.COM 		tems.ts_c_dimension.width = tp->width;
539*7688SAaron.Zang@Sun.COM 		tems.ts_c_dimension.height = tp->height;
540*7688SAaron.Zang@Sun.COM 		tems.ts_callbacks = &tem_safe_text_callbacks;
541*7688SAaron.Zang@Sun.COM 
542*7688SAaron.Zang@Sun.COM 		break;
543*7688SAaron.Zang@Sun.COM 
544*7688SAaron.Zang@Sun.COM 	case VIS_PIXEL:
5451253Slq150181 		/*
546*7688SAaron.Zang@Sun.COM 		 * First check to see if the user has specified a screen size.
547*7688SAaron.Zang@Sun.COM 		 * If so, use those values.  Else use 34x80 as the default.
5481253Slq150181 		 */
549*7688SAaron.Zang@Sun.COM 		if (width == 0) {
550*7688SAaron.Zang@Sun.COM 			width = TEM_DEFAULT_COLS;
551*7688SAaron.Zang@Sun.COM 			height = TEM_DEFAULT_ROWS;
552*7688SAaron.Zang@Sun.COM 		}
553*7688SAaron.Zang@Sun.COM 		tems.ts_c_dimension.height = (screen_size_t)height;
554*7688SAaron.Zang@Sun.COM 		tems.ts_c_dimension.width = (screen_size_t)width;
5551253Slq150181 
556*7688SAaron.Zang@Sun.COM 		tems.ts_p_dimension.height = tp->height;
557*7688SAaron.Zang@Sun.COM 		tems.ts_p_dimension.width = tp->width;
558*7688SAaron.Zang@Sun.COM 
559*7688SAaron.Zang@Sun.COM 		tems.ts_callbacks = &tem_safe_pix_callbacks;
5601253Slq150181 
5611253Slq150181 		/*
562*7688SAaron.Zang@Sun.COM 		 * set_font() will select a appropriate sized font for
563*7688SAaron.Zang@Sun.COM 		 * the number of rows and columns selected.  If we don't
564*7688SAaron.Zang@Sun.COM 		 * have a font that will fit, then it will use the
565*7688SAaron.Zang@Sun.COM 		 * default builtin font and adjust the rows and columns
566*7688SAaron.Zang@Sun.COM 		 * to fit on the screen.
5671253Slq150181 		 */
568*7688SAaron.Zang@Sun.COM 		set_font(&tems.ts_font,
569*7688SAaron.Zang@Sun.COM 		    &tems.ts_c_dimension.height,
570*7688SAaron.Zang@Sun.COM 		    &tems.ts_c_dimension.width,
571*7688SAaron.Zang@Sun.COM 		    tems.ts_p_dimension.height,
572*7688SAaron.Zang@Sun.COM 		    tems.ts_p_dimension.width);
5731253Slq150181 
574*7688SAaron.Zang@Sun.COM 		tems.ts_p_offset.y = (tems.ts_p_dimension.height -
575*7688SAaron.Zang@Sun.COM 		    (tems.ts_c_dimension.height * tems.ts_font.height)) / 2;
576*7688SAaron.Zang@Sun.COM 		tems.ts_p_offset.x = (tems.ts_p_dimension.width -
577*7688SAaron.Zang@Sun.COM 		    (tems.ts_c_dimension.width * tems.ts_font.width)) / 2;
5781253Slq150181 
579*7688SAaron.Zang@Sun.COM 		tems.ts_pix_data_size =
580*7688SAaron.Zang@Sun.COM 		    tems.ts_font.width * tems.ts_font.height;
581*7688SAaron.Zang@Sun.COM 
582*7688SAaron.Zang@Sun.COM 		tems.ts_pix_data_size *= 4;
583*7688SAaron.Zang@Sun.COM 
584*7688SAaron.Zang@Sun.COM 		tems.ts_pdepth = tp->depth;
585*7688SAaron.Zang@Sun.COM 
586*7688SAaron.Zang@Sun.COM 		break;
5871253Slq150181 	}
5881253Slq150181 
589*7688SAaron.Zang@Sun.COM 	/* Now virtual cls also uses the blank_line buffer */
590*7688SAaron.Zang@Sun.COM 	if (tems.ts_blank_line)
591*7688SAaron.Zang@Sun.COM 		kmem_free(tems.ts_blank_line, old_blank_buf_size);
5921253Slq150181 
593*7688SAaron.Zang@Sun.COM 	tems.ts_blank_line = (unsigned char *)
594*7688SAaron.Zang@Sun.COM 	    kmem_alloc(tems.ts_c_dimension.width, KM_SLEEP);
595*7688SAaron.Zang@Sun.COM 	for (i = 0; i < tems.ts_c_dimension.width; i++)
596*7688SAaron.Zang@Sun.COM 		tems.ts_blank_line[i] = ' ';
5971253Slq150181 }
5981253Slq150181 
5991253Slq150181 /*
6001253Slq150181  * This is a callback function that we register with the frame
6011253Slq150181  * buffer driver layered underneath.  It gets invoked from
6021253Slq150181  * the underlying frame buffer driver to reconfigure the terminal
6031253Slq150181  * emulator to a new screen size and depth in conjunction with
6041253Slq150181  * framebuffer videomode changes.
6053994Slq150181  * Here we keep the foreground/background color and attributes,
6063994Slq150181  * which may be different with the initial settings, so that
6073994Slq150181  * the color won't change while the framebuffer videomode changes.
6083994Slq150181  * And we also reset the kernel terminal emulator and clear the
6093994Slq150181  * whole screen.
6101253Slq150181  */
611*7688SAaron.Zang@Sun.COM /* ARGSUSED */
6121253Slq150181 void
tems_modechange_callback(struct vis_modechg_arg * arg,struct vis_devinit * devinit)613*7688SAaron.Zang@Sun.COM tems_modechange_callback(struct vis_modechg_arg *arg,
614*7688SAaron.Zang@Sun.COM     struct vis_devinit *devinit)
6151253Slq150181 {
616*7688SAaron.Zang@Sun.COM 	uchar_t diff;
617*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *p;
618*7688SAaron.Zang@Sun.COM 	tem_modechg_cb_t cb;
619*7688SAaron.Zang@Sun.COM 	tem_modechg_cb_arg_t cb_arg;
6201253Slq150181 
621*7688SAaron.Zang@Sun.COM 	ASSERT(!(list_is_empty(&tems.ts_list)));
6221253Slq150181 
623*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
6241253Slq150181 
625*7688SAaron.Zang@Sun.COM 	/*
626*7688SAaron.Zang@Sun.COM 	 * currently only for pixel mode
627*7688SAaron.Zang@Sun.COM 	 */
628*7688SAaron.Zang@Sun.COM 	diff = tems_check_videomode(devinit);
629*7688SAaron.Zang@Sun.COM 	if (diff == 0) {
630*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
631*7688SAaron.Zang@Sun.COM 		return;
6321253Slq150181 	}
6331253Slq150181 
634*7688SAaron.Zang@Sun.COM 	diff = diff & TEMS_DIMENSION_DIFF;
635*7688SAaron.Zang@Sun.COM 
636*7688SAaron.Zang@Sun.COM 	if (diff == 0) {
637*7688SAaron.Zang@Sun.COM 		/*
638*7688SAaron.Zang@Sun.COM 		 * Only need to reinit the active tem.
639*7688SAaron.Zang@Sun.COM 		 */
640*7688SAaron.Zang@Sun.COM 		struct tem_vt_state *active = tems.ts_active;
641*7688SAaron.Zang@Sun.COM 		tems.ts_pdepth = devinit->depth;
642*7688SAaron.Zang@Sun.COM 
643*7688SAaron.Zang@Sun.COM 		mutex_enter(&active->tvs_lock);
644*7688SAaron.Zang@Sun.COM 		ASSERT(active->tvs_isactive);
645*7688SAaron.Zang@Sun.COM 		tem_reinit(active, B_TRUE);
646*7688SAaron.Zang@Sun.COM 		mutex_exit(&active->tvs_lock);
647*7688SAaron.Zang@Sun.COM 
648*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
649*7688SAaron.Zang@Sun.COM 		return;
650*7688SAaron.Zang@Sun.COM 	}
651*7688SAaron.Zang@Sun.COM 
652*7688SAaron.Zang@Sun.COM 	tems_setup_terminal(devinit, tems.ts_c_dimension.height,
653*7688SAaron.Zang@Sun.COM 	    tems.ts_c_dimension.width);
654*7688SAaron.Zang@Sun.COM 
655*7688SAaron.Zang@Sun.COM 	for (p = list_head(&tems.ts_list); p != NULL;
656*7688SAaron.Zang@Sun.COM 	    p = list_next(&tems.ts_list, p)) {
657*7688SAaron.Zang@Sun.COM 		mutex_enter(&p->tvs_lock);
658*7688SAaron.Zang@Sun.COM 		tem_reinit(p, p->tvs_isactive);
659*7688SAaron.Zang@Sun.COM 		mutex_exit(&p->tvs_lock);
660*7688SAaron.Zang@Sun.COM 	}
661*7688SAaron.Zang@Sun.COM 
662*7688SAaron.Zang@Sun.COM 
663*7688SAaron.Zang@Sun.COM 	if (tems.ts_modechg_cb == NULL) {
664*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
665*7688SAaron.Zang@Sun.COM 		return;
666*7688SAaron.Zang@Sun.COM 	}
667*7688SAaron.Zang@Sun.COM 
668*7688SAaron.Zang@Sun.COM 	cb = tems.ts_modechg_cb;
669*7688SAaron.Zang@Sun.COM 	cb_arg = tems.ts_modechg_arg;
6701253Slq150181 
6711253Slq150181 	/*
672*7688SAaron.Zang@Sun.COM 	 * Release the lock while doing callback.
6731253Slq150181 	 */
674*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
675*7688SAaron.Zang@Sun.COM 	cb(cb_arg);
6761253Slq150181 }
6771253Slq150181 
6781253Slq150181 /*
6791253Slq150181  * This function is used to display a rectangular blit of data
6801253Slq150181  * of a given size and location via the underlying framebuffer driver.
6811253Slq150181  * The blit can be as small as a pixel or as large as the screen.
6821253Slq150181  */
6831253Slq150181 void
tems_display_layered(struct vis_consdisplay * pda,cred_t * credp)684*7688SAaron.Zang@Sun.COM tems_display_layered(
6851253Slq150181 	struct vis_consdisplay *pda,
6861253Slq150181 	cred_t *credp)
6871253Slq150181 {
6881253Slq150181 	int rval;
6891253Slq150181 
690*7688SAaron.Zang@Sun.COM 	(void) ldi_ioctl(tems.ts_hdl, VIS_CONSDISPLAY,
6911253Slq150181 	    (intptr_t)pda, FKIOCTL, credp, &rval);
6921253Slq150181 }
6931253Slq150181 
6941253Slq150181 /*
6951253Slq150181  * This function is used to invoke a block copy operation in the
6961253Slq150181  * underlying framebuffer driver.  Rectangle copies are how scrolling
6971253Slq150181  * is implemented, as well as horizontal text shifting escape seqs.
6981253Slq150181  * such as from vi when deleting characters and words.
6991253Slq150181  */
7001253Slq150181 void
tems_copy_layered(struct vis_conscopy * pma,cred_t * credp)701*7688SAaron.Zang@Sun.COM tems_copy_layered(
7021253Slq150181 	struct vis_conscopy *pma,
7031253Slq150181 	cred_t *credp)
7041253Slq150181 {
7051253Slq150181 	int rval;
7061253Slq150181 
707*7688SAaron.Zang@Sun.COM 	(void) ldi_ioctl(tems.ts_hdl, VIS_CONSCOPY,
7081253Slq150181 	    (intptr_t)pma, FKIOCTL, credp, &rval);
7091253Slq150181 }
7101253Slq150181 
7111253Slq150181 /*
7121253Slq150181  * This function is used to show or hide a rectangluar monochrom
7131253Slq150181  * pixel inverting, text block cursor via the underlying framebuffer.
7141253Slq150181  */
7151253Slq150181 void
tems_cursor_layered(struct vis_conscursor * pca,cred_t * credp)716*7688SAaron.Zang@Sun.COM tems_cursor_layered(
7171253Slq150181 	struct vis_conscursor *pca,
7181253Slq150181 	cred_t *credp)
7191253Slq150181 {
7201253Slq150181 	int rval;
7211253Slq150181 
722*7688SAaron.Zang@Sun.COM 	(void) ldi_ioctl(tems.ts_hdl, VIS_CONSCURSOR,
7231253Slq150181 	    (intptr_t)pca, FKIOCTL, credp, &rval);
7241253Slq150181 }
7251253Slq150181 
726*7688SAaron.Zang@Sun.COM static void
tem_kdsetmode(int mode,cred_t * credp)727*7688SAaron.Zang@Sun.COM tem_kdsetmode(int mode, cred_t *credp)
728*7688SAaron.Zang@Sun.COM {
729*7688SAaron.Zang@Sun.COM 	int rval;
730*7688SAaron.Zang@Sun.COM 
731*7688SAaron.Zang@Sun.COM 	(void) ldi_ioctl(tems.ts_hdl, KDSETMODE,
732*7688SAaron.Zang@Sun.COM 	    (intptr_t)mode, FKIOCTL, credp, &rval);
733*7688SAaron.Zang@Sun.COM 
734*7688SAaron.Zang@Sun.COM }
735*7688SAaron.Zang@Sun.COM 
736*7688SAaron.Zang@Sun.COM static void
tems_reset_colormap(cred_t * credp,enum called_from called_from)737*7688SAaron.Zang@Sun.COM tems_reset_colormap(cred_t *credp, enum called_from called_from)
7381253Slq150181 {
7391253Slq150181 	struct vis_cmap cm;
7401253Slq150181 	int rval;
7411253Slq150181 
7421253Slq150181 	if (called_from == CALLED_FROM_STANDALONE)
7431253Slq150181 		return;
7441253Slq150181 
745*7688SAaron.Zang@Sun.COM 	switch (tems.ts_pdepth) {
7461253Slq150181 	case 8:
7471253Slq150181 		cm.index = 0;
7481253Slq150181 		cm.count = 16;
7491253Slq150181 		cm.red   = cmap4_to_24.red;   /* 8-bits (1/3 of TrueColor 24) */
7501253Slq150181 		cm.blue  = cmap4_to_24.blue;  /* 8-bits (1/3 of TrueColor 24) */
7511253Slq150181 		cm.green = cmap4_to_24.green; /* 8-bits (1/3 of TrueColor 24) */
752*7688SAaron.Zang@Sun.COM 		(void) ldi_ioctl(tems.ts_hdl, VIS_PUTCMAP, (intptr_t)&cm,
7531253Slq150181 		    FKIOCTL, credp, &rval);
7541253Slq150181 		break;
7551253Slq150181 	}
7561253Slq150181 }
7571253Slq150181 
7581253Slq150181 void
tem_get_size(ushort_t * r,ushort_t * c,ushort_t * x,ushort_t * y)759*7688SAaron.Zang@Sun.COM tem_get_size(ushort_t *r, ushort_t *c,
7601253Slq150181 	ushort_t *x, ushort_t *y)
7611253Slq150181 {
762*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
763*7688SAaron.Zang@Sun.COM 	*r = (ushort_t)tems.ts_c_dimension.height;
764*7688SAaron.Zang@Sun.COM 	*c = (ushort_t)tems.ts_c_dimension.width;
765*7688SAaron.Zang@Sun.COM 	*x = (ushort_t)tems.ts_p_dimension.width;
766*7688SAaron.Zang@Sun.COM 	*y = (ushort_t)tems.ts_p_dimension.height;
767*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
7681253Slq150181 }
7691253Slq150181 
7701253Slq150181 void
tem_register_modechg_cb(tem_modechg_cb_t func,tem_modechg_cb_arg_t arg)771*7688SAaron.Zang@Sun.COM tem_register_modechg_cb(tem_modechg_cb_t func,
7721253Slq150181 	tem_modechg_cb_arg_t arg)
7731253Slq150181 {
774*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
775*7688SAaron.Zang@Sun.COM 
776*7688SAaron.Zang@Sun.COM 	tems.ts_modechg_cb = func;
777*7688SAaron.Zang@Sun.COM 	tems.ts_modechg_arg = arg;
778*7688SAaron.Zang@Sun.COM 
779*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
7801253Slq150181 }
7811253Slq150181 
7821253Slq150181 /*
7831253Slq150181  * This function is to scroll up the OBP output, which has
7841253Slq150181  * different screen height and width with our kernel console.
7851253Slq150181  */
7861253Slq150181 static void
tem_prom_scroll_up(struct tem_vt_state * tem,int nrows,cred_t * credp,enum called_from called_from)787*7688SAaron.Zang@Sun.COM tem_prom_scroll_up(struct tem_vt_state *tem, int nrows, cred_t *credp,
788*7688SAaron.Zang@Sun.COM     enum called_from called_from)
7891253Slq150181 {
7901253Slq150181 	struct vis_conscopy	ma;
7911253Slq150181 	int	ncols, width;
7921253Slq150181 
7931253Slq150181 	/* copy */
794*7688SAaron.Zang@Sun.COM 	ma.s_row = nrows * tems.ts_font.height;
795*7688SAaron.Zang@Sun.COM 	ma.e_row = tems.ts_p_dimension.height - 1;
7961253Slq150181 	ma.t_row = 0;
7971253Slq150181 
7981253Slq150181 	ma.s_col = 0;
799*7688SAaron.Zang@Sun.COM 	ma.e_col = tems.ts_p_dimension.width - 1;
8001253Slq150181 	ma.t_col = 0;
8011253Slq150181 
802*7688SAaron.Zang@Sun.COM 	tems_safe_copy(&ma, credp, called_from);
8031253Slq150181 
8041253Slq150181 	/* clear */
805*7688SAaron.Zang@Sun.COM 	width = tems.ts_font.width;
806*7688SAaron.Zang@Sun.COM 	ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
8071253Slq150181 
808*7688SAaron.Zang@Sun.COM 	tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y,
809*7688SAaron.Zang@Sun.COM 	    0, ncols, 0, B_TRUE, credp, called_from);
8101253Slq150181 }
8111253Slq150181 
8121253Slq150181 #define	PROM_DEFAULT_FONT_HEIGHT	22
813*7688SAaron.Zang@Sun.COM #define	PROM_DEFAULT_WINDOW_TOP		0x8a
8141253Slq150181 
8151253Slq150181 /*
8161253Slq150181  * This function is to compute the starting row of the console, according to
8171253Slq150181  * PROM cursor's position. Here we have to take different fonts into account.
8181253Slq150181  */
8191253Slq150181 static int
tem_adjust_row(struct tem_vt_state * tem,int prom_row,cred_t * credp,enum called_from called_from)820*7688SAaron.Zang@Sun.COM tem_adjust_row(struct tem_vt_state *tem, int prom_row, cred_t *credp,
821*7688SAaron.Zang@Sun.COM     enum called_from called_from)
8221253Slq150181 {
8231253Slq150181 	int	tem_row;
8241253Slq150181 	int	tem_y;
8251253Slq150181 	int	prom_charheight = 0;
8261253Slq150181 	int	prom_window_top = 0;
8271253Slq150181 	int	scroll_up_lines;
8281253Slq150181 
8291253Slq150181 	plat_tem_get_prom_font_size(&prom_charheight, &prom_window_top);
8301253Slq150181 	if (prom_charheight == 0)
8311253Slq150181 		prom_charheight = PROM_DEFAULT_FONT_HEIGHT;
8321253Slq150181 	if (prom_window_top == 0)
8331253Slq150181 		prom_window_top = PROM_DEFAULT_WINDOW_TOP;
8341253Slq150181 
8351253Slq150181 	tem_y = (prom_row + 1) * prom_charheight + prom_window_top -
836*7688SAaron.Zang@Sun.COM 	    tems.ts_p_offset.y;
837*7688SAaron.Zang@Sun.COM 	tem_row = (tem_y + tems.ts_font.height - 1) /
838*7688SAaron.Zang@Sun.COM 	    tems.ts_font.height - 1;
8391253Slq150181 
8401253Slq150181 	if (tem_row < 0) {
8411253Slq150181 		tem_row = 0;
842*7688SAaron.Zang@Sun.COM 	} else if (tem_row >= (tems.ts_c_dimension.height - 1)) {
8431253Slq150181 		/*
8441253Slq150181 		 * Scroll up the prom outputs if the PROM cursor's position is
8451253Slq150181 		 * below our tem's lower boundary.
8461253Slq150181 		 */
8471253Slq150181 		scroll_up_lines = tem_row -
848*7688SAaron.Zang@Sun.COM 		    (tems.ts_c_dimension.height - 1);
849*7688SAaron.Zang@Sun.COM 		tem_prom_scroll_up(tem, scroll_up_lines, credp, called_from);
850*7688SAaron.Zang@Sun.COM 		tem_row = tems.ts_c_dimension.height - 1;
8511253Slq150181 	}
8521253Slq150181 
8531253Slq150181 	return (tem_row);
8541253Slq150181 }
8553994Slq150181 
856*7688SAaron.Zang@Sun.COM void
tem_pix_align(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)857*7688SAaron.Zang@Sun.COM tem_pix_align(struct tem_vt_state *tem, cred_t *credp,
858*7688SAaron.Zang@Sun.COM     enum called_from called_from)
859*7688SAaron.Zang@Sun.COM {
860*7688SAaron.Zang@Sun.COM 	uint32_t row = 0;
861*7688SAaron.Zang@Sun.COM 	uint32_t col = 0;
862*7688SAaron.Zang@Sun.COM 
863*7688SAaron.Zang@Sun.COM 	if (plat_stdout_is_framebuffer()) {
864*7688SAaron.Zang@Sun.COM 		plat_tem_hide_prom_cursor();
865*7688SAaron.Zang@Sun.COM 
866*7688SAaron.Zang@Sun.COM 		/*
867*7688SAaron.Zang@Sun.COM 		 * We are getting the current cursor position in pixel
868*7688SAaron.Zang@Sun.COM 		 * mode so that we don't over-write the console output
869*7688SAaron.Zang@Sun.COM 		 * during boot.
870*7688SAaron.Zang@Sun.COM 		 */
871*7688SAaron.Zang@Sun.COM 		plat_tem_get_prom_pos(&row, &col);
872*7688SAaron.Zang@Sun.COM 
873*7688SAaron.Zang@Sun.COM 		/*
874*7688SAaron.Zang@Sun.COM 		 * Adjust the row if necessary when the font of our
875*7688SAaron.Zang@Sun.COM 		 * kernel console tem is different with that of prom
876*7688SAaron.Zang@Sun.COM 		 * tem.
877*7688SAaron.Zang@Sun.COM 		 */
878*7688SAaron.Zang@Sun.COM 		row = tem_adjust_row(tem, row, credp, called_from);
879*7688SAaron.Zang@Sun.COM 
880*7688SAaron.Zang@Sun.COM 		/* first line of our kernel console output */
881*7688SAaron.Zang@Sun.COM 		tem->tvs_first_line = row + 1;
882*7688SAaron.Zang@Sun.COM 
883*7688SAaron.Zang@Sun.COM 		/* re-set and align cusror position */
884*7688SAaron.Zang@Sun.COM 		tem->tvs_s_cursor.row = tem->tvs_c_cursor.row =
885*7688SAaron.Zang@Sun.COM 		    (screen_pos_t)row;
886*7688SAaron.Zang@Sun.COM 		tem->tvs_s_cursor.col = tem->tvs_c_cursor.col = 0;
887*7688SAaron.Zang@Sun.COM 	} else {
888*7688SAaron.Zang@Sun.COM 		tem_safe_reset_display(tem, credp, called_from, B_TRUE, B_TRUE);
889*7688SAaron.Zang@Sun.COM 	}
890*7688SAaron.Zang@Sun.COM }
891*7688SAaron.Zang@Sun.COM 
8923994Slq150181 static void
tems_get_inverses(boolean_t * p_inverse,boolean_t * p_inverse_screen)893*7688SAaron.Zang@Sun.COM tems_get_inverses(boolean_t *p_inverse, boolean_t *p_inverse_screen)
8943994Slq150181 {
8953994Slq150181 	int i_inverse = 0;
8963994Slq150181 	int i_inverse_screen = 0;
8973994Slq150181 
8983994Slq150181 	plat_tem_get_inverses(&i_inverse, &i_inverse_screen);
8993994Slq150181 
9003994Slq150181 	*p_inverse = (i_inverse == 0) ? B_FALSE : B_TRUE;
9013994Slq150181 	*p_inverse_screen = (i_inverse_screen == 0) ? B_FALSE : B_TRUE;
9023994Slq150181 }
9033994Slq150181 
9043994Slq150181 /*
9053994Slq150181  * Get the foreground/background color and attributes from the initial
9063994Slq150181  * PROM, so that our kernel console can keep the same visual behaviour.
9073994Slq150181  */
9083994Slq150181 static void
tems_get_initial_color(tem_color_t * pcolor)909*7688SAaron.Zang@Sun.COM tems_get_initial_color(tem_color_t *pcolor)
9103994Slq150181 {
9113994Slq150181 	boolean_t inverse, inverse_screen;
9123994Slq150181 	unsigned short  flags = 0;
9133994Slq150181 
914*7688SAaron.Zang@Sun.COM 	pcolor->fg_color = DEFAULT_ANSI_FOREGROUND;
915*7688SAaron.Zang@Sun.COM 	pcolor->bg_color = DEFAULT_ANSI_BACKGROUND;
9163994Slq150181 
9173994Slq150181 	if (plat_stdout_is_framebuffer()) {
918*7688SAaron.Zang@Sun.COM 		tems_get_inverses(&inverse, &inverse_screen);
9193994Slq150181 		if (inverse)
9203994Slq150181 			flags |= TEM_ATTR_REVERSE;
9213994Slq150181 		if (inverse_screen)
9223994Slq150181 			flags |= TEM_ATTR_SCREEN_REVERSE;
9233994Slq150181 		if (flags != 0)
9243994Slq150181 			flags |= TEM_ATTR_BOLD;
9253994Slq150181 	}
9263994Slq150181 
927*7688SAaron.Zang@Sun.COM 	pcolor->a_flags = flags;
928*7688SAaron.Zang@Sun.COM }
929*7688SAaron.Zang@Sun.COM 
930*7688SAaron.Zang@Sun.COM uchar_t
tem_get_fbmode(tem_vt_state_t tem_arg)931*7688SAaron.Zang@Sun.COM tem_get_fbmode(tem_vt_state_t tem_arg)
932*7688SAaron.Zang@Sun.COM {
933*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
934*7688SAaron.Zang@Sun.COM 
935*7688SAaron.Zang@Sun.COM 	uchar_t fbmode;
936*7688SAaron.Zang@Sun.COM 
937*7688SAaron.Zang@Sun.COM 	mutex_enter(&tem->tvs_lock);
938*7688SAaron.Zang@Sun.COM 	fbmode = tem->tvs_fbmode;
939*7688SAaron.Zang@Sun.COM 	mutex_exit(&tem->tvs_lock);
940*7688SAaron.Zang@Sun.COM 
941*7688SAaron.Zang@Sun.COM 	return (fbmode);
942*7688SAaron.Zang@Sun.COM }
943*7688SAaron.Zang@Sun.COM 
944*7688SAaron.Zang@Sun.COM void
tem_set_fbmode(tem_vt_state_t tem_arg,uchar_t fbmode,cred_t * credp)945*7688SAaron.Zang@Sun.COM tem_set_fbmode(tem_vt_state_t tem_arg, uchar_t fbmode, cred_t *credp)
946*7688SAaron.Zang@Sun.COM {
947*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
948*7688SAaron.Zang@Sun.COM 
949*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
950*7688SAaron.Zang@Sun.COM 	mutex_enter(&tem->tvs_lock);
951*7688SAaron.Zang@Sun.COM 
952*7688SAaron.Zang@Sun.COM 	if (fbmode == tem->tvs_fbmode) {
953*7688SAaron.Zang@Sun.COM 		mutex_exit(&tem->tvs_lock);
954*7688SAaron.Zang@Sun.COM 		mutex_exit(&tems.ts_lock);
955*7688SAaron.Zang@Sun.COM 		return;
956*7688SAaron.Zang@Sun.COM 	}
957*7688SAaron.Zang@Sun.COM 
958*7688SAaron.Zang@Sun.COM 	tem->tvs_fbmode = fbmode;
959*7688SAaron.Zang@Sun.COM 
960*7688SAaron.Zang@Sun.COM 	if (tem->tvs_isactive) {
961*7688SAaron.Zang@Sun.COM 		tem_kdsetmode(tem->tvs_fbmode, credp);
962*7688SAaron.Zang@Sun.COM 		if (fbmode == KD_TEXT)
963*7688SAaron.Zang@Sun.COM 			tem_safe_unblank_screen(tem, credp, CALLED_FROM_NORMAL);
964*7688SAaron.Zang@Sun.COM 	}
965*7688SAaron.Zang@Sun.COM 
966*7688SAaron.Zang@Sun.COM 	mutex_exit(&tem->tvs_lock);
967*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
9683994Slq150181 }
969*7688SAaron.Zang@Sun.COM 
970*7688SAaron.Zang@Sun.COM void
tem_activate(tem_vt_state_t tem_arg,boolean_t unblank,cred_t * credp)971*7688SAaron.Zang@Sun.COM tem_activate(tem_vt_state_t tem_arg, boolean_t unblank, cred_t *credp)
972*7688SAaron.Zang@Sun.COM {
973*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
974*7688SAaron.Zang@Sun.COM 
975*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
976*7688SAaron.Zang@Sun.COM 	tems.ts_active = tem;
977*7688SAaron.Zang@Sun.COM 
978*7688SAaron.Zang@Sun.COM 	mutex_enter(&tem->tvs_lock);
979*7688SAaron.Zang@Sun.COM 	tem->tvs_isactive = B_TRUE;
980*7688SAaron.Zang@Sun.COM 
981*7688SAaron.Zang@Sun.COM 	tem_kdsetmode(tem->tvs_fbmode, credp);
982*7688SAaron.Zang@Sun.COM 
983*7688SAaron.Zang@Sun.COM 	if (unblank)
984*7688SAaron.Zang@Sun.COM 		tem_safe_unblank_screen(tem, credp, CALLED_FROM_NORMAL);
985*7688SAaron.Zang@Sun.COM 
986*7688SAaron.Zang@Sun.COM 	mutex_exit(&tem->tvs_lock);
987*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
988*7688SAaron.Zang@Sun.COM }
989*7688SAaron.Zang@Sun.COM 
990*7688SAaron.Zang@Sun.COM void
tem_switch(tem_vt_state_t tem_arg1,tem_vt_state_t tem_arg2,cred_t * credp)991*7688SAaron.Zang@Sun.COM tem_switch(tem_vt_state_t tem_arg1, tem_vt_state_t tem_arg2, cred_t *credp)
992*7688SAaron.Zang@Sun.COM {
993*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *cur = (struct tem_vt_state *)tem_arg1;
994*7688SAaron.Zang@Sun.COM 	struct tem_vt_state *tobe = (struct tem_vt_state *)tem_arg2;
995*7688SAaron.Zang@Sun.COM 
996*7688SAaron.Zang@Sun.COM 	mutex_enter(&tems.ts_lock);
997*7688SAaron.Zang@Sun.COM 	mutex_enter(&tobe->tvs_lock);
998*7688SAaron.Zang@Sun.COM 	mutex_enter(&cur->tvs_lock);
999*7688SAaron.Zang@Sun.COM 
1000*7688SAaron.Zang@Sun.COM 	tems.ts_active = tobe;
1001*7688SAaron.Zang@Sun.COM 	cur->tvs_isactive = B_FALSE;
1002*7688SAaron.Zang@Sun.COM 	tobe->tvs_isactive = B_TRUE;
1003*7688SAaron.Zang@Sun.COM 
1004*7688SAaron.Zang@Sun.COM 	mutex_exit(&cur->tvs_lock);
1005*7688SAaron.Zang@Sun.COM 
1006*7688SAaron.Zang@Sun.COM 	if (cur->tvs_fbmode != tobe->tvs_fbmode)
1007*7688SAaron.Zang@Sun.COM 		tem_kdsetmode(tobe->tvs_fbmode, credp);
1008*7688SAaron.Zang@Sun.COM 
1009*7688SAaron.Zang@Sun.COM 	if (tobe->tvs_fbmode == KD_TEXT)
1010*7688SAaron.Zang@Sun.COM 		tem_safe_unblank_screen(tobe, credp, CALLED_FROM_NORMAL);
1011*7688SAaron.Zang@Sun.COM 
1012*7688SAaron.Zang@Sun.COM 	mutex_exit(&tobe->tvs_lock);
1013*7688SAaron.Zang@Sun.COM 	mutex_exit(&tems.ts_lock);
1014*7688SAaron.Zang@Sun.COM }
1015