Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / tem_safe.c
blob60ff789fb3e276e8b3a602ba4f5cc33a065f1f9c
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2016 Joyent, Inc.
32 * Polled I/O safe ANSI terminal emulator module;
33 * Supporting TERM types 'sun' and 'sun-color, parsing
34 * ANSI x3.64 escape sequences, and the like. (See wscons(7d)
35 * for more information).
37 * IMPORTANT:
39 * The functions in this file *must* be able to function in
40 * standalone mode, ie. on a quiesced system. In that state,
41 * access is single threaded, only one CPU is running.
42 * System services are NOT available.
44 * The following restrictions pertain to every function
45 * in this file:
47 * - CANNOT use the DDI or LDI interfaces
48 * - CANNOT call system services
49 * - CANNOT use mutexes
50 * - CANNOT wait for interrupts
51 * - CANNOT allocate memory
53 * All non-static functions in this file which:
54 * - Operates on tems and tem_vt_state
55 * - Not only called from standalone mode, i.e. has
56 * a "calledfrom" argument
57 * should assert this at the beginning:
59 * ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
60 * called_from == CALLED_FROM_STANDALONE);
63 #include <sys/types.h>
64 #include <sys/ascii.h>
65 #include <sys/visual_io.h>
66 #include <sys/font.h>
67 #include <sys/tem.h>
68 #include <sys/tem_impl.h>
69 #include <sys/ksynch.h>
70 #include <sys/sysmacros.h>
71 #include <sys/mutex.h>
72 #include <sys/note.h>
73 #include <sys/t_lock.h>
75 tem_safe_callbacks_t tem_safe_text_callbacks = {
76 &tem_safe_text_display,
77 &tem_safe_text_copy,
78 &tem_safe_text_cursor,
79 NULL,
80 &tem_safe_text_cls
82 tem_safe_callbacks_t tem_safe_pix_callbacks = {
83 &tem_safe_pix_display,
84 &tem_safe_pix_copy,
85 &tem_safe_pix_cursor,
86 &tem_safe_pix_bit2pix,
87 &tem_safe_pix_cls
91 static void tem_safe_control(struct tem_vt_state *, uchar_t,
92 cred_t *, enum called_from);
93 static void tem_safe_setparam(struct tem_vt_state *, int, int);
94 static void tem_safe_selgraph(struct tem_vt_state *);
95 static void tem_safe_chkparam(struct tem_vt_state *, uchar_t,
96 cred_t *, enum called_from);
97 static void tem_safe_getparams(struct tem_vt_state *, uchar_t,
98 cred_t *, enum called_from);
99 static void tem_safe_outch(struct tem_vt_state *, uchar_t,
100 cred_t *, enum called_from);
101 static void tem_safe_parse(struct tem_vt_state *, uchar_t,
102 cred_t *, enum called_from);
104 static void tem_safe_new_line(struct tem_vt_state *,
105 cred_t *, enum called_from);
106 static void tem_safe_cr(struct tem_vt_state *);
107 static void tem_safe_lf(struct tem_vt_state *,
108 cred_t *, enum called_from);
109 static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
110 enum called_from);
111 static void tem_safe_cls(struct tem_vt_state *,
112 cred_t *, enum called_from);
113 static void tem_safe_tab(struct tem_vt_state *,
114 cred_t *, enum called_from);
115 static void tem_safe_back_tab(struct tem_vt_state *,
116 cred_t *, enum called_from);
117 static void tem_safe_clear_tabs(struct tem_vt_state *, int);
118 static void tem_safe_set_tab(struct tem_vt_state *);
119 static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
120 cred_t *, enum called_from);
121 static void tem_safe_shift(struct tem_vt_state *, int, int,
122 cred_t *, enum called_from);
123 static void tem_safe_scroll(struct tem_vt_state *, int, int,
124 int, int, cred_t *, enum called_from);
125 static void tem_safe_clear_chars(struct tem_vt_state *tem,
126 int count, screen_pos_t row, screen_pos_t col,
127 cred_t *credp, enum called_from called_from);
128 static void tem_safe_copy_area(struct tem_vt_state *tem,
129 screen_pos_t s_col, screen_pos_t s_row,
130 screen_pos_t e_col, screen_pos_t e_row,
131 screen_pos_t t_col, screen_pos_t t_row,
132 cred_t *credp, enum called_from called_from);
133 static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
134 int, int, screen_pos_t, screen_pos_t,
135 cred_t *, enum called_from);
136 static void tem_safe_bell(struct tem_vt_state *tem,
137 enum called_from called_from);
138 static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
139 cred_t *credp, enum called_from called_from);
141 static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
142 screen_pos_t);
143 static void tem_safe_virtual_display(struct tem_vt_state *,
144 unsigned char *, int, screen_pos_t, screen_pos_t,
145 text_color_t, text_color_t);
146 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
147 screen_pos_t, screen_pos_t, screen_pos_t,
148 screen_pos_t, screen_pos_t);
149 static void tem_safe_align_cursor(struct tem_vt_state *tem);
150 static void bit_to_pix4(struct tem_vt_state *tem, uchar_t c,
151 text_color_t fg_color, text_color_t bg_color);
152 static void bit_to_pix8(struct tem_vt_state *tem, uchar_t c,
153 text_color_t fg_color, text_color_t bg_color);
154 static void bit_to_pix24(struct tem_vt_state *tem, uchar_t c,
155 text_color_t fg_color, text_color_t bg_color);
156 static void bit_to_pix32(struct tem_vt_state *tem, uchar_t c,
157 text_color_t fg_color, text_color_t bg_color);
159 /* BEGIN CSTYLED */
160 /* Bk Rd Gr Br Bl Mg Cy Wh */
161 static text_color_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
162 static text_color_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
163 /* END CSTYLED */
166 text_cmap_t cmap4_to_24 = {
167 /* BEGIN CSTYLED */
168 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
169 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
170 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
171 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
172 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
173 /* END CSTYLED */
176 #define PIX4TO32(pix4) (uint32_t)( \
177 cmap4_to_24.red[pix4] << 16 | \
178 cmap4_to_24.green[pix4] << 8 | \
179 cmap4_to_24.blue[pix4])
181 #define INVERSE(ch) (ch ^ 0xff)
183 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
184 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
185 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
186 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
187 #define tem_safe_callback_bit2pix(tem, c, fg, bg) { \
188 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
189 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c), (fg), (bg));\
192 void
193 tem_safe_check_first_time(
194 struct tem_vt_state *tem,
195 cred_t *credp,
196 enum called_from called_from)
198 static int first_time = 1;
200 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
201 called_from == CALLED_FROM_STANDALONE);
204 * Realign the console cursor. We did this in tem_init().
205 * However, drivers in the console stream may emit additional
206 * messages before we are ready. This causes text overwrite
207 * on the screen. This is a workaround.
209 if (!first_time)
210 return;
212 first_time = 0;
213 if (tems.ts_display_mode == VIS_TEXT) {
214 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
215 tem_safe_align_cursor(tem);
220 * This entry point handles output requests from restricted contexts like
221 * kmdb, where services like mutexes are not available. This function
222 * is entered when OBP or when a kernel debugger (such as kmdb)
223 * are generating console output. In those cases, power management
224 * concerns are handled by the abort sequence initiation (ie. when
225 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
226 * It is also entered when the kernel is panicing.
228 void
229 tem_safe_polled_write(
230 tem_vt_state_t tem_arg,
231 uchar_t *buf,
232 int len)
234 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
236 #ifdef __lock_lint
237 _NOTE(NO_COMPETING_THREADS_NOW)
238 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
239 #endif
241 if (!tem->tvs_initialized) {
242 return;
245 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
246 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
249 /* Process partial UTF-8 sequence. */
250 static void
251 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
252 enum called_from called_from)
254 int i;
255 uint8_t c;
257 if (tem->tvs_utf8_left == 0)
258 return;
260 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
261 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
262 if (c != 0) {
263 tem_safe_parse(tem, c, credp, called_from);
266 tem->tvs_utf8_left = 0;
267 tem->tvs_utf8_partial = 0;
271 * Handle UTF-8 sequences.
273 static void
274 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
275 enum called_from called_from)
278 * Check for UTF-8 code points. In case of error fall back to
279 * 8-bit code. As we only have 8859-1 fonts for console, this will set
280 * the limits on what chars we actually can display, therefore we
281 * have to return to this code once we have solved the font issue.
283 if ((c & 0x80) == 0x00) {
284 /* One-byte sequence. */
285 tem_safe_input_partial(tem, credp, called_from);
286 tem_safe_parse(tem, c, credp, called_from);
287 return;
289 if ((c & 0xe0) == 0xc0) {
290 /* Two-byte sequence. */
291 tem_safe_input_partial(tem, credp, called_from);
292 tem->tvs_utf8_left = 1;
293 tem->tvs_utf8_partial = c;
294 return;
296 if ((c & 0xf0) == 0xe0) {
297 /* Three-byte sequence. */
298 tem_safe_input_partial(tem, credp, called_from);
299 tem->tvs_utf8_left = 2;
300 tem->tvs_utf8_partial = c;
301 return;
303 if ((c & 0xf8) == 0xf0) {
304 /* Four-byte sequence. */
305 tem_safe_input_partial(tem, credp, called_from);
306 tem->tvs_utf8_left = 3;
307 tem->tvs_utf8_partial = c;
308 return;
310 if ((c & 0xc0) == 0x80) {
311 /* Invalid state? */
312 if (tem->tvs_utf8_left == 0) {
313 tem_safe_parse(tem, c, credp, called_from);
314 return;
316 tem->tvs_utf8_left--;
317 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
318 if (tem->tvs_utf8_left == 0) {
319 tem_char_t v, u;
320 uint8_t b;
323 * Transform the sequence of 2 to 4 bytes to
324 * unicode number.
326 v = 0;
327 u = tem->tvs_utf8_partial;
328 b = (u >> 24) & 0xff;
329 if (b != 0) { /* Four-byte sequence */
330 v = b & 0x07;
331 b = (u >> 16) & 0xff;
332 v = (v << 6) | (b & 0x3f);
333 b = (u >> 8) & 0xff;
334 v = (v << 6) | (b & 0x3f);
335 b = u & 0xff;
336 v = (v << 6) | (b & 0x3f);
337 } else if ((b = (u >> 16) & 0xff) != 0) {
338 v = b & 0x0f; /* Three-byte sequence */
339 b = (u >> 8) & 0xff;
340 v = (v << 6) | (b & 0x3f);
341 b = u & 0xff;
342 v = (v << 6) | (b & 0x3f);
343 } else if ((b = (u >> 8) & 0xff) != 0) {
344 v = b & 0x1f; /* Two-byte sequence */
345 b = u & 0xff;
346 v = (v << 6) | (b & 0x3f);
349 /* Use '?' as replacement if needed. */
350 if (v > 0xff)
351 v = '?';
352 tem_safe_parse(tem, v, credp, called_from);
353 tem->tvs_utf8_partial = 0;
355 return;
357 /* Anything left is illegal in UTF-8 sequence. */
358 tem_safe_input_partial(tem, credp, called_from);
359 tem_safe_parse(tem, c, credp, called_from);
363 * This is the main entry point into the terminal emulator.
365 * For each data message coming downstream, ANSI assumes that it is composed
366 * of ASCII characters, which are treated as a byte-stream input to the
367 * parsing state machine. All data is parsed immediately -- there is
368 * no enqueing.
370 void
371 tem_safe_terminal_emulate(
372 struct tem_vt_state *tem,
373 uchar_t *buf,
374 int len,
375 cred_t *credp,
376 enum called_from called_from)
379 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
380 called_from == CALLED_FROM_STANDALONE);
382 if (tem->tvs_isactive)
383 tem_safe_callback_cursor(tem,
384 VIS_HIDE_CURSOR, credp, called_from);
386 for (; len > 0; len--, buf++)
387 tem_safe_input_byte(tem, *buf, credp, called_from);
390 * Send the data we just got to the framebuffer.
392 tem_safe_send_data(tem, credp, called_from);
394 if (tem->tvs_isactive)
395 tem_safe_callback_cursor(tem,
396 VIS_DISPLAY_CURSOR, credp, called_from);
400 * Display an rectangular image on the frame buffer using the
401 * mechanism appropriate for the system state being called
402 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
404 static void
405 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
406 enum called_from called_from)
408 if (called_from == CALLED_FROM_STANDALONE)
409 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
410 else
411 tems_display_layered(pda, credp);
415 * Copy a rectangle from one location to another on the frame buffer
416 * using the mechanism appropriate for the system state being called
417 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
419 void
420 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
421 enum called_from called_from)
423 if (called_from == CALLED_FROM_STANDALONE)
424 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
425 else
426 tems_copy_layered(pca, credp);
430 * Display or hide a rectangular block text cursor of a specificsize
431 * at a specific location on frame buffer* using the mechanism
432 * appropriate for the system state being called from, quisced or
433 * normal (ie. use polled I/O vs. layered ioctls).
435 static void
436 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
437 enum called_from called_from)
439 if (called_from == CALLED_FROM_STANDALONE)
440 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
441 else
442 tems_cursor_layered(pca, credp);
446 * send the appropriate control message or set state based on the
447 * value of the control character ch
450 static void
451 tem_safe_control(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
452 enum called_from called_from)
454 tem->tvs_state = A_STATE_START;
455 switch (ch) {
456 case A_BEL:
457 tem_safe_bell(tem, called_from);
458 break;
460 case A_BS:
461 tem_safe_mv_cursor(tem,
462 tem->tvs_c_cursor.row,
463 tem->tvs_c_cursor.col - 1,
464 credp, called_from);
465 break;
467 case A_HT:
468 tem_safe_tab(tem, credp, called_from);
469 break;
471 case A_NL:
473 * tem_safe_send_data(tem, credp, called_from);
474 * tem_safe_new_line(tem, credp, called_from);
475 * break;
478 case A_VT:
479 tem_safe_send_data(tem, credp, called_from);
480 tem_safe_lf(tem, credp, called_from);
481 break;
483 case A_FF:
484 tem_safe_send_data(tem, credp, called_from);
485 tem_safe_cls(tem, credp, called_from);
486 break;
488 case A_CR:
489 tem_safe_send_data(tem, credp, called_from);
490 tem_safe_cr(tem);
491 break;
493 case A_ESC:
494 tem->tvs_state = A_STATE_ESC;
495 break;
497 case A_CSI:
499 int i;
500 tem->tvs_curparam = 0;
501 tem->tvs_paramval = 0;
502 tem->tvs_gotparam = B_FALSE;
503 /* clear the parameters */
504 for (i = 0; i < TEM_MAXPARAMS; i++)
505 tem->tvs_params[i] = -1;
506 tem->tvs_state = A_STATE_CSI;
508 break;
510 case A_GS:
511 tem_safe_back_tab(tem, credp, called_from);
512 break;
514 default:
515 break;
521 * if parameters [0..count - 1] are not set, set them to the value
522 * of newparam.
525 static void
526 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
528 int i;
530 for (i = 0; i < count; i++) {
531 if (tem->tvs_params[i] == -1)
532 tem->tvs_params[i] = newparam;
538 * select graphics mode based on the param vals stored in a_params
540 static void
541 tem_safe_selgraph(struct tem_vt_state *tem)
543 int curparam;
544 int count = 0;
545 int param;
547 tem->tvs_state = A_STATE_START;
549 curparam = tem->tvs_curparam;
550 do {
551 param = tem->tvs_params[count];
553 switch (param) {
554 case -1:
555 case 0:
556 /* reset to initial normal settings */
557 tem->tvs_fg_color = tems.ts_init_color.fg_color;
558 tem->tvs_bg_color = tems.ts_init_color.bg_color;
559 tem->tvs_flags = tems.ts_init_color.a_flags;
560 break;
562 case 1: /* Bold Intense */
563 tem->tvs_flags |= TEM_ATTR_BOLD;
564 break;
566 case 2: /* Faint Intense */
567 tem->tvs_flags &= ~TEM_ATTR_BOLD;
568 break;
570 case 5: /* Blink */
571 tem->tvs_flags |= TEM_ATTR_BLINK;
572 break;
574 case 7: /* Reverse video */
575 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
576 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
577 } else {
578 tem->tvs_flags |= TEM_ATTR_REVERSE;
580 break;
582 case 30: /* black (grey) foreground */
583 case 31: /* red (light red) foreground */
584 case 32: /* green (light green) foreground */
585 case 33: /* brown (yellow) foreground */
586 case 34: /* blue (light blue) foreground */
587 case 35: /* magenta (light magenta) foreground */
588 case 36: /* cyan (light cyan) foreground */
589 case 37: /* white (bright white) foreground */
590 tem->tvs_fg_color = param - 30;
591 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
592 break;
594 case 39:
596 * Reset the foreground colour and brightness.
598 tem->tvs_fg_color = tems.ts_init_color.fg_color;
599 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
600 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
601 else
602 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
603 break;
605 case 40: /* black (grey) background */
606 case 41: /* red (light red) background */
607 case 42: /* green (light green) background */
608 case 43: /* brown (yellow) background */
609 case 44: /* blue (light blue) background */
610 case 45: /* magenta (light magenta) background */
611 case 46: /* cyan (light cyan) background */
612 case 47: /* white (bright white) background */
613 tem->tvs_bg_color = param - 40;
614 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
615 break;
617 case 49:
619 * Reset the background colour and brightness.
621 tem->tvs_bg_color = tems.ts_init_color.bg_color;
622 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
623 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
624 else
625 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
626 break;
628 case 90: /* black (grey) foreground */
629 case 91: /* red (light red) foreground */
630 case 92: /* green (light green) foreground */
631 case 93: /* brown (yellow) foreground */
632 case 94: /* blue (light blue) foreground */
633 case 95: /* magenta (light magenta) foreground */
634 case 96: /* cyan (light cyan) foreground */
635 case 97: /* white (bright white) foreground */
636 tem->tvs_fg_color = param - 90;
637 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
638 break;
640 case 100: /* black (grey) background */
641 case 101: /* red (light red) background */
642 case 102: /* green (light green) background */
643 case 103: /* brown (yellow) background */
644 case 104: /* blue (light blue) background */
645 case 105: /* magenta (light magenta) background */
646 case 106: /* cyan (light cyan) background */
647 case 107: /* white (bright white) background */
648 tem->tvs_bg_color = param - 100;
649 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
650 break;
652 default:
653 break;
655 count++;
656 curparam--;
658 } while (curparam > 0);
662 * perform the appropriate action for the escape sequence
664 * General rule: This code does not validate the arguments passed.
665 * It assumes that the next lower level will do so.
667 static void
668 tem_safe_chkparam(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
669 enum called_from called_from)
671 int i;
672 int row;
673 int col;
675 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
676 MUTEX_HELD(&tem->tvs_lock));
678 row = tem->tvs_c_cursor.row;
679 col = tem->tvs_c_cursor.col;
681 switch (ch) {
683 case 'm': /* select terminal graphics mode */
684 tem_safe_send_data(tem, credp, called_from);
685 tem_safe_selgraph(tem);
686 break;
688 case '@': /* insert char */
689 tem_safe_setparam(tem, 1, 1);
690 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
691 credp, called_from);
692 break;
694 case 'A': /* cursor up */
695 tem_safe_setparam(tem, 1, 1);
696 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
697 credp, called_from);
698 break;
700 case 'd': /* VPA - vertical position absolute */
701 tem_safe_setparam(tem, 1, 1);
702 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
703 credp, called_from);
704 break;
706 case 'e': /* VPR - vertical position relative */
707 case 'B': /* cursor down */
708 tem_safe_setparam(tem, 1, 1);
709 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
710 credp, called_from);
711 break;
713 case 'a': /* HPR - horizontal position relative */
714 case 'C': /* cursor right */
715 tem_safe_setparam(tem, 1, 1);
716 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
717 credp, called_from);
718 break;
720 case '`': /* HPA - horizontal position absolute */
721 tem_safe_setparam(tem, 1, 1);
722 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
723 credp, called_from);
724 break;
726 case 'D': /* cursor left */
727 tem_safe_setparam(tem, 1, 1);
728 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
729 credp, called_from);
730 break;
732 case 'E': /* CNL cursor next line */
733 tem_safe_setparam(tem, 1, 1);
734 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
735 credp, called_from);
736 break;
738 case 'F': /* CPL cursor previous line */
739 tem_safe_setparam(tem, 1, 1);
740 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
741 credp, called_from);
742 break;
744 case 'G': /* cursor horizontal position */
745 tem_safe_setparam(tem, 1, 1);
746 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
747 credp, called_from);
748 break;
750 case 'g': /* clear tabs */
751 tem_safe_setparam(tem, 1, 0);
752 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
753 break;
755 case 'f': /* HVP Horizontal and Vertical Position */
756 case 'H': /* CUP position cursor */
757 tem_safe_setparam(tem, 2, 1);
758 tem_safe_mv_cursor(tem,
759 tem->tvs_params[0] - 1,
760 tem->tvs_params[1] - 1,
761 credp, called_from);
762 break;
764 case 'I': /* CHT - Cursor Horizontal Tab */
765 /* Not implemented */
766 break;
768 case 'J': /* ED - Erase in Display */
769 tem_safe_send_data(tem, credp, called_from);
770 tem_safe_setparam(tem, 1, 0);
771 switch (tem->tvs_params[0]) {
772 case 0:
773 /* erase cursor to end of screen */
774 /* FIRST erase cursor to end of line */
775 tem_safe_clear_chars(tem,
776 tems.ts_c_dimension.width -
777 tem->tvs_c_cursor.col,
778 tem->tvs_c_cursor.row,
779 tem->tvs_c_cursor.col, credp, called_from);
781 /* THEN erase lines below the cursor */
782 for (row = tem->tvs_c_cursor.row + 1;
783 row < tems.ts_c_dimension.height;
784 row++) {
785 tem_safe_clear_chars(tem,
786 tems.ts_c_dimension.width,
787 row, 0, credp, called_from);
789 break;
791 case 1:
792 /* erase beginning of screen to cursor */
793 /* FIRST erase lines above the cursor */
794 for (row = 0;
795 row < tem->tvs_c_cursor.row;
796 row++) {
797 tem_safe_clear_chars(tem,
798 tems.ts_c_dimension.width,
799 row, 0, credp, called_from);
801 /* THEN erase beginning of line to cursor */
802 tem_safe_clear_chars(tem,
803 tem->tvs_c_cursor.col + 1,
804 tem->tvs_c_cursor.row,
805 0, credp, called_from);
806 break;
808 case 2:
809 /* erase whole screen */
810 for (row = 0;
811 row < tems.ts_c_dimension.height;
812 row++) {
813 tem_safe_clear_chars(tem,
814 tems.ts_c_dimension.width,
815 row, 0, credp, called_from);
817 break;
819 break;
821 case 'K': /* EL - Erase in Line */
822 tem_safe_send_data(tem, credp, called_from);
823 tem_safe_setparam(tem, 1, 0);
824 switch (tem->tvs_params[0]) {
825 case 0:
826 /* erase cursor to end of line */
827 tem_safe_clear_chars(tem,
828 (tems.ts_c_dimension.width -
829 tem->tvs_c_cursor.col),
830 tem->tvs_c_cursor.row,
831 tem->tvs_c_cursor.col,
832 credp, called_from);
833 break;
835 case 1:
836 /* erase beginning of line to cursor */
837 tem_safe_clear_chars(tem,
838 tem->tvs_c_cursor.col + 1,
839 tem->tvs_c_cursor.row,
840 0, credp, called_from);
841 break;
843 case 2:
844 /* erase whole line */
845 tem_safe_clear_chars(tem,
846 tems.ts_c_dimension.width,
847 tem->tvs_c_cursor.row,
848 0, credp, called_from);
849 break;
851 break;
853 case 'L': /* insert line */
854 tem_safe_send_data(tem, credp, called_from);
855 tem_safe_setparam(tem, 1, 1);
856 tem_safe_scroll(tem,
857 tem->tvs_c_cursor.row,
858 tems.ts_c_dimension.height - 1,
859 tem->tvs_params[0], TEM_SCROLL_DOWN,
860 credp, called_from);
861 break;
863 case 'M': /* delete line */
864 tem_safe_send_data(tem, credp, called_from);
865 tem_safe_setparam(tem, 1, 1);
866 tem_safe_scroll(tem,
867 tem->tvs_c_cursor.row,
868 tems.ts_c_dimension.height - 1,
869 tem->tvs_params[0], TEM_SCROLL_UP,
870 credp, called_from);
871 break;
873 case 'P': /* DCH - delete char */
874 tem_safe_setparam(tem, 1, 1);
875 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
876 credp, called_from);
877 break;
879 case 'S': /* scroll up */
880 tem_safe_send_data(tem, credp, called_from);
881 tem_safe_setparam(tem, 1, 1);
882 tem_safe_scroll(tem, 0,
883 tems.ts_c_dimension.height - 1,
884 tem->tvs_params[0], TEM_SCROLL_UP,
885 credp, called_from);
886 break;
888 case 'T': /* scroll down */
889 tem_safe_send_data(tem, credp, called_from);
890 tem_safe_setparam(tem, 1, 1);
891 tem_safe_scroll(tem, 0,
892 tems.ts_c_dimension.height - 1,
893 tem->tvs_params[0], TEM_SCROLL_DOWN,
894 credp, called_from);
895 break;
897 case 'X': /* erase char */
898 tem_safe_setparam(tem, 1, 1);
899 tem_safe_clear_chars(tem,
900 tem->tvs_params[0],
901 tem->tvs_c_cursor.row,
902 tem->tvs_c_cursor.col,
903 credp, called_from);
904 break;
906 case 'Z': /* cursor backward tabulation */
907 tem_safe_setparam(tem, 1, 1);
910 * Rule exception - We do sanity checking here.
912 * Restrict the count to a sane value to keep from
913 * looping for a long time. There can't be more than one
914 * tab stop per column, so use that as a limit.
916 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
917 tem->tvs_params[0] = tems.ts_c_dimension.width;
919 for (i = 0; i < tem->tvs_params[0]; i++)
920 tem_safe_back_tab(tem, credp, called_from);
921 break;
923 tem->tvs_state = A_STATE_START;
928 * Gather the parameters of an ANSI escape sequence
930 static void
931 tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
932 cred_t *credp, enum called_from called_from)
934 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
935 MUTEX_HELD(&tem->tvs_lock));
937 if (ch >= '0' && ch <= '9') {
938 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
939 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
940 return; /* Return immediately */
941 } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
942 tem->tvs_state == A_STATE_CSI_QMARK) {
943 tem->tvs_state = A_STATE_START;
944 } else {
945 if (tem->tvs_curparam < TEM_MAXPARAMS) {
946 if (tem->tvs_gotparam) {
947 /* get the parameter value */
948 tem->tvs_params[tem->tvs_curparam] =
949 tem->tvs_paramval;
951 tem->tvs_curparam++;
954 if (ch == ';') {
955 /* Restart parameter search */
956 tem->tvs_gotparam = B_FALSE;
957 tem->tvs_paramval = 0; /* No parame value yet */
958 } else {
959 /* Handle escape sequence */
960 tem_safe_chkparam(tem, ch, credp, called_from);
966 * Add character to internal buffer.
967 * When its full, send it to the next layer.
970 static void
971 tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
972 cred_t *credp, enum called_from called_from)
975 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
976 called_from == CALLED_FROM_STANDALONE);
978 /* buffer up the character until later */
980 tem->tvs_outbuf[tem->tvs_outindex++] = ch;
981 tem->tvs_c_cursor.col++;
982 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
983 tem_safe_send_data(tem, credp, called_from);
984 tem_safe_new_line(tem, credp, called_from);
988 static void
989 tem_safe_new_line(struct tem_vt_state *tem,
990 cred_t *credp, enum called_from called_from)
992 tem_safe_cr(tem);
993 tem_safe_lf(tem, credp, called_from);
996 static void
997 tem_safe_cr(struct tem_vt_state *tem)
999 tem->tvs_c_cursor.col = 0;
1000 tem_safe_align_cursor(tem);
1003 static void
1004 tem_safe_lf(struct tem_vt_state *tem,
1005 cred_t *credp, enum called_from called_from)
1007 int row;
1009 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1010 MUTEX_HELD(&tem->tvs_lock));
1013 * Sanity checking notes:
1014 * . a_nscroll was validated when it was set.
1015 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
1016 * will prevent anything bad from happening.
1018 row = tem->tvs_c_cursor.row + 1;
1020 if (row >= tems.ts_c_dimension.height) {
1021 if (tem->tvs_nscroll != 0) {
1022 tem_safe_scroll(tem, 0,
1023 tems.ts_c_dimension.height - 1,
1024 tem->tvs_nscroll, TEM_SCROLL_UP,
1025 credp, called_from);
1026 row = tems.ts_c_dimension.height -
1027 tem->tvs_nscroll;
1028 } else { /* no scroll */
1030 * implement Esc[#r when # is zero. This means no
1031 * scroll but just return cursor to top of screen,
1032 * do not clear screen.
1034 row = 0;
1038 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
1039 credp, called_from);
1041 if (tem->tvs_nscroll == 0) {
1042 /* erase rest of cursor line */
1043 tem_safe_clear_chars(tem,
1044 tems.ts_c_dimension.width -
1045 tem->tvs_c_cursor.col,
1046 tem->tvs_c_cursor.row,
1047 tem->tvs_c_cursor.col,
1048 credp, called_from);
1052 tem_safe_align_cursor(tem);
1055 static void
1056 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1057 enum called_from called_from)
1059 text_color_t fg_color;
1060 text_color_t bg_color;
1062 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1063 MUTEX_HELD(&tem->tvs_lock));
1065 if (tem->tvs_outindex == 0) {
1066 tem_safe_align_cursor(tem);
1067 return;
1070 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_REVERSE);
1071 tem_safe_virtual_display(tem,
1072 tem->tvs_outbuf, tem->tvs_outindex,
1073 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1074 fg_color, bg_color);
1076 if (tem->tvs_isactive) {
1078 * Call the primitive to render this data.
1080 tem_safe_callback_display(tem,
1081 tem->tvs_outbuf, tem->tvs_outindex,
1082 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1083 fg_color, bg_color,
1084 credp, called_from);
1087 tem->tvs_outindex = 0;
1089 tem_safe_align_cursor(tem);
1094 * We have just done something to the current output point. Reset the start
1095 * point for the buffered data in a_outbuf. There shouldn't be any data
1096 * buffered yet.
1098 static void
1099 tem_safe_align_cursor(struct tem_vt_state *tem)
1101 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1102 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1106 * State machine parser based on the current state and character input
1107 * major terminations are to control character or normal character
1110 static void
1111 tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
1112 cred_t *credp, enum called_from called_from)
1114 int i;
1116 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1117 MUTEX_HELD(&tem->tvs_lock));
1119 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1120 if (ch == A_CSI || ch == A_ESC || ch < ' ') {
1121 /* Control */
1122 tem_safe_control(tem, ch, credp, called_from);
1123 } else {
1124 /* Display */
1125 tem_safe_outch(tem, ch, credp, called_from);
1127 return;
1130 /* In <ESC> sequence */
1131 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1132 if (tem->tvs_state != A_STATE_CSI) {
1133 tem_safe_getparams(tem, ch, credp, called_from);
1134 return;
1137 switch (ch) {
1138 case '?':
1139 tem->tvs_state = A_STATE_CSI_QMARK;
1140 return;
1141 case '=':
1142 tem->tvs_state = A_STATE_CSI_EQUAL;
1143 return;
1144 case 's':
1146 * As defined below, this sequence
1147 * saves the cursor. However, Sun
1148 * defines ESC[s as reset. We resolved
1149 * the conflict by selecting reset as it
1150 * is exported in the termcap file for
1151 * sun-mon, while the "save cursor"
1152 * definition does not exist anywhere in
1153 * /etc/termcap.
1154 * However, having no coherent
1155 * definition of reset, we have not
1156 * implemented it.
1160 * Original code
1161 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1162 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1163 * tem->tvs_state = A_STATE_START;
1166 tem->tvs_state = A_STATE_START;
1167 return;
1168 case 'u':
1169 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1170 tem->tvs_r_cursor.col, credp, called_from);
1171 tem->tvs_state = A_STATE_START;
1172 return;
1173 case 'p': /* sunbow */
1174 tem_safe_send_data(tem, credp, called_from);
1176 * Don't set anything if we are
1177 * already as we want to be.
1179 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1180 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1182 * If we have switched the characters to be the
1183 * inverse from the screen, then switch them as
1184 * well to keep them the inverse of the screen.
1186 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1187 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1188 else
1189 tem->tvs_flags |= TEM_ATTR_REVERSE;
1191 tem_safe_cls(tem, credp, called_from);
1192 tem->tvs_state = A_STATE_START;
1193 return;
1194 case 'q': /* sunwob */
1195 tem_safe_send_data(tem, credp, called_from);
1197 * Don't set anything if we are
1198 * already where as we want to be.
1200 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1201 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1203 * If we have switched the characters to be the
1204 * inverse from the screen, then switch them as
1205 * well to keep them the inverse of the screen.
1207 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1208 tem->tvs_flags |= TEM_ATTR_REVERSE;
1209 else
1210 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1213 tem_safe_cls(tem, credp, called_from);
1214 tem->tvs_state = A_STATE_START;
1215 return;
1216 case 'r': /* sunscrl */
1218 * Rule exception: check for validity here.
1220 tem->tvs_nscroll = tem->tvs_paramval;
1221 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
1222 tem->tvs_nscroll = tems.ts_c_dimension.height;
1223 if (tem->tvs_nscroll < 0)
1224 tem->tvs_nscroll = 1;
1225 tem->tvs_state = A_STATE_START;
1226 return;
1227 default:
1228 tem_safe_getparams(tem, ch, credp, called_from);
1229 return;
1233 /* Previous char was <ESC> */
1234 if (ch == '[') {
1235 tem->tvs_curparam = 0;
1236 tem->tvs_paramval = 0;
1237 tem->tvs_gotparam = B_FALSE;
1238 /* clear the parameters */
1239 for (i = 0; i < TEM_MAXPARAMS; i++)
1240 tem->tvs_params[i] = -1;
1241 tem->tvs_state = A_STATE_CSI;
1242 } else if (ch == 'Q') { /* <ESC>Q ? */
1243 tem->tvs_state = A_STATE_START;
1244 } else if (ch == 'C') { /* <ESC>C ? */
1245 tem->tvs_state = A_STATE_START;
1246 } else {
1247 tem->tvs_state = A_STATE_START;
1248 if (ch == 'c') {
1249 /* ESC c resets display */
1250 tem_safe_reset_display(tem, credp, called_from,
1251 B_TRUE, B_TRUE);
1252 } else if (ch == 'H') {
1253 /* ESC H sets a tab */
1254 tem_safe_set_tab(tem);
1255 } else if (ch == '7') {
1256 /* ESC 7 Save Cursor position */
1257 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1258 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1259 } else if (ch == '8') {
1260 /* ESC 8 Restore Cursor position */
1261 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1262 tem->tvs_r_cursor.col, credp, called_from);
1263 /* check for control chars */
1264 } else if (ch < ' ') {
1265 tem_safe_control(tem, ch, credp, called_from);
1266 } else {
1267 tem_safe_outch(tem, ch, credp, called_from);
1272 /* ARGSUSED */
1273 static void
1274 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1276 if (called_from == CALLED_FROM_STANDALONE)
1277 (void) beep_polled(BEEP_CONSOLE);
1278 else
1279 (void) beep(BEEP_CONSOLE);
1283 static void
1284 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1285 int direction, cred_t *credp, enum called_from called_from)
1287 int row;
1288 int lines_affected;
1290 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1291 called_from == CALLED_FROM_STANDALONE);
1293 lines_affected = end - start + 1;
1294 if (count > lines_affected)
1295 count = lines_affected;
1296 if (count <= 0)
1297 return;
1299 switch (direction) {
1300 case TEM_SCROLL_UP:
1301 if (count < lines_affected) {
1302 tem_safe_copy_area(tem, 0, start + count,
1303 tems.ts_c_dimension.width - 1, end,
1304 0, start, credp, called_from);
1306 for (row = (end - count) + 1; row <= end; row++) {
1307 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1308 row, 0, credp, called_from);
1310 break;
1312 case TEM_SCROLL_DOWN:
1313 if (count < lines_affected) {
1314 tem_safe_copy_area(tem, 0, start,
1315 tems.ts_c_dimension.width - 1,
1316 end - count, 0, start + count,
1317 credp, called_from);
1319 for (row = start; row < start + count; row++) {
1320 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1321 row, 0, credp, called_from);
1323 break;
1327 static void
1328 tem_safe_copy_area(struct tem_vt_state *tem,
1329 screen_pos_t s_col, screen_pos_t s_row,
1330 screen_pos_t e_col, screen_pos_t e_row,
1331 screen_pos_t t_col, screen_pos_t t_row,
1332 cred_t *credp, enum called_from called_from)
1334 int rows;
1335 int cols;
1337 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1338 called_from == CALLED_FROM_STANDALONE);
1340 if (s_col < 0 || s_row < 0 ||
1341 e_col < 0 || e_row < 0 ||
1342 t_col < 0 || t_row < 0 ||
1343 s_col >= tems.ts_c_dimension.width ||
1344 e_col >= tems.ts_c_dimension.width ||
1345 t_col >= tems.ts_c_dimension.width ||
1346 s_row >= tems.ts_c_dimension.height ||
1347 e_row >= tems.ts_c_dimension.height ||
1348 t_row >= tems.ts_c_dimension.height)
1349 return;
1351 if (s_row > e_row || s_col > e_col)
1352 return;
1354 rows = e_row - s_row + 1;
1355 cols = e_col - s_col + 1;
1356 if (t_row + rows > tems.ts_c_dimension.height ||
1357 t_col + cols > tems.ts_c_dimension.width)
1358 return;
1360 tem_safe_virtual_copy(tem,
1361 s_col, s_row,
1362 e_col, e_row,
1363 t_col, t_row);
1365 if (!tem->tvs_isactive)
1366 return;
1368 tem_safe_callback_copy(tem, s_col, s_row,
1369 e_col, e_row, t_col, t_row, credp, called_from);
1372 static void
1373 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1374 screen_pos_t col, cred_t *credp, enum called_from called_from)
1376 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1377 called_from == CALLED_FROM_STANDALONE);
1379 if (row < 0 || row >= tems.ts_c_dimension.height ||
1380 col < 0 || col >= tems.ts_c_dimension.width ||
1381 count < 0)
1382 return;
1385 * Note that very large values of "count" could cause col+count
1386 * to overflow, so we check "count" independently.
1388 if (count > tems.ts_c_dimension.width ||
1389 col + count > tems.ts_c_dimension.width)
1390 count = tems.ts_c_dimension.width - col;
1392 tem_safe_virtual_cls(tem, count, row, col);
1394 if (!tem->tvs_isactive)
1395 return;
1397 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1400 /*ARGSUSED*/
1401 void
1402 tem_safe_text_display(struct tem_vt_state *tem, uchar_t *string,
1403 int count, screen_pos_t row, screen_pos_t col,
1404 text_color_t fg_color, text_color_t bg_color,
1405 cred_t *credp, enum called_from called_from)
1407 struct vis_consdisplay da;
1409 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1410 called_from == CALLED_FROM_STANDALONE);
1412 da.data = string;
1413 da.width = (screen_size_t)count;
1414 da.row = row;
1415 da.col = col;
1417 da.fg_color = fg_color;
1418 da.bg_color = bg_color;
1420 tems_safe_display(&da, credp, called_from);
1424 * This function is used to blit a rectangular color image,
1425 * unperturbed on the underlying framebuffer, to render
1426 * icons and pictures. The data is a pixel pattern that
1427 * fills a rectangle bounded to the width and height parameters.
1428 * The color pixel data must to be pre-adjusted by the caller
1429 * for the current video depth.
1431 * This function is unused now.
1433 /*ARGSUSED*/
1434 static void
1435 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1436 int height, int width, screen_pos_t row, screen_pos_t col,
1437 cred_t *credp, enum called_from called_from)
1439 struct vis_consdisplay da;
1441 mutex_enter(&tems.ts_lock);
1442 mutex_enter(&tem->tvs_lock);
1444 da.data = image;
1445 da.width = (screen_size_t)width;
1446 da.height = (screen_size_t)height;
1447 da.row = row;
1448 da.col = col;
1450 tems_safe_display(&da, credp, called_from);
1452 mutex_exit(&tem->tvs_lock);
1453 mutex_exit(&tems.ts_lock);
1457 /*ARGSUSED*/
1458 void
1459 tem_safe_text_copy(struct tem_vt_state *tem,
1460 screen_pos_t s_col, screen_pos_t s_row,
1461 screen_pos_t e_col, screen_pos_t e_row,
1462 screen_pos_t t_col, screen_pos_t t_row,
1463 cred_t *credp, enum called_from called_from)
1465 struct vis_conscopy da;
1467 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1468 called_from == CALLED_FROM_STANDALONE);
1470 da.s_row = s_row;
1471 da.s_col = s_col;
1472 da.e_row = e_row;
1473 da.e_col = e_col;
1474 da.t_row = t_row;
1475 da.t_col = t_col;
1477 tems_safe_copy(&da, credp, called_from);
1480 void
1481 tem_safe_text_cls(struct tem_vt_state *tem,
1482 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1483 enum called_from called_from)
1485 struct vis_consdisplay da;
1487 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1488 called_from == CALLED_FROM_STANDALONE);
1490 da.data = tems.ts_blank_line;
1491 da.width = (screen_size_t)count;
1492 da.row = row;
1493 da.col = col;
1495 tem_safe_get_color(tem, &da.fg_color, &da.bg_color,
1496 TEM_ATTR_SCREEN_REVERSE);
1497 tems_safe_display(&da, credp, called_from);
1500 void
1501 tem_safe_pix_display(struct tem_vt_state *tem,
1502 uchar_t *string, int count,
1503 screen_pos_t row, screen_pos_t col,
1504 text_color_t fg_color, text_color_t bg_color,
1505 cred_t *credp, enum called_from called_from)
1507 struct vis_consdisplay da;
1508 int i;
1510 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1511 called_from == CALLED_FROM_STANDALONE);
1513 da.data = (uchar_t *)tem->tvs_pix_data;
1514 da.width = tems.ts_font.width;
1515 da.height = tems.ts_font.height;
1516 da.row = (row * da.height) + tems.ts_p_offset.y;
1517 da.col = (col * da.width) + tems.ts_p_offset.x;
1519 for (i = 0; i < count; i++) {
1520 tem_safe_callback_bit2pix(tem, string[i], fg_color, bg_color);
1521 tems_safe_display(&da, credp, called_from);
1522 da.col += da.width;
1526 void
1527 tem_safe_pix_copy(struct tem_vt_state *tem,
1528 screen_pos_t s_col, screen_pos_t s_row,
1529 screen_pos_t e_col, screen_pos_t e_row,
1530 screen_pos_t t_col, screen_pos_t t_row,
1531 cred_t *credp,
1532 enum called_from called_from)
1534 struct vis_conscopy ma;
1535 static boolean_t need_clear = B_TRUE;
1537 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1538 called_from == CALLED_FROM_STANDALONE);
1540 if (need_clear && tem->tvs_first_line > 0) {
1542 * Clear OBP output above our kernel console term
1543 * when our kernel console term begins to scroll up,
1544 * we hope it is user friendly.
1545 * (Also see comments on tem_safe_pix_clear_prom_output)
1547 * This is only one time call.
1549 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1551 need_clear = B_FALSE;
1553 ma.s_row = s_row * tems.ts_font.height + tems.ts_p_offset.y;
1554 ma.e_row = (e_row + 1) * tems.ts_font.height + tems.ts_p_offset.y - 1;
1555 ma.t_row = t_row * tems.ts_font.height + tems.ts_p_offset.y;
1558 * Check if we're in process of clearing OBP's columns area,
1559 * which only happens when term scrolls up a whole line.
1561 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1562 e_col == tems.ts_c_dimension.width - 1) {
1564 * We need to clear OBP's columns area outside our kernel
1565 * console term. So that we set ma.e_col to entire row here.
1567 ma.s_col = s_col * tems.ts_font.width;
1568 ma.e_col = tems.ts_p_dimension.width - 1;
1570 ma.t_col = t_col * tems.ts_font.width;
1571 } else {
1572 ma.s_col = s_col * tems.ts_font.width + tems.ts_p_offset.x;
1573 ma.e_col = (e_col + 1) * tems.ts_font.width +
1574 tems.ts_p_offset.x - 1;
1575 ma.t_col = t_col * tems.ts_font.width + tems.ts_p_offset.x;
1578 tems_safe_copy(&ma, credp, called_from);
1580 if (tem->tvs_first_line > 0 && t_row < s_row) {
1581 /* We have scrolled up (s_row - t_row) rows. */
1582 tem->tvs_first_line -= (s_row - t_row);
1583 if (tem->tvs_first_line <= 0) {
1584 /* All OBP rows have been cleared. */
1585 tem->tvs_first_line = 0;
1591 void
1592 tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
1593 unsigned char fg, unsigned char bg)
1595 void (*fp)(struct tem_vt_state *, unsigned char,
1596 unsigned char, unsigned char);
1598 switch (tems.ts_pdepth) {
1599 case 4:
1600 fp = bit_to_pix4;
1601 break;
1602 case 8:
1603 fp = bit_to_pix8;
1604 break;
1605 case 24:
1606 fp = bit_to_pix24;
1607 break;
1608 case 32:
1609 fp = bit_to_pix32;
1610 break;
1611 default:
1612 return;
1615 fp(tem, c, fg, bg);
1620 * This function only clears count of columns in one row
1622 void
1623 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
1624 screen_pos_t row, screen_pos_t col, cred_t *credp,
1625 enum called_from called_from)
1627 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1628 called_from == CALLED_FROM_STANDALONE);
1630 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
1631 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
1635 * This function clears OBP output above our kernel console term area
1636 * because OBP's term may have a bigger terminal window than that of
1637 * our kernel console term. So we need to clear OBP output garbage outside
1638 * of our kernel console term at a proper time, which is when the first
1639 * row output of our kernel console term scrolls at the first screen line.
1641 * _________________________________
1642 * | _____________________ | ---> OBP's bigger term window
1643 * | | | |
1644 * |___| | |
1645 * | | | | |
1646 * | | | | |
1647 * |_|_|___________________|_______|
1648 * | | | ---> first line
1649 * | |___________________|---> our kernel console term window
1651 * |---> columns area to be cleared
1653 * This function only takes care of the output above our kernel console term,
1654 * and tem_prom_scroll_up takes care of columns area outside of our kernel
1655 * console term.
1657 static void
1658 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1659 enum called_from called_from)
1661 int nrows, ncols, width, height;
1663 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1664 called_from == CALLED_FROM_STANDALONE);
1666 width = tems.ts_font.width;
1667 height = tems.ts_font.height;
1669 nrows = (tems.ts_p_offset.y + (height - 1))/ height;
1670 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1672 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1673 B_FALSE, credp, called_from);
1677 * clear the whole screen for pixel mode, just clear the
1678 * physical screen.
1680 void
1681 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1682 enum called_from called_from)
1684 int nrows, ncols, width, height;
1686 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1687 called_from == CALLED_FROM_STANDALONE);
1689 width = tems.ts_font.width;
1690 height = tems.ts_font.height;
1692 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1693 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1695 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1696 B_FALSE, credp, called_from);
1699 * Since the whole screen is cleared, we don't need
1700 * to clear OBP output later.
1702 if (tem->tvs_first_line > 0)
1703 tem->tvs_first_line = 0;
1707 * clear the whole screen, including the virtual screen buffer,
1708 * and reset the cursor to start point.
1710 static void
1711 tem_safe_cls(struct tem_vt_state *tem,
1712 cred_t *credp, enum called_from called_from)
1714 int row;
1716 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1717 called_from == CALLED_FROM_STANDALONE);
1719 if (tems.ts_display_mode == VIS_TEXT) {
1720 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1721 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1722 row, 0, credp, called_from);
1724 tem->tvs_c_cursor.row = 0;
1725 tem->tvs_c_cursor.col = 0;
1726 tem_safe_align_cursor(tem);
1727 return;
1730 ASSERT(tems.ts_display_mode == VIS_PIXEL);
1732 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1733 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
1735 tem->tvs_c_cursor.row = 0;
1736 tem->tvs_c_cursor.col = 0;
1737 tem_safe_align_cursor(tem);
1739 if (!tem->tvs_isactive)
1740 return;
1742 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
1745 static void
1746 tem_safe_back_tab(struct tem_vt_state *tem,
1747 cred_t *credp, enum called_from called_from)
1749 int i;
1750 screen_pos_t tabstop;
1752 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1753 called_from == CALLED_FROM_STANDALONE);
1755 tabstop = 0;
1757 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
1758 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
1759 tabstop = tem->tvs_tabs[i];
1760 break;
1764 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1765 tabstop, credp, called_from);
1768 static void
1769 tem_safe_tab(struct tem_vt_state *tem,
1770 cred_t *credp, enum called_from called_from)
1772 int i;
1773 screen_pos_t tabstop;
1775 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1776 called_from == CALLED_FROM_STANDALONE);
1778 tabstop = tems.ts_c_dimension.width - 1;
1780 for (i = 0; i < tem->tvs_ntabs; i++) {
1781 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1782 tabstop = tem->tvs_tabs[i];
1783 break;
1787 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1788 tabstop, credp, called_from);
1791 static void
1792 tem_safe_set_tab(struct tem_vt_state *tem)
1794 int i;
1795 int j;
1797 if (tem->tvs_ntabs == TEM_MAXTAB)
1798 return;
1799 if (tem->tvs_ntabs == 0 ||
1800 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
1801 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
1802 return;
1804 for (i = 0; i < tem->tvs_ntabs; i++) {
1805 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
1806 return;
1807 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1808 for (j = tem->tvs_ntabs - 1; j >= i; j--)
1809 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
1810 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
1811 tem->tvs_ntabs++;
1812 return;
1817 static void
1818 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
1820 int i;
1821 int j;
1823 switch (action) {
1824 case 3: /* clear all tabs */
1825 tem->tvs_ntabs = 0;
1826 break;
1827 case 0: /* clr tab at cursor */
1829 for (i = 0; i < tem->tvs_ntabs; i++) {
1830 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
1831 tem->tvs_ntabs--;
1832 for (j = i; j < tem->tvs_ntabs; j++)
1833 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
1834 return;
1837 break;
1841 static void
1842 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
1843 cred_t *credp, enum called_from called_from)
1845 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1846 called_from == CALLED_FROM_STANDALONE);
1849 * Sanity check and bounds enforcement. Out of bounds requests are
1850 * clipped to the screen boundaries. This seems to be what SPARC
1851 * does.
1853 if (row < 0)
1854 row = 0;
1855 if (row >= tems.ts_c_dimension.height)
1856 row = tems.ts_c_dimension.height - 1;
1857 if (col < 0)
1858 col = 0;
1859 if (col >= tems.ts_c_dimension.width)
1860 col = tems.ts_c_dimension.width - 1;
1862 tem_safe_send_data(tem, credp, called_from);
1863 tem->tvs_c_cursor.row = (screen_pos_t)row;
1864 tem->tvs_c_cursor.col = (screen_pos_t)col;
1865 tem_safe_align_cursor(tem);
1868 /* ARGSUSED */
1869 void
1870 tem_safe_reset_emulator(struct tem_vt_state *tem,
1871 cred_t *credp, enum called_from called_from,
1872 boolean_t init_color)
1874 int j;
1876 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1877 called_from == CALLED_FROM_STANDALONE);
1879 tem->tvs_c_cursor.row = 0;
1880 tem->tvs_c_cursor.col = 0;
1881 tem->tvs_r_cursor.row = 0;
1882 tem->tvs_r_cursor.col = 0;
1883 tem->tvs_s_cursor.row = 0;
1884 tem->tvs_s_cursor.col = 0;
1885 tem->tvs_outindex = 0;
1886 tem->tvs_state = A_STATE_START;
1887 tem->tvs_gotparam = B_FALSE;
1888 tem->tvs_curparam = 0;
1889 tem->tvs_paramval = 0;
1890 tem->tvs_nscroll = 1;
1892 if (init_color) {
1893 /* use initial settings */
1894 tem->tvs_fg_color = tems.ts_init_color.fg_color;
1895 tem->tvs_bg_color = tems.ts_init_color.bg_color;
1896 tem->tvs_flags = tems.ts_init_color.a_flags;
1900 * set up the initial tab stops
1902 tem->tvs_ntabs = 0;
1903 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
1904 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
1906 for (j = 0; j < TEM_MAXPARAMS; j++)
1907 tem->tvs_params[j] = 0;
1910 void
1911 tem_safe_reset_display(struct tem_vt_state *tem,
1912 cred_t *credp, enum called_from called_from,
1913 boolean_t clear_txt, boolean_t init_color)
1915 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1916 called_from == CALLED_FROM_STANDALONE);
1918 tem_safe_reset_emulator(tem, credp, called_from, init_color);
1920 if (clear_txt) {
1921 if (tem->tvs_isactive)
1922 tem_safe_callback_cursor(tem,
1923 VIS_HIDE_CURSOR, credp, called_from);
1925 tem_safe_cls(tem, credp, called_from);
1927 if (tem->tvs_isactive)
1928 tem_safe_callback_cursor(tem,
1929 VIS_DISPLAY_CURSOR, credp, called_from);
1933 static void
1934 tem_safe_shift(
1935 struct tem_vt_state *tem,
1936 int count,
1937 int direction,
1938 cred_t *credp,
1939 enum called_from called_from)
1941 int rest_of_line;
1943 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1944 called_from == CALLED_FROM_STANDALONE);
1946 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
1947 if (count > rest_of_line)
1948 count = rest_of_line;
1950 if (count <= 0)
1951 return;
1953 switch (direction) {
1954 case TEM_SHIFT_LEFT:
1955 if (count < rest_of_line) {
1956 tem_safe_copy_area(tem,
1957 tem->tvs_c_cursor.col + count,
1958 tem->tvs_c_cursor.row,
1959 tems.ts_c_dimension.width - 1,
1960 tem->tvs_c_cursor.row,
1961 tem->tvs_c_cursor.col,
1962 tem->tvs_c_cursor.row,
1963 credp, called_from);
1966 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1967 (tems.ts_c_dimension.width - count), credp,
1968 called_from);
1969 break;
1970 case TEM_SHIFT_RIGHT:
1971 if (count < rest_of_line) {
1972 tem_safe_copy_area(tem,
1973 tem->tvs_c_cursor.col,
1974 tem->tvs_c_cursor.row,
1975 tems.ts_c_dimension.width - count - 1,
1976 tem->tvs_c_cursor.row,
1977 tem->tvs_c_cursor.col + count,
1978 tem->tvs_c_cursor.row,
1979 credp, called_from);
1982 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1983 tem->tvs_c_cursor.col, credp, called_from);
1984 break;
1988 void
1989 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
1990 cred_t *credp, enum called_from called_from)
1992 struct vis_conscursor ca;
1994 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1995 called_from == CALLED_FROM_STANDALONE);
1997 ca.row = tem->tvs_c_cursor.row;
1998 ca.col = tem->tvs_c_cursor.col;
1999 ca.action = action;
2001 tems_safe_cursor(&ca, credp, called_from);
2003 if (action == VIS_GET_CURSOR) {
2004 tem->tvs_c_cursor.row = ca.row;
2005 tem->tvs_c_cursor.col = ca.col;
2009 void
2010 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
2011 cred_t *credp, enum called_from called_from)
2013 struct vis_conscursor ca;
2015 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2016 called_from == CALLED_FROM_STANDALONE);
2018 ca.row = tem->tvs_c_cursor.row * tems.ts_font.height +
2019 tems.ts_p_offset.y;
2020 ca.col = tem->tvs_c_cursor.col * tems.ts_font.width +
2021 tems.ts_p_offset.x;
2022 ca.width = tems.ts_font.width;
2023 ca.height = tems.ts_font.height;
2024 if (tems.ts_pdepth == 8 || tems.ts_pdepth == 4) {
2025 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2026 ca.fg_color.mono = TEM_TEXT_WHITE;
2027 ca.bg_color.mono = TEM_TEXT_BLACK;
2028 } else {
2029 ca.fg_color.mono = TEM_TEXT_BLACK;
2030 ca.bg_color.mono = TEM_TEXT_WHITE;
2032 } else if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32) {
2033 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2034 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2035 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2036 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2038 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2039 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2040 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2041 } else {
2042 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2043 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2044 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2046 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2047 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2048 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2052 ca.action = action;
2054 tems_safe_cursor(&ca, credp, called_from);
2057 static void
2058 bit_to_pix4(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2059 text_color_t bg_color)
2061 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2062 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
2065 static void
2066 bit_to_pix8(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2067 text_color_t bg_color)
2069 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2070 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
2073 static void
2074 bit_to_pix24(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color4,
2075 text_color_t bg_color4)
2077 uint32_t fg_color32, bg_color32;
2078 uint8_t *dest;
2080 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2082 fg_color32 = PIX4TO32(fg_color4);
2083 bg_color32 = PIX4TO32(bg_color4);
2085 dest = (uint8_t *)tem->tvs_pix_data;
2086 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
2089 static void
2090 bit_to_pix32(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color4,
2091 text_color_t bg_color4)
2093 uint32_t fg_color32, bg_color32, *dest;
2095 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2097 fg_color32 = PIX4TO32(fg_color4);
2098 bg_color32 = PIX4TO32(bg_color4);
2100 dest = (uint32_t *)tem->tvs_pix_data;
2101 font_bit_to_pix32(&tems.ts_font, dest, c, fg_color32, bg_color32);
2104 static text_color_t
2105 ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
2107 if (tem->tvs_flags & TEM_ATTR_BRIGHT_BG)
2108 return (brt_xlate[ansi]);
2109 else
2110 return (dim_xlate[ansi]);
2113 static text_color_t
2114 ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
2116 if (tem->tvs_flags & TEM_ATTR_BRIGHT_FG ||
2117 tem->tvs_flags & TEM_ATTR_BOLD) {
2118 return (brt_xlate[ansi]);
2119 } else {
2120 return (dim_xlate[ansi]);
2125 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2127 void
2128 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2129 text_color_t *bg, uint8_t flag)
2131 if (tem->tvs_flags & flag) {
2132 *fg = ansi_fg_to_solaris(tem,
2133 tem->tvs_bg_color);
2134 *bg = ansi_bg_to_solaris(tem,
2135 tem->tvs_fg_color);
2136 } else {
2137 *fg = ansi_fg_to_solaris(tem,
2138 tem->tvs_fg_color);
2139 *bg = ansi_bg_to_solaris(tem,
2140 tem->tvs_bg_color);
2145 * Clear a rectangle of screen for pixel mode.
2147 * arguments:
2148 * row: start row#
2149 * nrows: the number of rows to clear
2150 * offset_y: the offset of height in pixels to begin clear
2151 * col: start col#
2152 * ncols: the number of cols to clear
2153 * offset_x: the offset of width in pixels to begin clear
2154 * scroll_up: whether this function is called during sroll up,
2155 * which is called only once.
2157 void
2158 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2159 screen_pos_t row, int nrows, int offset_y,
2160 screen_pos_t col, int ncols, int offset_x,
2161 boolean_t sroll_up, cred_t *credp,
2162 enum called_from called_from)
2164 struct vis_consdisplay da;
2165 int i, j;
2166 int row_add = 0;
2167 text_color_t fg_color;
2168 text_color_t bg_color;
2170 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2171 called_from == CALLED_FROM_STANDALONE);
2173 if (sroll_up)
2174 row_add = tems.ts_c_dimension.height - 1;
2176 da.width = tems.ts_font.width;
2177 da.height = tems.ts_font.height;
2179 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2181 tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
2182 da.data = (uchar_t *)tem->tvs_pix_data;
2184 for (i = 0; i < nrows; i++, row++) {
2185 da.row = (row + row_add) * da.height + offset_y;
2186 da.col = col * da.width + offset_x;
2187 for (j = 0; j < ncols; j++) {
2188 tems_safe_display(&da, credp, called_from);
2189 da.col += da.width;
2195 * virtual screen operations
2197 static void
2198 tem_safe_virtual_display(struct tem_vt_state *tem, unsigned char *string,
2199 int count, screen_pos_t row, screen_pos_t col,
2200 text_color_t fg_color, text_color_t bg_color)
2202 int i, width;
2203 unsigned char *addr;
2204 text_color_t *pfgcolor;
2205 text_color_t *pbgcolor;
2207 if (row < 0 || row >= tems.ts_c_dimension.height ||
2208 col < 0 || col >= tems.ts_c_dimension.width ||
2209 col + count > tems.ts_c_dimension.width)
2210 return;
2212 width = tems.ts_c_dimension.width;
2213 addr = tem->tvs_screen_buf + (row * width + col);
2214 pfgcolor = tem->tvs_fg_buf + (row * width + col);
2215 pbgcolor = tem->tvs_bg_buf + (row * width + col);
2216 for (i = 0; i < count; i++) {
2217 *addr++ = string[i];
2218 *pfgcolor++ = fg_color;
2219 *pbgcolor++ = bg_color;
2223 static void
2224 i_virtual_copy(unsigned char *base,
2225 screen_pos_t s_col, screen_pos_t s_row,
2226 screen_pos_t e_col, screen_pos_t e_row,
2227 screen_pos_t t_col, screen_pos_t t_row)
2229 unsigned char *from;
2230 unsigned char *to;
2231 int cnt;
2232 screen_size_t chars_per_row;
2233 unsigned char *to_row_start;
2234 unsigned char *from_row_start;
2235 screen_size_t rows_to_move;
2236 int cols = tems.ts_c_dimension.width;
2238 chars_per_row = e_col - s_col + 1;
2239 rows_to_move = e_row - s_row + 1;
2241 to_row_start = base + ((t_row * cols) + t_col);
2242 from_row_start = base + ((s_row * cols) + s_col);
2244 if (to_row_start < from_row_start) {
2245 while (rows_to_move-- > 0) {
2246 to = to_row_start;
2247 from = from_row_start;
2248 to_row_start += cols;
2249 from_row_start += cols;
2250 for (cnt = chars_per_row; cnt-- > 0; )
2251 *to++ = *from++;
2253 } else {
2255 * Offset to the end of the region and copy backwards.
2257 cnt = rows_to_move * cols + chars_per_row;
2258 to_row_start += cnt;
2259 from_row_start += cnt;
2261 while (rows_to_move-- > 0) {
2262 to_row_start -= cols;
2263 from_row_start -= cols;
2264 to = to_row_start;
2265 from = from_row_start;
2266 for (cnt = chars_per_row; cnt-- > 0; )
2267 *--to = *--from;
2272 static void
2273 tem_safe_virtual_copy(struct tem_vt_state *tem,
2274 screen_pos_t s_col, screen_pos_t s_row,
2275 screen_pos_t e_col, screen_pos_t e_row,
2276 screen_pos_t t_col, screen_pos_t t_row)
2278 screen_size_t chars_per_row;
2279 screen_size_t rows_to_move;
2280 int rows = tems.ts_c_dimension.height;
2281 int cols = tems.ts_c_dimension.width;
2283 if (s_col < 0 || s_col >= cols ||
2284 s_row < 0 || s_row >= rows ||
2285 e_col < 0 || e_col >= cols ||
2286 e_row < 0 || e_row >= rows ||
2287 t_col < 0 || t_col >= cols ||
2288 t_row < 0 || t_row >= rows ||
2289 s_col > e_col ||
2290 s_row > e_row)
2291 return;
2293 chars_per_row = e_col - s_col + 1;
2294 rows_to_move = e_row - s_row + 1;
2296 /* More sanity checks. */
2297 if (t_row + rows_to_move > rows ||
2298 t_col + chars_per_row > cols)
2299 return;
2301 i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
2302 e_col, e_row, t_col, t_row);
2304 /* text_color_t is the same size as char */
2305 i_virtual_copy((unsigned char *)tem->tvs_fg_buf,
2306 s_col, s_row, e_col, e_row, t_col, t_row);
2307 i_virtual_copy((unsigned char *)tem->tvs_bg_buf,
2308 s_col, s_row, e_col, e_row, t_col, t_row);
2312 static void
2313 tem_safe_virtual_cls(struct tem_vt_state *tem,
2314 int count, screen_pos_t row, screen_pos_t col)
2316 text_color_t fg_color;
2317 text_color_t bg_color;
2319 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2320 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col,
2321 fg_color, bg_color);
2325 * only blank screen, not clear our screen buffer
2327 void
2328 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2329 enum called_from called_from)
2331 int row;
2333 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2334 called_from == CALLED_FROM_STANDALONE);
2336 if (tems.ts_display_mode == VIS_PIXEL) {
2337 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2338 return;
2341 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2342 tem_safe_callback_cls(tem,
2343 tems.ts_c_dimension.width,
2344 row, 0, credp, called_from);
2349 * unblank screen with associated tem from its screen buffer
2351 void
2352 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2353 enum called_from called_from)
2355 text_color_t fg_color, fg_last;
2356 text_color_t bg_color, bg_last;
2357 size_t tc_size = sizeof (text_color_t);
2358 int row, col, count, col_start;
2359 int width;
2360 unsigned char *buf;
2362 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2363 called_from == CALLED_FROM_STANDALONE);
2365 if (tems.ts_display_mode == VIS_PIXEL)
2366 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2368 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2370 width = tems.ts_c_dimension.width;
2373 * Display data in tvs_screen_buf to the actual framebuffer in a
2374 * row by row way.
2375 * When dealing with one row, output data with the same foreground
2376 * and background color all together.
2378 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2379 buf = tem->tvs_screen_buf + (row * width);
2380 count = col_start = 0;
2381 for (col = 0; col < width; col++) {
2382 fg_color =
2383 tem->tvs_fg_buf[(row * width + col) * tc_size];
2384 bg_color =
2385 tem->tvs_bg_buf[(row * width + col) * tc_size];
2386 if (col == 0) {
2387 fg_last = fg_color;
2388 bg_last = bg_color;
2391 if ((fg_color != fg_last) || (bg_color != bg_last)) {
2393 * Call the primitive to render this data.
2395 tem_safe_callback_display(tem,
2396 buf, count, row, col_start,
2397 fg_last, bg_last, credp, called_from);
2398 buf += count;
2399 count = 1;
2400 col_start = col;
2401 fg_last = fg_color;
2402 bg_last = bg_color;
2403 } else {
2404 count++;
2408 if (col_start == (width - 1))
2409 continue;
2412 * Call the primitive to render this data.
2414 tem_safe_callback_display(tem,
2415 buf, count, row, col_start,
2416 fg_last, bg_last, credp, called_from);
2419 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);