4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * ANSI terminal emulator module; parse ANSI X3.64 escape sequences and
31 * How Virtual Terminal Emulator Works:
33 * Every virtual terminal is associated with a tem_vt_state structure
34 * and maintains a virtual screen buffer in tvs_screen_buf, which contains
35 * all the characters which should be shown on the physical screen when
36 * the terminal is activated. There are also two other buffers, tvs_fg_buf
37 * and tvs_bg_buf, which track the foreground and background colors of the
38 * on screen characters
40 * Data written to a virtual terminal is composed of characters which
41 * should be displayed on the screen when this virtual terminal is
42 * activated, fg/bg colors of these characters, and other control
43 * information (escape sequence, etc).
45 * When data is passed to a virtual terminal it first is parsed for
46 * control information by tem_safe_parse(). Subsequently the character
47 * and color data are written to tvs_screen_buf, tvs_fg_buf, and
48 * tvs_bg_buf. They are saved in these buffers in order to refresh
49 * the screen when this terminal is activated. If the terminal is
50 * currently active, the data (characters and colors) are also written
51 * to the physical screen by invoking a callback function,
52 * tem_safe_text_callbacks() or tem_safe_pix_callbacks().
54 * When rendering data to the framebuffer, if the framebuffer is in
55 * VIS_PIXEL mode, the character data will first be converted to pixel
56 * data using tem_safe_pix_bit2pix(), and then the pixels get displayed
57 * on the physical screen. We only store the character and color data in
58 * tem_vt_state since the bit2pix conversion only happens when actually
59 * rendering to the physical framebuffer.
63 #include <sys/types.h>
66 #include <sys/errno.h>
70 #include <sys/ascii.h>
71 #include <sys/consdev.h>
75 #include <sys/modctl.h>
76 #include <sys/strsubr.h>
78 #include <sys/visual_io.h>
79 #include <sys/mutex.h>
80 #include <sys/param.h>
81 #include <sys/debug.h>
82 #include <sys/cmn_err.h>
83 #include <sys/console.h>
85 #include <sys/sunddi.h>
86 #include <sys/sunldi.h>
87 #include <sys/tem_impl.h>
88 #ifdef _HAVE_TEM_FIRMWARE
89 #include <sys/promif.h>
90 #endif /* _HAVE_TEM_FIRMWARE */
91 #include <sys/consplat.h>
93 #include <sys/sysmacros.h>
95 #include <sys/t_lock.h>
97 /* Terminal emulator internal helper functions */
98 static void tems_setup_terminal(struct vis_devinit
*, size_t, size_t);
99 static void tems_modechange_callback(struct vis_modechg_arg
*,
100 struct vis_devinit
*);
102 static void tems_reset_colormap(cred_t
*, enum called_from
);
104 static void tem_free_buf(struct tem_vt_state
*);
105 static void tem_internal_init(struct tem_vt_state
*, cred_t
*, boolean_t
,
107 static void tems_get_initial_color(tem_color_t
*pcolor
);
112 static ldi_ident_t term_li
= NULL
;
113 tem_state_t tems
; /* common term info */
114 _NOTE(MUTEX_PROTECTS_DATA(tems
.ts_lock
, tems
))
116 extern struct mod_ops mod_miscops
;
118 static struct modlmisc modlmisc
= {
119 &mod_miscops
, /* modops */
120 "ANSI Terminal Emulator", /* name */
123 static struct modlinkage modlinkage
= {
124 MODREV_1
, (void *)&modlmisc
, NULL
131 ret
= mod_install(&modlinkage
);
134 ret
= ldi_ident_from_mod(&modlinkage
, &term_li
);
136 (void) mod_remove(&modlinkage
);
140 mutex_init(&tems
.ts_lock
, (char *)NULL
, MUTEX_DRIVER
, NULL
);
141 list_create(&tems
.ts_list
, sizeof (struct tem_vt_state
),
142 offsetof(struct tem_vt_state
, tvs_list_node
));
143 tems
.ts_active
= NULL
;
153 ret
= mod_remove(&modlinkage
);
155 ldi_ident_release(term_li
);
162 _info(struct modinfo
*modinfop
)
164 return (mod_info(&modlinkage
, modinfop
));
168 tem_add(struct tem_vt_state
*tem
)
170 ASSERT(MUTEX_HELD(&tems
.ts_lock
) && MUTEX_HELD(&tem
->tvs_lock
));
172 list_insert_head(&tems
.ts_list
, tem
);
176 tem_rm(struct tem_vt_state
*tem
)
178 ASSERT(MUTEX_HELD(&tems
.ts_lock
) && MUTEX_HELD(&tem
->tvs_lock
));
180 list_remove(&tems
.ts_list
, tem
);
184 * This is the main entry point to the module. It handles output requests
185 * during normal system operation, when (e.g.) mutexes are available.
188 tem_write(tem_vt_state_t tem_arg
, uchar_t
*buf
, ssize_t len
, cred_t
*credp
)
190 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
192 mutex_enter(&tems
.ts_lock
);
193 mutex_enter(&tem
->tvs_lock
);
195 if (!tem
->tvs_initialized
) {
196 mutex_exit(&tem
->tvs_lock
);
197 mutex_exit(&tems
.ts_lock
);
201 tem_safe_check_first_time(tem
, credp
, CALLED_FROM_NORMAL
);
202 tem_safe_terminal_emulate(tem
, buf
, len
, credp
, CALLED_FROM_NORMAL
);
204 mutex_exit(&tem
->tvs_lock
);
205 mutex_exit(&tems
.ts_lock
);
209 tem_internal_init(struct tem_vt_state
*ptem
, cred_t
*credp
,
210 boolean_t init_color
, boolean_t clear_screen
)
217 size_t tc_size
= sizeof (text_color_t
);
219 ASSERT(MUTEX_HELD(&tems
.ts_lock
) && MUTEX_HELD(&ptem
->tvs_lock
));
221 if (tems
.ts_display_mode
== VIS_PIXEL
) {
222 ptem
->tvs_pix_data_size
= tems
.ts_pix_data_size
;
224 kmem_alloc(ptem
->tvs_pix_data_size
, KM_SLEEP
);
227 ptem
->tvs_outbuf_size
= tems
.ts_c_dimension
.width
;
229 (unsigned char *)kmem_alloc(ptem
->tvs_outbuf_size
, KM_SLEEP
);
231 width
= tems
.ts_c_dimension
.width
;
232 height
= tems
.ts_c_dimension
.height
;
233 ptem
->tvs_screen_buf_size
= width
* height
;
234 ptem
->tvs_screen_buf
=
235 (unsigned char *)kmem_alloc(width
* height
, KM_SLEEP
);
237 total
= width
* height
* tc_size
;
238 ptem
->tvs_fg_buf
= (text_color_t
*)kmem_alloc(total
, KM_SLEEP
);
239 ptem
->tvs_bg_buf
= (text_color_t
*)kmem_alloc(total
, KM_SLEEP
);
240 ptem
->tvs_color_buf_size
= total
;
242 tem_safe_reset_display(ptem
, credp
, CALLED_FROM_NORMAL
,
243 clear_screen
, init_color
);
245 tem_safe_get_color(ptem
, &fg
, &bg
, TEM_ATTR_SCREEN_REVERSE
);
246 for (i
= 0; i
< height
; i
++)
247 for (j
= 0; j
< width
; j
++) {
248 ptem
->tvs_screen_buf
[i
* width
+ j
] = ' ';
249 ptem
->tvs_fg_buf
[(i
* width
+j
) * tc_size
] = fg
;
250 ptem
->tvs_bg_buf
[(i
* width
+j
) * tc_size
] = bg
;
254 ptem
->tvs_initialized
= 1;
258 tem_initialized(tem_vt_state_t tem_arg
)
260 struct tem_vt_state
*ptem
= (struct tem_vt_state
*)tem_arg
;
263 mutex_enter(&ptem
->tvs_lock
);
264 ret
= ptem
->tvs_initialized
;
265 mutex_exit(&ptem
->tvs_lock
);
271 tem_init(cred_t
*credp
)
273 struct tem_vt_state
*ptem
;
275 ptem
= kmem_zalloc(sizeof (struct tem_vt_state
), KM_SLEEP
);
276 mutex_init(&ptem
->tvs_lock
, (char *)NULL
, MUTEX_DRIVER
, NULL
);
278 mutex_enter(&tems
.ts_lock
);
279 mutex_enter(&ptem
->tvs_lock
);
281 ptem
->tvs_isactive
= B_FALSE
;
282 ptem
->tvs_fbmode
= KD_TEXT
;
285 * A tem is regarded as initialized only after tem_internal_init(),
286 * will be set at the end of tem_internal_init().
288 ptem
->tvs_initialized
= 0;
291 if (!tems
.ts_initialized
) {
293 * Only happens during early console configuration.
296 mutex_exit(&ptem
->tvs_lock
);
297 mutex_exit(&tems
.ts_lock
);
298 return ((tem_vt_state_t
)ptem
);
301 tem_internal_init(ptem
, credp
, B_TRUE
, B_FALSE
);
303 mutex_exit(&ptem
->tvs_lock
);
304 mutex_exit(&tems
.ts_lock
);
306 return ((tem_vt_state_t
)ptem
);
310 * re-init the tem after video mode has changed and tems_info has
311 * been re-inited. The lock is already held.
314 tem_reinit(struct tem_vt_state
*tem
, boolean_t reset_display
)
316 ASSERT(MUTEX_HELD(&tems
.ts_lock
) && MUTEX_HELD(&tem
->tvs_lock
));
318 tem_free_buf(tem
); /* only free virtual buffers */
321 tem_internal_init(tem
, kcred
, B_FALSE
, reset_display
);
325 tem_free_buf(struct tem_vt_state
*tem
)
327 ASSERT(tem
!= NULL
&& MUTEX_HELD(&tem
->tvs_lock
));
329 if (tem
->tvs_outbuf
!= NULL
)
330 kmem_free(tem
->tvs_outbuf
, tem
->tvs_outbuf_size
);
331 if (tem
->tvs_pix_data
!= NULL
)
332 kmem_free(tem
->tvs_pix_data
, tem
->tvs_pix_data_size
);
333 if (tem
->tvs_screen_buf
!= NULL
)
334 kmem_free(tem
->tvs_screen_buf
, tem
->tvs_screen_buf_size
);
335 if (tem
->tvs_fg_buf
!= NULL
)
336 kmem_free(tem
->tvs_fg_buf
, tem
->tvs_color_buf_size
);
337 if (tem
->tvs_bg_buf
!= NULL
)
338 kmem_free(tem
->tvs_bg_buf
, tem
->tvs_color_buf_size
);
342 tem_destroy(tem_vt_state_t tem_arg
, cred_t
*credp
)
344 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
346 mutex_enter(&tems
.ts_lock
);
347 mutex_enter(&tem
->tvs_lock
);
349 if (tem
->tvs_isactive
&& tem
->tvs_fbmode
== KD_TEXT
)
350 tem_safe_blank_screen(tem
, credp
, CALLED_FROM_NORMAL
);
355 if (tems
.ts_active
== tem
)
356 tems
.ts_active
= NULL
;
358 mutex_exit(&tem
->tvs_lock
);
359 mutex_exit(&tems
.ts_lock
);
361 kmem_free(tem
, sizeof (struct tem_vt_state
));
365 tems_failed(cred_t
*credp
, boolean_t finish_ioctl
)
369 ASSERT(MUTEX_HELD(&tems
.ts_lock
));
372 (void) ldi_ioctl(tems
.ts_hdl
, VIS_DEVFINI
, 0,
373 FWRITE
|FKIOCTL
, credp
, &lyr_rval
);
375 (void) ldi_close(tems
.ts_hdl
, NULL
, credp
);
381 * only called once during boot
384 tem_info_init(char *pathname
, cred_t
*credp
)
387 struct vis_devinit temargs
;
391 struct tem_vt_state
*p
;
393 mutex_enter(&tems
.ts_lock
);
395 if (tems
.ts_initialized
) {
396 mutex_exit(&tems
.ts_lock
);
401 * Open the layered device using the devfs physical device name
402 * after adding the /devices prefix.
404 pathbuf
= kmem_alloc(MAXPATHLEN
, KM_SLEEP
);
405 (void) strcpy(pathbuf
, "/devices");
406 if (i_ddi_prompath_to_devfspath(pathname
,
407 pathbuf
+ strlen("/devices")) != DDI_SUCCESS
) {
408 cmn_err(CE_WARN
, "terminal-emulator: path conversion error");
409 kmem_free(pathbuf
, MAXPATHLEN
);
411 mutex_exit(&tems
.ts_lock
);
414 if (ldi_open_by_name(pathbuf
, FWRITE
, credp
,
415 &tems
.ts_hdl
, term_li
) != 0) {
416 cmn_err(CE_WARN
, "terminal-emulator: device path open error");
417 kmem_free(pathbuf
, MAXPATHLEN
);
419 mutex_exit(&tems
.ts_lock
);
422 kmem_free(pathbuf
, MAXPATHLEN
);
424 temargs
.modechg_cb
= (vis_modechg_cb_t
)tems_modechange_callback
;
425 temargs
.modechg_arg
= NULL
;
428 * Initialize the console and get the device parameters
430 if (ldi_ioctl(tems
.ts_hdl
, VIS_DEVINIT
,
431 (intptr_t)&temargs
, FWRITE
|FKIOCTL
, credp
, &lyr_rval
) != 0) {
432 cmn_err(CE_WARN
, "terminal emulator: Compatible fb not found");
433 ret
= tems_failed(credp
, B_FALSE
);
434 mutex_exit(&tems
.ts_lock
);
438 /* Make sure the fb driver and terminal emulator versions match */
439 if (temargs
.version
!= VIS_CONS_REV
) {
441 "terminal emulator: VIS_CONS_REV %d (see sys/visual_io.h) "
442 "of console fb driver not supported", temargs
.version
);
443 ret
= tems_failed(credp
, B_TRUE
);
444 mutex_exit(&tems
.ts_lock
);
448 if ((tems
.ts_fb_polledio
= temargs
.polledio
) == NULL
) {
449 cmn_err(CE_WARN
, "terminal emulator: fb doesn't support polled "
451 ret
= tems_failed(credp
, B_TRUE
);
452 mutex_exit(&tems
.ts_lock
);
456 /* other sanity checks */
457 if (!((temargs
.depth
== 4) || (temargs
.depth
== 8) ||
458 (temargs
.depth
== 24) || (temargs
.depth
== 32))) {
459 cmn_err(CE_WARN
, "terminal emulator: unsupported depth");
460 ret
= tems_failed(credp
, B_TRUE
);
461 mutex_exit(&tems
.ts_lock
);
465 if ((temargs
.mode
!= VIS_TEXT
) && (temargs
.mode
!= VIS_PIXEL
)) {
466 cmn_err(CE_WARN
, "terminal emulator: unsupported mode");
467 ret
= tems_failed(credp
, B_TRUE
);
468 mutex_exit(&tems
.ts_lock
);
472 if ((temargs
.mode
== VIS_PIXEL
) && plat_stdout_is_framebuffer())
473 plat_tem_get_prom_size(&height
, &width
);
476 * Initialize the common terminal emulator info
478 tems_setup_terminal(&temargs
, height
, width
);
480 tems_reset_colormap(credp
, CALLED_FROM_NORMAL
);
481 tems_get_initial_color(&tems
.ts_init_color
);
483 tems
.ts_initialized
= 1; /* initialization flag */
485 for (p
= list_head(&tems
.ts_list
); p
!= NULL
;
486 p
= list_next(&tems
.ts_list
, p
)) {
487 mutex_enter(&p
->tvs_lock
);
488 tem_internal_init(p
, credp
, B_TRUE
, B_FALSE
);
489 if (temargs
.mode
== VIS_PIXEL
)
490 tem_pix_align(p
, credp
, CALLED_FROM_NORMAL
);
491 mutex_exit(&p
->tvs_lock
);
494 mutex_exit(&tems
.ts_lock
);
498 #define TEMS_DEPTH_DIFF 0x01
499 #define TEMS_DIMENSION_DIFF 0x02
502 tems_check_videomode(struct vis_devinit
*tp
)
506 if (tems
.ts_pdepth
!= tp
->depth
)
507 result
|= TEMS_DEPTH_DIFF
;
509 if (tp
->mode
== VIS_TEXT
) {
510 if (tems
.ts_c_dimension
.width
!= tp
->width
||
511 tems
.ts_c_dimension
.height
!= tp
->height
)
512 result
|= TEMS_DIMENSION_DIFF
;
514 if (tems
.ts_p_dimension
.width
!= tp
->width
||
515 tems
.ts_p_dimension
.height
!= tp
->height
)
516 result
|= TEMS_DIMENSION_DIFF
;
523 tems_setup_terminal(struct vis_devinit
*tp
, size_t height
, size_t width
)
526 int old_blank_buf_size
= tems
.ts_c_dimension
.width
;
528 ASSERT(MUTEX_HELD(&tems
.ts_lock
));
530 tems
.ts_pdepth
= tp
->depth
;
531 tems
.ts_linebytes
= tp
->linebytes
;
532 tems
.ts_display_mode
= tp
->mode
;
536 tems
.ts_p_dimension
.width
= 0;
537 tems
.ts_p_dimension
.height
= 0;
538 tems
.ts_c_dimension
.width
= tp
->width
;
539 tems
.ts_c_dimension
.height
= tp
->height
;
540 tems
.ts_callbacks
= &tem_safe_text_callbacks
;
546 * First check to see if the user has specified a screen size.
547 * If so, use those values. Else use 34x80 as the default.
550 width
= TEM_DEFAULT_COLS
;
551 height
= TEM_DEFAULT_ROWS
;
553 tems
.ts_c_dimension
.height
= (screen_size_t
)height
;
554 tems
.ts_c_dimension
.width
= (screen_size_t
)width
;
556 tems
.ts_p_dimension
.height
= tp
->height
;
557 tems
.ts_p_dimension
.width
= tp
->width
;
559 tems
.ts_callbacks
= &tem_safe_pix_callbacks
;
562 * set_font() will select a appropriate sized font for
563 * the number of rows and columns selected. If we don't
564 * have a font that will fit, then it will use the
565 * default builtin font and adjust the rows and columns
566 * to fit on the screen.
568 set_font(&tems
.ts_font
,
569 &tems
.ts_c_dimension
.height
,
570 &tems
.ts_c_dimension
.width
,
571 tems
.ts_p_dimension
.height
,
572 tems
.ts_p_dimension
.width
);
574 tems
.ts_p_offset
.y
= (tems
.ts_p_dimension
.height
-
575 (tems
.ts_c_dimension
.height
* tems
.ts_font
.height
)) / 2;
576 tems
.ts_p_offset
.x
= (tems
.ts_p_dimension
.width
-
577 (tems
.ts_c_dimension
.width
* tems
.ts_font
.width
)) / 2;
579 tems
.ts_pix_data_size
=
580 tems
.ts_font
.width
* tems
.ts_font
.height
;
582 tems
.ts_pix_data_size
*= 4;
584 tems
.ts_pdepth
= tp
->depth
;
589 /* Now virtual cls also uses the blank_line buffer */
590 if (tems
.ts_blank_line
)
591 kmem_free(tems
.ts_blank_line
, old_blank_buf_size
);
593 tems
.ts_blank_line
= (unsigned char *)
594 kmem_alloc(tems
.ts_c_dimension
.width
, KM_SLEEP
);
595 for (i
= 0; i
< tems
.ts_c_dimension
.width
; i
++)
596 tems
.ts_blank_line
[i
] = ' ';
600 * This is a callback function that we register with the frame
601 * buffer driver layered underneath. It gets invoked from
602 * the underlying frame buffer driver to reconfigure the terminal
603 * emulator to a new screen size and depth in conjunction with
604 * framebuffer videomode changes.
605 * Here we keep the foreground/background color and attributes,
606 * which may be different with the initial settings, so that
607 * the color won't change while the framebuffer videomode changes.
608 * And we also reset the kernel terminal emulator and clear the
613 tems_modechange_callback(struct vis_modechg_arg
*arg
,
614 struct vis_devinit
*devinit
)
617 struct tem_vt_state
*p
;
619 tem_modechg_cb_arg_t cb_arg
;
621 ASSERT(!(list_is_empty(&tems
.ts_list
)));
623 mutex_enter(&tems
.ts_lock
);
626 * currently only for pixel mode
628 diff
= tems_check_videomode(devinit
);
630 mutex_exit(&tems
.ts_lock
);
634 diff
= diff
& TEMS_DIMENSION_DIFF
;
638 * Only need to reinit the active tem.
640 struct tem_vt_state
*active
= tems
.ts_active
;
641 tems
.ts_pdepth
= devinit
->depth
;
643 mutex_enter(&active
->tvs_lock
);
644 ASSERT(active
->tvs_isactive
);
645 tem_reinit(active
, B_TRUE
);
646 mutex_exit(&active
->tvs_lock
);
648 mutex_exit(&tems
.ts_lock
);
652 tems_setup_terminal(devinit
, tems
.ts_c_dimension
.height
,
653 tems
.ts_c_dimension
.width
);
655 for (p
= list_head(&tems
.ts_list
); p
!= NULL
;
656 p
= list_next(&tems
.ts_list
, p
)) {
657 mutex_enter(&p
->tvs_lock
);
658 tem_reinit(p
, p
->tvs_isactive
);
659 mutex_exit(&p
->tvs_lock
);
663 if (tems
.ts_modechg_cb
== NULL
) {
664 mutex_exit(&tems
.ts_lock
);
668 cb
= tems
.ts_modechg_cb
;
669 cb_arg
= tems
.ts_modechg_arg
;
672 * Release the lock while doing callback.
674 mutex_exit(&tems
.ts_lock
);
679 * This function is used to display a rectangular blit of data
680 * of a given size and location via the underlying framebuffer driver.
681 * The blit can be as small as a pixel or as large as the screen.
684 tems_display_layered(
685 struct vis_consdisplay
*pda
,
690 (void) ldi_ioctl(tems
.ts_hdl
, VIS_CONSDISPLAY
,
691 (intptr_t)pda
, FKIOCTL
, credp
, &rval
);
695 * This function is used to invoke a block copy operation in the
696 * underlying framebuffer driver. Rectangle copies are how scrolling
697 * is implemented, as well as horizontal text shifting escape seqs.
698 * such as from vi when deleting characters and words.
702 struct vis_conscopy
*pma
,
707 (void) ldi_ioctl(tems
.ts_hdl
, VIS_CONSCOPY
,
708 (intptr_t)pma
, FKIOCTL
, credp
, &rval
);
712 * This function is used to show or hide a rectangluar monochrom
713 * pixel inverting, text block cursor via the underlying framebuffer.
717 struct vis_conscursor
*pca
,
722 (void) ldi_ioctl(tems
.ts_hdl
, VIS_CONSCURSOR
,
723 (intptr_t)pca
, FKIOCTL
, credp
, &rval
);
727 tem_kdsetmode(int mode
, cred_t
*credp
)
731 (void) ldi_ioctl(tems
.ts_hdl
, KDSETMODE
,
732 (intptr_t)mode
, FKIOCTL
, credp
, &rval
);
737 tems_reset_colormap(cred_t
*credp
, enum called_from called_from
)
742 if (called_from
== CALLED_FROM_STANDALONE
)
745 switch (tems
.ts_pdepth
) {
749 cm
.red
= cmap4_to_24
.red
; /* 8-bits (1/3 of TrueColor 24) */
750 cm
.blue
= cmap4_to_24
.blue
; /* 8-bits (1/3 of TrueColor 24) */
751 cm
.green
= cmap4_to_24
.green
; /* 8-bits (1/3 of TrueColor 24) */
752 (void) ldi_ioctl(tems
.ts_hdl
, VIS_PUTCMAP
, (intptr_t)&cm
,
753 FKIOCTL
, credp
, &rval
);
759 tem_get_size(ushort_t
*r
, ushort_t
*c
,
760 ushort_t
*x
, ushort_t
*y
)
762 mutex_enter(&tems
.ts_lock
);
763 *r
= (ushort_t
)tems
.ts_c_dimension
.height
;
764 *c
= (ushort_t
)tems
.ts_c_dimension
.width
;
765 *x
= (ushort_t
)tems
.ts_p_dimension
.width
;
766 *y
= (ushort_t
)tems
.ts_p_dimension
.height
;
767 mutex_exit(&tems
.ts_lock
);
771 tem_register_modechg_cb(tem_modechg_cb_t func
,
772 tem_modechg_cb_arg_t arg
)
774 mutex_enter(&tems
.ts_lock
);
776 tems
.ts_modechg_cb
= func
;
777 tems
.ts_modechg_arg
= arg
;
779 mutex_exit(&tems
.ts_lock
);
783 * This function is to scroll up the OBP output, which has
784 * different screen height and width with our kernel console.
787 tem_prom_scroll_up(struct tem_vt_state
*tem
, int nrows
, cred_t
*credp
,
788 enum called_from called_from
)
790 struct vis_conscopy ma
;
794 ma
.s_row
= nrows
* tems
.ts_font
.height
;
795 ma
.e_row
= tems
.ts_p_dimension
.height
- 1;
799 ma
.e_col
= tems
.ts_p_dimension
.width
- 1;
802 tems_safe_copy(&ma
, credp
, called_from
);
805 width
= tems
.ts_font
.width
;
806 ncols
= (tems
.ts_p_dimension
.width
+ (width
- 1))/ width
;
808 tem_safe_pix_cls_range(tem
, 0, nrows
, tems
.ts_p_offset
.y
,
809 0, ncols
, 0, B_TRUE
, credp
, called_from
);
812 #define PROM_DEFAULT_FONT_HEIGHT 22
813 #define PROM_DEFAULT_WINDOW_TOP 0x8a
816 * This function is to compute the starting row of the console, according to
817 * PROM cursor's position. Here we have to take different fonts into account.
820 tem_adjust_row(struct tem_vt_state
*tem
, int prom_row
, cred_t
*credp
,
821 enum called_from called_from
)
825 int prom_charheight
= 0;
826 int prom_window_top
= 0;
829 plat_tem_get_prom_font_size(&prom_charheight
, &prom_window_top
);
830 if (prom_charheight
== 0)
831 prom_charheight
= PROM_DEFAULT_FONT_HEIGHT
;
832 if (prom_window_top
== 0)
833 prom_window_top
= PROM_DEFAULT_WINDOW_TOP
;
835 tem_y
= (prom_row
+ 1) * prom_charheight
+ prom_window_top
-
837 tem_row
= (tem_y
+ tems
.ts_font
.height
- 1) /
838 tems
.ts_font
.height
- 1;
842 } else if (tem_row
>= (tems
.ts_c_dimension
.height
- 1)) {
844 * Scroll up the prom outputs if the PROM cursor's position is
845 * below our tem's lower boundary.
847 scroll_up_lines
= tem_row
-
848 (tems
.ts_c_dimension
.height
- 1);
849 tem_prom_scroll_up(tem
, scroll_up_lines
, credp
, called_from
);
850 tem_row
= tems
.ts_c_dimension
.height
- 1;
857 tem_pix_align(struct tem_vt_state
*tem
, cred_t
*credp
,
858 enum called_from called_from
)
863 if (plat_stdout_is_framebuffer()) {
864 plat_tem_hide_prom_cursor();
867 * We are getting the current cursor position in pixel
868 * mode so that we don't over-write the console output
871 plat_tem_get_prom_pos(&row
, &col
);
874 * Adjust the row if necessary when the font of our
875 * kernel console tem is different with that of prom
878 row
= tem_adjust_row(tem
, row
, credp
, called_from
);
880 /* first line of our kernel console output */
881 tem
->tvs_first_line
= row
+ 1;
883 /* re-set and align cusror position */
884 tem
->tvs_s_cursor
.row
= tem
->tvs_c_cursor
.row
=
886 tem
->tvs_s_cursor
.col
= tem
->tvs_c_cursor
.col
= 0;
888 tem_safe_reset_display(tem
, credp
, called_from
, B_TRUE
, B_TRUE
);
893 tems_get_inverses(boolean_t
*p_inverse
, boolean_t
*p_inverse_screen
)
896 int i_inverse_screen
= 0;
898 plat_tem_get_inverses(&i_inverse
, &i_inverse_screen
);
900 *p_inverse
= (i_inverse
== 0) ? B_FALSE
: B_TRUE
;
901 *p_inverse_screen
= (i_inverse_screen
== 0) ? B_FALSE
: B_TRUE
;
905 * Get the foreground/background color and attributes from the initial
906 * PROM, so that our kernel console can keep the same visual behaviour.
909 tems_get_initial_color(tem_color_t
*pcolor
)
911 boolean_t inverse
, inverse_screen
;
912 unsigned short flags
= 0;
914 pcolor
->fg_color
= DEFAULT_ANSI_FOREGROUND
;
915 pcolor
->bg_color
= DEFAULT_ANSI_BACKGROUND
;
917 if (plat_stdout_is_framebuffer()) {
918 tems_get_inverses(&inverse
, &inverse_screen
);
920 flags
|= TEM_ATTR_REVERSE
;
922 flags
|= TEM_ATTR_SCREEN_REVERSE
;
924 flags
|= TEM_ATTR_BOLD
;
927 pcolor
->a_flags
= flags
;
931 tem_get_fbmode(tem_vt_state_t tem_arg
)
933 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
937 mutex_enter(&tem
->tvs_lock
);
938 fbmode
= tem
->tvs_fbmode
;
939 mutex_exit(&tem
->tvs_lock
);
945 tem_set_fbmode(tem_vt_state_t tem_arg
, uchar_t fbmode
, cred_t
*credp
)
947 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
949 mutex_enter(&tems
.ts_lock
);
950 mutex_enter(&tem
->tvs_lock
);
952 if (fbmode
== tem
->tvs_fbmode
) {
953 mutex_exit(&tem
->tvs_lock
);
954 mutex_exit(&tems
.ts_lock
);
958 tem
->tvs_fbmode
= fbmode
;
960 if (tem
->tvs_isactive
) {
961 tem_kdsetmode(tem
->tvs_fbmode
, credp
);
962 if (fbmode
== KD_TEXT
)
963 tem_safe_unblank_screen(tem
, credp
, CALLED_FROM_NORMAL
);
966 mutex_exit(&tem
->tvs_lock
);
967 mutex_exit(&tems
.ts_lock
);
971 tem_activate(tem_vt_state_t tem_arg
, boolean_t unblank
, cred_t
*credp
)
973 struct tem_vt_state
*tem
= (struct tem_vt_state
*)tem_arg
;
975 mutex_enter(&tems
.ts_lock
);
976 tems
.ts_active
= tem
;
978 mutex_enter(&tem
->tvs_lock
);
979 tem
->tvs_isactive
= B_TRUE
;
981 tem_kdsetmode(tem
->tvs_fbmode
, credp
);
984 tem_safe_unblank_screen(tem
, credp
, CALLED_FROM_NORMAL
);
986 mutex_exit(&tem
->tvs_lock
);
987 mutex_exit(&tems
.ts_lock
);
991 tem_switch(tem_vt_state_t tem_arg1
, tem_vt_state_t tem_arg2
, cred_t
*credp
)
993 struct tem_vt_state
*cur
= (struct tem_vt_state
*)tem_arg1
;
994 struct tem_vt_state
*tobe
= (struct tem_vt_state
*)tem_arg2
;
996 mutex_enter(&tems
.ts_lock
);
997 mutex_enter(&tobe
->tvs_lock
);
998 mutex_enter(&cur
->tvs_lock
);
1000 tems
.ts_active
= tobe
;
1001 cur
->tvs_isactive
= B_FALSE
;
1002 tobe
->tvs_isactive
= B_TRUE
;
1004 mutex_exit(&cur
->tvs_lock
);
1006 if (cur
->tvs_fbmode
!= tobe
->tvs_fbmode
)
1007 tem_kdsetmode(tobe
->tvs_fbmode
, credp
);
1009 if (tobe
->tvs_fbmode
== KD_TEXT
)
1010 tem_safe_unblank_screen(tobe
, credp
, CALLED_FROM_NORMAL
);
1012 mutex_exit(&tobe
->tvs_lock
);
1013 mutex_exit(&tems
.ts_lock
);