7760 uts: tem should be able to display UTF-8
[unleashed.git] / usr / src / uts / common / io / tem_safe.c
blob031288446519c41d4aae3f5dc9263289ad071a8d
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);
157 /* BEGIN CSTYLED */
158 /* Bk Rd Gr Br Bl Mg Cy Wh */
159 static text_color_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
160 static text_color_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
161 /* END CSTYLED */
164 text_cmap_t cmap4_to_24 = {
165 /* BEGIN CSTYLED */
166 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
167 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
168 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
169 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
170 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
171 /* END CSTYLED */
174 #define PIX4TO32(pix4) (uint32_t)( \
175 cmap4_to_24.red[pix4] << 16 | \
176 cmap4_to_24.green[pix4] << 8 | \
177 cmap4_to_24.blue[pix4])
179 #define INVERSE(ch) (ch ^ 0xff)
181 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
182 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
183 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
184 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
185 #define tem_safe_callback_bit2pix(tem, c, fg, bg) { \
186 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
187 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c), (fg), (bg));\
190 void
191 tem_safe_check_first_time(
192 struct tem_vt_state *tem,
193 cred_t *credp,
194 enum called_from called_from)
196 static int first_time = 1;
198 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
199 called_from == CALLED_FROM_STANDALONE);
202 * Realign the console cursor. We did this in tem_init().
203 * However, drivers in the console stream may emit additional
204 * messages before we are ready. This causes text overwrite
205 * on the screen. This is a workaround.
207 if (!first_time)
208 return;
210 first_time = 0;
211 if (tems.ts_display_mode == VIS_TEXT) {
212 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
213 tem_safe_align_cursor(tem);
218 * This entry point handles output requests from restricted contexts like
219 * kmdb, where services like mutexes are not available. This function
220 * is entered when OBP or when a kernel debugger (such as kmdb)
221 * are generating console output. In those cases, power management
222 * concerns are handled by the abort sequence initiation (ie. when
223 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
224 * It is also entered when the kernel is panicing.
226 void
227 tem_safe_polled_write(
228 tem_vt_state_t tem_arg,
229 uchar_t *buf,
230 int len)
232 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
234 #ifdef __lock_lint
235 _NOTE(NO_COMPETING_THREADS_NOW)
236 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
237 #endif
239 if (!tem->tvs_initialized) {
240 return;
243 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
244 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
247 /* Process partial UTF-8 sequence. */
248 static void
249 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
250 enum called_from called_from)
252 int i;
253 uint8_t c;
255 if (tem->tvs_utf8_left == 0)
256 return;
258 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
259 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
260 if (c != 0) {
261 tem_safe_parse(tem, c, credp, called_from);
264 tem->tvs_utf8_left = 0;
265 tem->tvs_utf8_partial = 0;
269 * Handle UTF-8 sequences.
271 static void
272 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
273 enum called_from called_from)
276 * Check for UTF-8 code points. In case of error fall back to
277 * 8-bit code. As we only have 8859-1 fonts for console, this will set
278 * the limits on what chars we actually can display, therefore we
279 * have to return to this code once we have solved the font issue.
281 if ((c & 0x80) == 0x00) {
282 /* One-byte sequence. */
283 tem_safe_input_partial(tem, credp, called_from);
284 tem_safe_parse(tem, c, credp, called_from);
285 return;
287 if ((c & 0xe0) == 0xc0) {
288 /* Two-byte sequence. */
289 tem_safe_input_partial(tem, credp, called_from);
290 tem->tvs_utf8_left = 1;
291 tem->tvs_utf8_partial = c;
292 return;
294 if ((c & 0xf0) == 0xe0) {
295 /* Three-byte sequence. */
296 tem_safe_input_partial(tem, credp, called_from);
297 tem->tvs_utf8_left = 2;
298 tem->tvs_utf8_partial = c;
299 return;
301 if ((c & 0xf8) == 0xf0) {
302 /* Four-byte sequence. */
303 tem_safe_input_partial(tem, credp, called_from);
304 tem->tvs_utf8_left = 3;
305 tem->tvs_utf8_partial = c;
306 return;
308 if ((c & 0xc0) == 0x80) {
309 /* Invalid state? */
310 if (tem->tvs_utf8_left == 0) {
311 tem_safe_parse(tem, c, credp, called_from);
312 return;
314 tem->tvs_utf8_left--;
315 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
316 if (tem->tvs_utf8_left == 0) {
317 tem_char_t v, u;
318 uint8_t b;
321 * Transform the sequence of 2 to 4 bytes to
322 * unicode number.
324 v = 0;
325 u = tem->tvs_utf8_partial;
326 b = (u >> 24) & 0xff;
327 if (b != 0) { /* Four-byte sequence */
328 v = b & 0x07;
329 b = (u >> 16) & 0xff;
330 v = (v << 6) | (b & 0x3f);
331 b = (u >> 8) & 0xff;
332 v = (v << 6) | (b & 0x3f);
333 b = u & 0xff;
334 v = (v << 6) | (b & 0x3f);
335 } else if ((b = (u >> 16) & 0xff) != 0) {
336 v = b & 0x0f; /* Three-byte sequence */
337 b = (u >> 8) & 0xff;
338 v = (v << 6) | (b & 0x3f);
339 b = u & 0xff;
340 v = (v << 6) | (b & 0x3f);
341 } else if ((b = (u >> 8) & 0xff) != 0) {
342 v = b & 0x1f; /* Two-byte sequence */
343 b = u & 0xff;
344 v = (v << 6) | (b & 0x3f);
347 /* Use '?' as replacement if needed. */
348 if (v > 0xff)
349 v = '?';
350 tem_safe_parse(tem, v, credp, called_from);
351 tem->tvs_utf8_partial = 0;
353 return;
355 /* Anything left is illegal in UTF-8 sequence. */
356 tem_safe_input_partial(tem, credp, called_from);
357 tem_safe_parse(tem, c, credp, called_from);
361 * This is the main entry point into the terminal emulator.
363 * For each data message coming downstream, ANSI assumes that it is composed
364 * of ASCII characters, which are treated as a byte-stream input to the
365 * parsing state machine. All data is parsed immediately -- there is
366 * no enqueing.
368 void
369 tem_safe_terminal_emulate(
370 struct tem_vt_state *tem,
371 uchar_t *buf,
372 int len,
373 cred_t *credp,
374 enum called_from called_from)
377 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
378 called_from == CALLED_FROM_STANDALONE);
380 if (tem->tvs_isactive)
381 tem_safe_callback_cursor(tem,
382 VIS_HIDE_CURSOR, credp, called_from);
384 for (; len > 0; len--, buf++)
385 tem_safe_input_byte(tem, *buf, credp, called_from);
388 * Send the data we just got to the framebuffer.
390 tem_safe_send_data(tem, credp, called_from);
392 if (tem->tvs_isactive)
393 tem_safe_callback_cursor(tem,
394 VIS_DISPLAY_CURSOR, credp, called_from);
398 * Display an rectangular image on the frame buffer using the
399 * mechanism appropriate for the system state being called
400 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
402 static void
403 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
404 enum called_from called_from)
406 if (called_from == CALLED_FROM_STANDALONE)
407 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
408 else
409 tems_display_layered(pda, credp);
413 * Copy a rectangle from one location to another on the frame buffer
414 * using the mechanism appropriate for the system state being called
415 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
417 void
418 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
419 enum called_from called_from)
421 if (called_from == CALLED_FROM_STANDALONE)
422 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
423 else
424 tems_copy_layered(pca, credp);
428 * Display or hide a rectangular block text cursor of a specificsize
429 * at a specific location on frame buffer* using the mechanism
430 * appropriate for the system state being called from, quisced or
431 * normal (ie. use polled I/O vs. layered ioctls).
433 static void
434 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
435 enum called_from called_from)
437 if (called_from == CALLED_FROM_STANDALONE)
438 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
439 else
440 tems_cursor_layered(pca, credp);
444 * send the appropriate control message or set state based on the
445 * value of the control character ch
448 static void
449 tem_safe_control(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
450 enum called_from called_from)
452 tem->tvs_state = A_STATE_START;
453 switch (ch) {
454 case A_BEL:
455 tem_safe_bell(tem, called_from);
456 break;
458 case A_BS:
459 tem_safe_mv_cursor(tem,
460 tem->tvs_c_cursor.row,
461 tem->tvs_c_cursor.col - 1,
462 credp, called_from);
463 break;
465 case A_HT:
466 tem_safe_tab(tem, credp, called_from);
467 break;
469 case A_NL:
471 * tem_safe_send_data(tem, credp, called_from);
472 * tem_safe_new_line(tem, credp, called_from);
473 * break;
476 case A_VT:
477 tem_safe_send_data(tem, credp, called_from);
478 tem_safe_lf(tem, credp, called_from);
479 break;
481 case A_FF:
482 tem_safe_send_data(tem, credp, called_from);
483 tem_safe_cls(tem, credp, called_from);
484 break;
486 case A_CR:
487 tem_safe_send_data(tem, credp, called_from);
488 tem_safe_cr(tem);
489 break;
491 case A_ESC:
492 tem->tvs_state = A_STATE_ESC;
493 break;
495 case A_CSI:
497 int i;
498 tem->tvs_curparam = 0;
499 tem->tvs_paramval = 0;
500 tem->tvs_gotparam = B_FALSE;
501 /* clear the parameters */
502 for (i = 0; i < TEM_MAXPARAMS; i++)
503 tem->tvs_params[i] = -1;
504 tem->tvs_state = A_STATE_CSI;
506 break;
508 case A_GS:
509 tem_safe_back_tab(tem, credp, called_from);
510 break;
512 default:
513 break;
519 * if parameters [0..count - 1] are not set, set them to the value
520 * of newparam.
523 static void
524 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
526 int i;
528 for (i = 0; i < count; i++) {
529 if (tem->tvs_params[i] == -1)
530 tem->tvs_params[i] = newparam;
536 * select graphics mode based on the param vals stored in a_params
538 static void
539 tem_safe_selgraph(struct tem_vt_state *tem)
541 int curparam;
542 int count = 0;
543 int param;
545 tem->tvs_state = A_STATE_START;
547 curparam = tem->tvs_curparam;
548 do {
549 param = tem->tvs_params[count];
551 switch (param) {
552 case -1:
553 case 0:
554 /* reset to initial normal settings */
555 tem->tvs_fg_color = tems.ts_init_color.fg_color;
556 tem->tvs_bg_color = tems.ts_init_color.bg_color;
557 tem->tvs_flags = tems.ts_init_color.a_flags;
558 break;
560 case 1: /* Bold Intense */
561 tem->tvs_flags |= TEM_ATTR_BOLD;
562 break;
564 case 2: /* Faint Intense */
565 tem->tvs_flags &= ~TEM_ATTR_BOLD;
566 break;
568 case 5: /* Blink */
569 tem->tvs_flags |= TEM_ATTR_BLINK;
570 break;
572 case 7: /* Reverse video */
573 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
574 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
575 } else {
576 tem->tvs_flags |= TEM_ATTR_REVERSE;
578 break;
580 case 30: /* black (grey) foreground */
581 case 31: /* red (light red) foreground */
582 case 32: /* green (light green) foreground */
583 case 33: /* brown (yellow) foreground */
584 case 34: /* blue (light blue) foreground */
585 case 35: /* magenta (light magenta) foreground */
586 case 36: /* cyan (light cyan) foreground */
587 case 37: /* white (bright white) foreground */
588 tem->tvs_fg_color = param - 30;
589 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
590 break;
592 case 39:
594 * Reset the foreground colour and brightness.
596 tem->tvs_fg_color = tems.ts_init_color.fg_color;
597 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
598 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
599 else
600 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
601 break;
603 case 40: /* black (grey) background */
604 case 41: /* red (light red) background */
605 case 42: /* green (light green) background */
606 case 43: /* brown (yellow) background */
607 case 44: /* blue (light blue) background */
608 case 45: /* magenta (light magenta) background */
609 case 46: /* cyan (light cyan) background */
610 case 47: /* white (bright white) background */
611 tem->tvs_bg_color = param - 40;
612 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
613 break;
615 case 49:
617 * Reset the background colour and brightness.
619 tem->tvs_bg_color = tems.ts_init_color.bg_color;
620 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
621 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
622 else
623 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
624 break;
626 case 90: /* black (grey) foreground */
627 case 91: /* red (light red) foreground */
628 case 92: /* green (light green) foreground */
629 case 93: /* brown (yellow) foreground */
630 case 94: /* blue (light blue) foreground */
631 case 95: /* magenta (light magenta) foreground */
632 case 96: /* cyan (light cyan) foreground */
633 case 97: /* white (bright white) foreground */
634 tem->tvs_fg_color = param - 90;
635 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
636 break;
638 case 100: /* black (grey) background */
639 case 101: /* red (light red) background */
640 case 102: /* green (light green) background */
641 case 103: /* brown (yellow) background */
642 case 104: /* blue (light blue) background */
643 case 105: /* magenta (light magenta) background */
644 case 106: /* cyan (light cyan) background */
645 case 107: /* white (bright white) background */
646 tem->tvs_bg_color = param - 100;
647 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
648 break;
650 default:
651 break;
653 count++;
654 curparam--;
656 } while (curparam > 0);
660 * perform the appropriate action for the escape sequence
662 * General rule: This code does not validate the arguments passed.
663 * It assumes that the next lower level will do so.
665 static void
666 tem_safe_chkparam(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
667 enum called_from called_from)
669 int i;
670 int row;
671 int col;
673 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
674 MUTEX_HELD(&tem->tvs_lock));
676 row = tem->tvs_c_cursor.row;
677 col = tem->tvs_c_cursor.col;
679 switch (ch) {
681 case 'm': /* select terminal graphics mode */
682 tem_safe_send_data(tem, credp, called_from);
683 tem_safe_selgraph(tem);
684 break;
686 case '@': /* insert char */
687 tem_safe_setparam(tem, 1, 1);
688 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
689 credp, called_from);
690 break;
692 case 'A': /* cursor up */
693 tem_safe_setparam(tem, 1, 1);
694 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
695 credp, called_from);
696 break;
698 case 'd': /* VPA - vertical position absolute */
699 tem_safe_setparam(tem, 1, 1);
700 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
701 credp, called_from);
702 break;
704 case 'e': /* VPR - vertical position relative */
705 case 'B': /* cursor down */
706 tem_safe_setparam(tem, 1, 1);
707 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
708 credp, called_from);
709 break;
711 case 'a': /* HPR - horizontal position relative */
712 case 'C': /* cursor right */
713 tem_safe_setparam(tem, 1, 1);
714 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
715 credp, called_from);
716 break;
718 case '`': /* HPA - horizontal position absolute */
719 tem_safe_setparam(tem, 1, 1);
720 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
721 credp, called_from);
722 break;
724 case 'D': /* cursor left */
725 tem_safe_setparam(tem, 1, 1);
726 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
727 credp, called_from);
728 break;
730 case 'E': /* CNL cursor next line */
731 tem_safe_setparam(tem, 1, 1);
732 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
733 credp, called_from);
734 break;
736 case 'F': /* CPL cursor previous line */
737 tem_safe_setparam(tem, 1, 1);
738 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
739 credp, called_from);
740 break;
742 case 'G': /* cursor horizontal position */
743 tem_safe_setparam(tem, 1, 1);
744 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
745 credp, called_from);
746 break;
748 case 'g': /* clear tabs */
749 tem_safe_setparam(tem, 1, 0);
750 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
751 break;
753 case 'f': /* HVP Horizontal and Vertical Position */
754 case 'H': /* CUP position cursor */
755 tem_safe_setparam(tem, 2, 1);
756 tem_safe_mv_cursor(tem,
757 tem->tvs_params[0] - 1,
758 tem->tvs_params[1] - 1,
759 credp, called_from);
760 break;
762 case 'I': /* CHT - Cursor Horizontal Tab */
763 /* Not implemented */
764 break;
766 case 'J': /* ED - Erase in Display */
767 tem_safe_send_data(tem, credp, called_from);
768 tem_safe_setparam(tem, 1, 0);
769 switch (tem->tvs_params[0]) {
770 case 0:
771 /* erase cursor to end of screen */
772 /* FIRST erase cursor to end of line */
773 tem_safe_clear_chars(tem,
774 tems.ts_c_dimension.width -
775 tem->tvs_c_cursor.col,
776 tem->tvs_c_cursor.row,
777 tem->tvs_c_cursor.col, credp, called_from);
779 /* THEN erase lines below the cursor */
780 for (row = tem->tvs_c_cursor.row + 1;
781 row < tems.ts_c_dimension.height;
782 row++) {
783 tem_safe_clear_chars(tem,
784 tems.ts_c_dimension.width,
785 row, 0, credp, called_from);
787 break;
789 case 1:
790 /* erase beginning of screen to cursor */
791 /* FIRST erase lines above the cursor */
792 for (row = 0;
793 row < tem->tvs_c_cursor.row;
794 row++) {
795 tem_safe_clear_chars(tem,
796 tems.ts_c_dimension.width,
797 row, 0, credp, called_from);
799 /* THEN erase beginning of line to cursor */
800 tem_safe_clear_chars(tem,
801 tem->tvs_c_cursor.col + 1,
802 tem->tvs_c_cursor.row,
803 0, credp, called_from);
804 break;
806 case 2:
807 /* erase whole screen */
808 for (row = 0;
809 row < tems.ts_c_dimension.height;
810 row++) {
811 tem_safe_clear_chars(tem,
812 tems.ts_c_dimension.width,
813 row, 0, credp, called_from);
815 break;
817 break;
819 case 'K': /* EL - Erase in Line */
820 tem_safe_send_data(tem, credp, called_from);
821 tem_safe_setparam(tem, 1, 0);
822 switch (tem->tvs_params[0]) {
823 case 0:
824 /* erase cursor to end of line */
825 tem_safe_clear_chars(tem,
826 (tems.ts_c_dimension.width -
827 tem->tvs_c_cursor.col),
828 tem->tvs_c_cursor.row,
829 tem->tvs_c_cursor.col,
830 credp, called_from);
831 break;
833 case 1:
834 /* erase beginning of line to cursor */
835 tem_safe_clear_chars(tem,
836 tem->tvs_c_cursor.col + 1,
837 tem->tvs_c_cursor.row,
838 0, credp, called_from);
839 break;
841 case 2:
842 /* erase whole line */
843 tem_safe_clear_chars(tem,
844 tems.ts_c_dimension.width,
845 tem->tvs_c_cursor.row,
846 0, credp, called_from);
847 break;
849 break;
851 case 'L': /* insert line */
852 tem_safe_send_data(tem, credp, called_from);
853 tem_safe_setparam(tem, 1, 1);
854 tem_safe_scroll(tem,
855 tem->tvs_c_cursor.row,
856 tems.ts_c_dimension.height - 1,
857 tem->tvs_params[0], TEM_SCROLL_DOWN,
858 credp, called_from);
859 break;
861 case 'M': /* delete line */
862 tem_safe_send_data(tem, credp, called_from);
863 tem_safe_setparam(tem, 1, 1);
864 tem_safe_scroll(tem,
865 tem->tvs_c_cursor.row,
866 tems.ts_c_dimension.height - 1,
867 tem->tvs_params[0], TEM_SCROLL_UP,
868 credp, called_from);
869 break;
871 case 'P': /* DCH - delete char */
872 tem_safe_setparam(tem, 1, 1);
873 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
874 credp, called_from);
875 break;
877 case 'S': /* scroll up */
878 tem_safe_send_data(tem, credp, called_from);
879 tem_safe_setparam(tem, 1, 1);
880 tem_safe_scroll(tem, 0,
881 tems.ts_c_dimension.height - 1,
882 tem->tvs_params[0], TEM_SCROLL_UP,
883 credp, called_from);
884 break;
886 case 'T': /* scroll down */
887 tem_safe_send_data(tem, credp, called_from);
888 tem_safe_setparam(tem, 1, 1);
889 tem_safe_scroll(tem, 0,
890 tems.ts_c_dimension.height - 1,
891 tem->tvs_params[0], TEM_SCROLL_DOWN,
892 credp, called_from);
893 break;
895 case 'X': /* erase char */
896 tem_safe_setparam(tem, 1, 1);
897 tem_safe_clear_chars(tem,
898 tem->tvs_params[0],
899 tem->tvs_c_cursor.row,
900 tem->tvs_c_cursor.col,
901 credp, called_from);
902 break;
904 case 'Z': /* cursor backward tabulation */
905 tem_safe_setparam(tem, 1, 1);
908 * Rule exception - We do sanity checking here.
910 * Restrict the count to a sane value to keep from
911 * looping for a long time. There can't be more than one
912 * tab stop per column, so use that as a limit.
914 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
915 tem->tvs_params[0] = tems.ts_c_dimension.width;
917 for (i = 0; i < tem->tvs_params[0]; i++)
918 tem_safe_back_tab(tem, credp, called_from);
919 break;
921 tem->tvs_state = A_STATE_START;
926 * Gather the parameters of an ANSI escape sequence
928 static void
929 tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
930 cred_t *credp, enum called_from called_from)
932 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
933 MUTEX_HELD(&tem->tvs_lock));
935 if (ch >= '0' && ch <= '9') {
936 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
937 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
938 return; /* Return immediately */
939 } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
940 tem->tvs_state == A_STATE_CSI_QMARK) {
941 tem->tvs_state = A_STATE_START;
942 } else {
943 if (tem->tvs_curparam < TEM_MAXPARAMS) {
944 if (tem->tvs_gotparam) {
945 /* get the parameter value */
946 tem->tvs_params[tem->tvs_curparam] =
947 tem->tvs_paramval;
949 tem->tvs_curparam++;
952 if (ch == ';') {
953 /* Restart parameter search */
954 tem->tvs_gotparam = B_FALSE;
955 tem->tvs_paramval = 0; /* No parame value yet */
956 } else {
957 /* Handle escape sequence */
958 tem_safe_chkparam(tem, ch, credp, called_from);
964 * Add character to internal buffer.
965 * When its full, send it to the next layer.
968 static void
969 tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
970 cred_t *credp, enum called_from called_from)
973 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
974 called_from == CALLED_FROM_STANDALONE);
976 /* buffer up the character until later */
978 tem->tvs_outbuf[tem->tvs_outindex++] = ch;
979 tem->tvs_c_cursor.col++;
980 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
981 tem_safe_send_data(tem, credp, called_from);
982 tem_safe_new_line(tem, credp, called_from);
986 static void
987 tem_safe_new_line(struct tem_vt_state *tem,
988 cred_t *credp, enum called_from called_from)
990 tem_safe_cr(tem);
991 tem_safe_lf(tem, credp, called_from);
994 static void
995 tem_safe_cr(struct tem_vt_state *tem)
997 tem->tvs_c_cursor.col = 0;
998 tem_safe_align_cursor(tem);
1001 static void
1002 tem_safe_lf(struct tem_vt_state *tem,
1003 cred_t *credp, enum called_from called_from)
1005 int row;
1007 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1008 MUTEX_HELD(&tem->tvs_lock));
1011 * Sanity checking notes:
1012 * . a_nscroll was validated when it was set.
1013 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
1014 * will prevent anything bad from happening.
1016 row = tem->tvs_c_cursor.row + 1;
1018 if (row >= tems.ts_c_dimension.height) {
1019 if (tem->tvs_nscroll != 0) {
1020 tem_safe_scroll(tem, 0,
1021 tems.ts_c_dimension.height - 1,
1022 tem->tvs_nscroll, TEM_SCROLL_UP,
1023 credp, called_from);
1024 row = tems.ts_c_dimension.height -
1025 tem->tvs_nscroll;
1026 } else { /* no scroll */
1028 * implement Esc[#r when # is zero. This means no
1029 * scroll but just return cursor to top of screen,
1030 * do not clear screen.
1032 row = 0;
1036 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
1037 credp, called_from);
1039 if (tem->tvs_nscroll == 0) {
1040 /* erase rest of cursor line */
1041 tem_safe_clear_chars(tem,
1042 tems.ts_c_dimension.width -
1043 tem->tvs_c_cursor.col,
1044 tem->tvs_c_cursor.row,
1045 tem->tvs_c_cursor.col,
1046 credp, called_from);
1050 tem_safe_align_cursor(tem);
1053 static void
1054 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1055 enum called_from called_from)
1057 text_color_t fg_color;
1058 text_color_t bg_color;
1060 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1061 MUTEX_HELD(&tem->tvs_lock));
1063 if (tem->tvs_outindex == 0) {
1064 tem_safe_align_cursor(tem);
1065 return;
1068 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_REVERSE);
1069 tem_safe_virtual_display(tem,
1070 tem->tvs_outbuf, tem->tvs_outindex,
1071 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1072 fg_color, bg_color);
1074 if (tem->tvs_isactive) {
1076 * Call the primitive to render this data.
1078 tem_safe_callback_display(tem,
1079 tem->tvs_outbuf, tem->tvs_outindex,
1080 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1081 fg_color, bg_color,
1082 credp, called_from);
1085 tem->tvs_outindex = 0;
1087 tem_safe_align_cursor(tem);
1092 * We have just done something to the current output point. Reset the start
1093 * point for the buffered data in a_outbuf. There shouldn't be any data
1094 * buffered yet.
1096 static void
1097 tem_safe_align_cursor(struct tem_vt_state *tem)
1099 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1100 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1104 * State machine parser based on the current state and character input
1105 * major terminations are to control character or normal character
1108 static void
1109 tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
1110 cred_t *credp, enum called_from called_from)
1112 int i;
1114 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1115 MUTEX_HELD(&tem->tvs_lock));
1117 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1118 if (ch == A_CSI || ch == A_ESC || ch < ' ') {
1119 /* Control */
1120 tem_safe_control(tem, ch, credp, called_from);
1121 } else {
1122 /* Display */
1123 tem_safe_outch(tem, ch, credp, called_from);
1125 return;
1128 /* In <ESC> sequence */
1129 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1130 if (tem->tvs_state != A_STATE_CSI) {
1131 tem_safe_getparams(tem, ch, credp, called_from);
1132 return;
1135 switch (ch) {
1136 case '?':
1137 tem->tvs_state = A_STATE_CSI_QMARK;
1138 return;
1139 case '=':
1140 tem->tvs_state = A_STATE_CSI_EQUAL;
1141 return;
1142 case 's':
1144 * As defined below, this sequence
1145 * saves the cursor. However, Sun
1146 * defines ESC[s as reset. We resolved
1147 * the conflict by selecting reset as it
1148 * is exported in the termcap file for
1149 * sun-mon, while the "save cursor"
1150 * definition does not exist anywhere in
1151 * /etc/termcap.
1152 * However, having no coherent
1153 * definition of reset, we have not
1154 * implemented it.
1158 * Original code
1159 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1160 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1161 * tem->tvs_state = A_STATE_START;
1164 tem->tvs_state = A_STATE_START;
1165 return;
1166 case 'u':
1167 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1168 tem->tvs_r_cursor.col, credp, called_from);
1169 tem->tvs_state = A_STATE_START;
1170 return;
1171 case 'p': /* sunbow */
1172 tem_safe_send_data(tem, credp, called_from);
1174 * Don't set anything if we are
1175 * already as we want to be.
1177 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1178 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1180 * If we have switched the characters to be the
1181 * inverse from the screen, then switch them as
1182 * well to keep them the inverse of the screen.
1184 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1185 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1186 else
1187 tem->tvs_flags |= TEM_ATTR_REVERSE;
1189 tem_safe_cls(tem, credp, called_from);
1190 tem->tvs_state = A_STATE_START;
1191 return;
1192 case 'q': /* sunwob */
1193 tem_safe_send_data(tem, credp, called_from);
1195 * Don't set anything if we are
1196 * already where as we want to be.
1198 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1199 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1201 * If we have switched the characters to be the
1202 * inverse from the screen, then switch them as
1203 * well to keep them the inverse of the screen.
1205 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1206 tem->tvs_flags |= TEM_ATTR_REVERSE;
1207 else
1208 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1211 tem_safe_cls(tem, credp, called_from);
1212 tem->tvs_state = A_STATE_START;
1213 return;
1214 case 'r': /* sunscrl */
1216 * Rule exception: check for validity here.
1218 tem->tvs_nscroll = tem->tvs_paramval;
1219 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
1220 tem->tvs_nscroll = tems.ts_c_dimension.height;
1221 if (tem->tvs_nscroll < 0)
1222 tem->tvs_nscroll = 1;
1223 tem->tvs_state = A_STATE_START;
1224 return;
1225 default:
1226 tem_safe_getparams(tem, ch, credp, called_from);
1227 return;
1231 /* Previous char was <ESC> */
1232 if (ch == '[') {
1233 tem->tvs_curparam = 0;
1234 tem->tvs_paramval = 0;
1235 tem->tvs_gotparam = B_FALSE;
1236 /* clear the parameters */
1237 for (i = 0; i < TEM_MAXPARAMS; i++)
1238 tem->tvs_params[i] = -1;
1239 tem->tvs_state = A_STATE_CSI;
1240 } else if (ch == 'Q') { /* <ESC>Q ? */
1241 tem->tvs_state = A_STATE_START;
1242 } else if (ch == 'C') { /* <ESC>C ? */
1243 tem->tvs_state = A_STATE_START;
1244 } else {
1245 tem->tvs_state = A_STATE_START;
1246 if (ch == 'c') {
1247 /* ESC c resets display */
1248 tem_safe_reset_display(tem, credp, called_from,
1249 B_TRUE, B_TRUE);
1250 } else if (ch == 'H') {
1251 /* ESC H sets a tab */
1252 tem_safe_set_tab(tem);
1253 } else if (ch == '7') {
1254 /* ESC 7 Save Cursor position */
1255 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1256 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1257 } else if (ch == '8') {
1258 /* ESC 8 Restore Cursor position */
1259 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1260 tem->tvs_r_cursor.col, credp, called_from);
1261 /* check for control chars */
1262 } else if (ch < ' ') {
1263 tem_safe_control(tem, ch, credp, called_from);
1264 } else {
1265 tem_safe_outch(tem, ch, credp, called_from);
1270 /* ARGSUSED */
1271 static void
1272 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1274 if (called_from == CALLED_FROM_STANDALONE)
1275 (void) beep_polled(BEEP_CONSOLE);
1276 else
1277 (void) beep(BEEP_CONSOLE);
1281 static void
1282 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1283 int direction, cred_t *credp, enum called_from called_from)
1285 int row;
1286 int lines_affected;
1288 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1289 called_from == CALLED_FROM_STANDALONE);
1291 lines_affected = end - start + 1;
1292 if (count > lines_affected)
1293 count = lines_affected;
1294 if (count <= 0)
1295 return;
1297 switch (direction) {
1298 case TEM_SCROLL_UP:
1299 if (count < lines_affected) {
1300 tem_safe_copy_area(tem, 0, start + count,
1301 tems.ts_c_dimension.width - 1, end,
1302 0, start, credp, called_from);
1304 for (row = (end - count) + 1; row <= end; row++) {
1305 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1306 row, 0, credp, called_from);
1308 break;
1310 case TEM_SCROLL_DOWN:
1311 if (count < lines_affected) {
1312 tem_safe_copy_area(tem, 0, start,
1313 tems.ts_c_dimension.width - 1,
1314 end - count, 0, start + count,
1315 credp, called_from);
1317 for (row = start; row < start + count; row++) {
1318 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1319 row, 0, credp, called_from);
1321 break;
1325 static void
1326 tem_safe_copy_area(struct tem_vt_state *tem,
1327 screen_pos_t s_col, screen_pos_t s_row,
1328 screen_pos_t e_col, screen_pos_t e_row,
1329 screen_pos_t t_col, screen_pos_t t_row,
1330 cred_t *credp, enum called_from called_from)
1332 int rows;
1333 int cols;
1335 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1336 called_from == CALLED_FROM_STANDALONE);
1338 if (s_col < 0 || s_row < 0 ||
1339 e_col < 0 || e_row < 0 ||
1340 t_col < 0 || t_row < 0 ||
1341 s_col >= tems.ts_c_dimension.width ||
1342 e_col >= tems.ts_c_dimension.width ||
1343 t_col >= tems.ts_c_dimension.width ||
1344 s_row >= tems.ts_c_dimension.height ||
1345 e_row >= tems.ts_c_dimension.height ||
1346 t_row >= tems.ts_c_dimension.height)
1347 return;
1349 if (s_row > e_row || s_col > e_col)
1350 return;
1352 rows = e_row - s_row + 1;
1353 cols = e_col - s_col + 1;
1354 if (t_row + rows > tems.ts_c_dimension.height ||
1355 t_col + cols > tems.ts_c_dimension.width)
1356 return;
1358 tem_safe_virtual_copy(tem,
1359 s_col, s_row,
1360 e_col, e_row,
1361 t_col, t_row);
1363 if (!tem->tvs_isactive)
1364 return;
1366 tem_safe_callback_copy(tem, s_col, s_row,
1367 e_col, e_row, t_col, t_row, credp, called_from);
1370 static void
1371 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1372 screen_pos_t col, cred_t *credp, enum called_from called_from)
1374 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1375 called_from == CALLED_FROM_STANDALONE);
1377 if (row < 0 || row >= tems.ts_c_dimension.height ||
1378 col < 0 || col >= tems.ts_c_dimension.width ||
1379 count < 0)
1380 return;
1383 * Note that very large values of "count" could cause col+count
1384 * to overflow, so we check "count" independently.
1386 if (count > tems.ts_c_dimension.width ||
1387 col + count > tems.ts_c_dimension.width)
1388 count = tems.ts_c_dimension.width - col;
1390 tem_safe_virtual_cls(tem, count, row, col);
1392 if (!tem->tvs_isactive)
1393 return;
1395 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1398 /*ARGSUSED*/
1399 void
1400 tem_safe_text_display(struct tem_vt_state *tem, uchar_t *string,
1401 int count, screen_pos_t row, screen_pos_t col,
1402 text_color_t fg_color, text_color_t bg_color,
1403 cred_t *credp, enum called_from called_from)
1405 struct vis_consdisplay da;
1407 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1408 called_from == CALLED_FROM_STANDALONE);
1410 da.data = string;
1411 da.width = (screen_size_t)count;
1412 da.row = row;
1413 da.col = col;
1415 da.fg_color = fg_color;
1416 da.bg_color = bg_color;
1418 tems_safe_display(&da, credp, called_from);
1422 * This function is used to blit a rectangular color image,
1423 * unperturbed on the underlying framebuffer, to render
1424 * icons and pictures. The data is a pixel pattern that
1425 * fills a rectangle bounded to the width and height parameters.
1426 * The color pixel data must to be pre-adjusted by the caller
1427 * for the current video depth.
1429 * This function is unused now.
1431 /*ARGSUSED*/
1432 static void
1433 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1434 int height, int width, screen_pos_t row, screen_pos_t col,
1435 cred_t *credp, enum called_from called_from)
1437 struct vis_consdisplay da;
1439 mutex_enter(&tems.ts_lock);
1440 mutex_enter(&tem->tvs_lock);
1442 da.data = image;
1443 da.width = (screen_size_t)width;
1444 da.height = (screen_size_t)height;
1445 da.row = row;
1446 da.col = col;
1448 tems_safe_display(&da, credp, called_from);
1450 mutex_exit(&tem->tvs_lock);
1451 mutex_exit(&tems.ts_lock);
1455 /*ARGSUSED*/
1456 void
1457 tem_safe_text_copy(struct tem_vt_state *tem,
1458 screen_pos_t s_col, screen_pos_t s_row,
1459 screen_pos_t e_col, screen_pos_t e_row,
1460 screen_pos_t t_col, screen_pos_t t_row,
1461 cred_t *credp, enum called_from called_from)
1463 struct vis_conscopy da;
1465 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1466 called_from == CALLED_FROM_STANDALONE);
1468 da.s_row = s_row;
1469 da.s_col = s_col;
1470 da.e_row = e_row;
1471 da.e_col = e_col;
1472 da.t_row = t_row;
1473 da.t_col = t_col;
1475 tems_safe_copy(&da, credp, called_from);
1478 void
1479 tem_safe_text_cls(struct tem_vt_state *tem,
1480 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1481 enum called_from called_from)
1483 struct vis_consdisplay da;
1485 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1486 called_from == CALLED_FROM_STANDALONE);
1488 da.data = tems.ts_blank_line;
1489 da.width = (screen_size_t)count;
1490 da.row = row;
1491 da.col = col;
1493 tem_safe_get_color(tem, &da.fg_color, &da.bg_color,
1494 TEM_ATTR_SCREEN_REVERSE);
1495 tems_safe_display(&da, credp, called_from);
1498 void
1499 tem_safe_pix_display(struct tem_vt_state *tem,
1500 uchar_t *string, int count,
1501 screen_pos_t row, screen_pos_t col,
1502 text_color_t fg_color, text_color_t bg_color,
1503 cred_t *credp, enum called_from called_from)
1505 struct vis_consdisplay da;
1506 int i;
1508 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1509 called_from == CALLED_FROM_STANDALONE);
1511 da.data = (uchar_t *)tem->tvs_pix_data;
1512 da.width = tems.ts_font.width;
1513 da.height = tems.ts_font.height;
1514 da.row = (row * da.height) + tems.ts_p_offset.y;
1515 da.col = (col * da.width) + tems.ts_p_offset.x;
1517 for (i = 0; i < count; i++) {
1518 tem_safe_callback_bit2pix(tem, string[i], fg_color, bg_color);
1519 tems_safe_display(&da, credp, called_from);
1520 da.col += da.width;
1524 void
1525 tem_safe_pix_copy(struct tem_vt_state *tem,
1526 screen_pos_t s_col, screen_pos_t s_row,
1527 screen_pos_t e_col, screen_pos_t e_row,
1528 screen_pos_t t_col, screen_pos_t t_row,
1529 cred_t *credp,
1530 enum called_from called_from)
1532 struct vis_conscopy ma;
1533 static boolean_t need_clear = B_TRUE;
1535 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1536 called_from == CALLED_FROM_STANDALONE);
1538 if (need_clear && tem->tvs_first_line > 0) {
1540 * Clear OBP output above our kernel console term
1541 * when our kernel console term begins to scroll up,
1542 * we hope it is user friendly.
1543 * (Also see comments on tem_safe_pix_clear_prom_output)
1545 * This is only one time call.
1547 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1549 need_clear = B_FALSE;
1551 ma.s_row = s_row * tems.ts_font.height + tems.ts_p_offset.y;
1552 ma.e_row = (e_row + 1) * tems.ts_font.height + tems.ts_p_offset.y - 1;
1553 ma.t_row = t_row * tems.ts_font.height + tems.ts_p_offset.y;
1556 * Check if we're in process of clearing OBP's columns area,
1557 * which only happens when term scrolls up a whole line.
1559 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1560 e_col == tems.ts_c_dimension.width - 1) {
1562 * We need to clear OBP's columns area outside our kernel
1563 * console term. So that we set ma.e_col to entire row here.
1565 ma.s_col = s_col * tems.ts_font.width;
1566 ma.e_col = tems.ts_p_dimension.width - 1;
1568 ma.t_col = t_col * tems.ts_font.width;
1569 } else {
1570 ma.s_col = s_col * tems.ts_font.width + tems.ts_p_offset.x;
1571 ma.e_col = (e_col + 1) * tems.ts_font.width +
1572 tems.ts_p_offset.x - 1;
1573 ma.t_col = t_col * tems.ts_font.width + tems.ts_p_offset.x;
1576 tems_safe_copy(&ma, credp, called_from);
1578 if (tem->tvs_first_line > 0 && t_row < s_row) {
1579 /* We have scrolled up (s_row - t_row) rows. */
1580 tem->tvs_first_line -= (s_row - t_row);
1581 if (tem->tvs_first_line <= 0) {
1582 /* All OBP rows have been cleared. */
1583 tem->tvs_first_line = 0;
1589 void
1590 tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
1591 unsigned char fg, unsigned char bg)
1593 void (*fp)(struct tem_vt_state *, unsigned char,
1594 unsigned char, unsigned char);
1596 switch (tems.ts_pdepth) {
1597 case 4:
1598 fp = bit_to_pix4;
1599 break;
1600 case 8:
1601 fp = bit_to_pix8;
1602 break;
1603 case 24:
1604 case 32:
1605 fp = bit_to_pix24;
1608 fp(tem, c, fg, bg);
1613 * This function only clears count of columns in one row
1615 void
1616 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
1617 screen_pos_t row, screen_pos_t col, cred_t *credp,
1618 enum called_from called_from)
1620 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1621 called_from == CALLED_FROM_STANDALONE);
1623 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
1624 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
1628 * This function clears OBP output above our kernel console term area
1629 * because OBP's term may have a bigger terminal window than that of
1630 * our kernel console term. So we need to clear OBP output garbage outside
1631 * of our kernel console term at a proper time, which is when the first
1632 * row output of our kernel console term scrolls at the first screen line.
1634 * _________________________________
1635 * | _____________________ | ---> OBP's bigger term window
1636 * | | | |
1637 * |___| | |
1638 * | | | | |
1639 * | | | | |
1640 * |_|_|___________________|_______|
1641 * | | | ---> first line
1642 * | |___________________|---> our kernel console term window
1644 * |---> columns area to be cleared
1646 * This function only takes care of the output above our kernel console term,
1647 * and tem_prom_scroll_up takes care of columns area outside of our kernel
1648 * console term.
1650 static void
1651 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1652 enum called_from called_from)
1654 int nrows, ncols, width, height;
1656 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1657 called_from == CALLED_FROM_STANDALONE);
1659 width = tems.ts_font.width;
1660 height = tems.ts_font.height;
1662 nrows = (tems.ts_p_offset.y + (height - 1))/ height;
1663 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1665 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1666 B_FALSE, credp, called_from);
1670 * clear the whole screen for pixel mode, just clear the
1671 * physical screen.
1673 void
1674 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1675 enum called_from called_from)
1677 int nrows, ncols, width, height;
1679 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1680 called_from == CALLED_FROM_STANDALONE);
1682 width = tems.ts_font.width;
1683 height = tems.ts_font.height;
1685 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1686 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1688 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1689 B_FALSE, credp, called_from);
1692 * Since the whole screen is cleared, we don't need
1693 * to clear OBP output later.
1695 if (tem->tvs_first_line > 0)
1696 tem->tvs_first_line = 0;
1700 * clear the whole screen, including the virtual screen buffer,
1701 * and reset the cursor to start point.
1703 static void
1704 tem_safe_cls(struct tem_vt_state *tem,
1705 cred_t *credp, enum called_from called_from)
1707 int row;
1709 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1710 called_from == CALLED_FROM_STANDALONE);
1712 if (tems.ts_display_mode == VIS_TEXT) {
1713 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1714 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1715 row, 0, credp, called_from);
1717 tem->tvs_c_cursor.row = 0;
1718 tem->tvs_c_cursor.col = 0;
1719 tem_safe_align_cursor(tem);
1720 return;
1723 ASSERT(tems.ts_display_mode == VIS_PIXEL);
1725 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1726 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
1728 tem->tvs_c_cursor.row = 0;
1729 tem->tvs_c_cursor.col = 0;
1730 tem_safe_align_cursor(tem);
1732 if (!tem->tvs_isactive)
1733 return;
1735 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
1738 static void
1739 tem_safe_back_tab(struct tem_vt_state *tem,
1740 cred_t *credp, enum called_from called_from)
1742 int i;
1743 screen_pos_t tabstop;
1745 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1746 called_from == CALLED_FROM_STANDALONE);
1748 tabstop = 0;
1750 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
1751 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
1752 tabstop = tem->tvs_tabs[i];
1753 break;
1757 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1758 tabstop, credp, called_from);
1761 static void
1762 tem_safe_tab(struct tem_vt_state *tem,
1763 cred_t *credp, enum called_from called_from)
1765 int i;
1766 screen_pos_t tabstop;
1768 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1769 called_from == CALLED_FROM_STANDALONE);
1771 tabstop = tems.ts_c_dimension.width - 1;
1773 for (i = 0; i < tem->tvs_ntabs; i++) {
1774 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1775 tabstop = tem->tvs_tabs[i];
1776 break;
1780 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1781 tabstop, credp, called_from);
1784 static void
1785 tem_safe_set_tab(struct tem_vt_state *tem)
1787 int i;
1788 int j;
1790 if (tem->tvs_ntabs == TEM_MAXTAB)
1791 return;
1792 if (tem->tvs_ntabs == 0 ||
1793 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
1794 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
1795 return;
1797 for (i = 0; i < tem->tvs_ntabs; i++) {
1798 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
1799 return;
1800 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1801 for (j = tem->tvs_ntabs - 1; j >= i; j--)
1802 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
1803 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
1804 tem->tvs_ntabs++;
1805 return;
1810 static void
1811 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
1813 int i;
1814 int j;
1816 switch (action) {
1817 case 3: /* clear all tabs */
1818 tem->tvs_ntabs = 0;
1819 break;
1820 case 0: /* clr tab at cursor */
1822 for (i = 0; i < tem->tvs_ntabs; i++) {
1823 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
1824 tem->tvs_ntabs--;
1825 for (j = i; j < tem->tvs_ntabs; j++)
1826 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
1827 return;
1830 break;
1834 static void
1835 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
1836 cred_t *credp, enum called_from called_from)
1838 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1839 called_from == CALLED_FROM_STANDALONE);
1842 * Sanity check and bounds enforcement. Out of bounds requests are
1843 * clipped to the screen boundaries. This seems to be what SPARC
1844 * does.
1846 if (row < 0)
1847 row = 0;
1848 if (row >= tems.ts_c_dimension.height)
1849 row = tems.ts_c_dimension.height - 1;
1850 if (col < 0)
1851 col = 0;
1852 if (col >= tems.ts_c_dimension.width)
1853 col = tems.ts_c_dimension.width - 1;
1855 tem_safe_send_data(tem, credp, called_from);
1856 tem->tvs_c_cursor.row = (screen_pos_t)row;
1857 tem->tvs_c_cursor.col = (screen_pos_t)col;
1858 tem_safe_align_cursor(tem);
1861 /* ARGSUSED */
1862 void
1863 tem_safe_reset_emulator(struct tem_vt_state *tem,
1864 cred_t *credp, enum called_from called_from,
1865 boolean_t init_color)
1867 int j;
1869 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1870 called_from == CALLED_FROM_STANDALONE);
1872 tem->tvs_c_cursor.row = 0;
1873 tem->tvs_c_cursor.col = 0;
1874 tem->tvs_r_cursor.row = 0;
1875 tem->tvs_r_cursor.col = 0;
1876 tem->tvs_s_cursor.row = 0;
1877 tem->tvs_s_cursor.col = 0;
1878 tem->tvs_outindex = 0;
1879 tem->tvs_state = A_STATE_START;
1880 tem->tvs_gotparam = B_FALSE;
1881 tem->tvs_curparam = 0;
1882 tem->tvs_paramval = 0;
1883 tem->tvs_nscroll = 1;
1885 if (init_color) {
1886 /* use initial settings */
1887 tem->tvs_fg_color = tems.ts_init_color.fg_color;
1888 tem->tvs_bg_color = tems.ts_init_color.bg_color;
1889 tem->tvs_flags = tems.ts_init_color.a_flags;
1893 * set up the initial tab stops
1895 tem->tvs_ntabs = 0;
1896 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
1897 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
1899 for (j = 0; j < TEM_MAXPARAMS; j++)
1900 tem->tvs_params[j] = 0;
1903 void
1904 tem_safe_reset_display(struct tem_vt_state *tem,
1905 cred_t *credp, enum called_from called_from,
1906 boolean_t clear_txt, boolean_t init_color)
1908 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1909 called_from == CALLED_FROM_STANDALONE);
1911 tem_safe_reset_emulator(tem, credp, called_from, init_color);
1913 if (clear_txt) {
1914 if (tem->tvs_isactive)
1915 tem_safe_callback_cursor(tem,
1916 VIS_HIDE_CURSOR, credp, called_from);
1918 tem_safe_cls(tem, credp, called_from);
1920 if (tem->tvs_isactive)
1921 tem_safe_callback_cursor(tem,
1922 VIS_DISPLAY_CURSOR, credp, called_from);
1926 static void
1927 tem_safe_shift(
1928 struct tem_vt_state *tem,
1929 int count,
1930 int direction,
1931 cred_t *credp,
1932 enum called_from called_from)
1934 int rest_of_line;
1936 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1937 called_from == CALLED_FROM_STANDALONE);
1939 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
1940 if (count > rest_of_line)
1941 count = rest_of_line;
1943 if (count <= 0)
1944 return;
1946 switch (direction) {
1947 case TEM_SHIFT_LEFT:
1948 if (count < rest_of_line) {
1949 tem_safe_copy_area(tem,
1950 tem->tvs_c_cursor.col + count,
1951 tem->tvs_c_cursor.row,
1952 tems.ts_c_dimension.width - 1,
1953 tem->tvs_c_cursor.row,
1954 tem->tvs_c_cursor.col,
1955 tem->tvs_c_cursor.row,
1956 credp, called_from);
1959 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1960 (tems.ts_c_dimension.width - count), credp,
1961 called_from);
1962 break;
1963 case TEM_SHIFT_RIGHT:
1964 if (count < rest_of_line) {
1965 tem_safe_copy_area(tem,
1966 tem->tvs_c_cursor.col,
1967 tem->tvs_c_cursor.row,
1968 tems.ts_c_dimension.width - count - 1,
1969 tem->tvs_c_cursor.row,
1970 tem->tvs_c_cursor.col + count,
1971 tem->tvs_c_cursor.row,
1972 credp, called_from);
1975 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1976 tem->tvs_c_cursor.col, credp, called_from);
1977 break;
1981 void
1982 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
1983 cred_t *credp, enum called_from called_from)
1985 struct vis_conscursor ca;
1987 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1988 called_from == CALLED_FROM_STANDALONE);
1990 ca.row = tem->tvs_c_cursor.row;
1991 ca.col = tem->tvs_c_cursor.col;
1992 ca.action = action;
1994 tems_safe_cursor(&ca, credp, called_from);
1996 if (action == VIS_GET_CURSOR) {
1997 tem->tvs_c_cursor.row = ca.row;
1998 tem->tvs_c_cursor.col = ca.col;
2002 void
2003 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
2004 cred_t *credp, enum called_from called_from)
2006 struct vis_conscursor ca;
2008 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2009 called_from == CALLED_FROM_STANDALONE);
2011 ca.row = tem->tvs_c_cursor.row * tems.ts_font.height +
2012 tems.ts_p_offset.y;
2013 ca.col = tem->tvs_c_cursor.col * tems.ts_font.width +
2014 tems.ts_p_offset.x;
2015 ca.width = tems.ts_font.width;
2016 ca.height = tems.ts_font.height;
2017 if (tems.ts_pdepth == 8 || tems.ts_pdepth == 4) {
2018 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2019 ca.fg_color.mono = TEM_TEXT_WHITE;
2020 ca.bg_color.mono = TEM_TEXT_BLACK;
2021 } else {
2022 ca.fg_color.mono = TEM_TEXT_BLACK;
2023 ca.bg_color.mono = TEM_TEXT_WHITE;
2025 } else if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32) {
2026 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2027 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2028 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2029 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2031 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2032 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2033 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2034 } else {
2035 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2036 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2037 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2039 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2040 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2041 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2045 ca.action = action;
2047 tems_safe_cursor(&ca, credp, called_from);
2050 static void
2051 bit_to_pix4(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2052 text_color_t bg_color)
2054 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2055 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
2058 static void
2059 bit_to_pix8(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2060 text_color_t bg_color)
2062 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2063 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
2066 static void
2067 bit_to_pix24(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color4,
2068 text_color_t bg_color4)
2070 uint32_t fg_color32, bg_color32, *dest;
2072 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2074 fg_color32 = PIX4TO32(fg_color4);
2075 bg_color32 = PIX4TO32(bg_color4);
2077 dest = (uint32_t *)tem->tvs_pix_data;
2078 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
2081 static text_color_t
2082 ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
2084 if (tem->tvs_flags & TEM_ATTR_BRIGHT_BG)
2085 return (brt_xlate[ansi]);
2086 else
2087 return (dim_xlate[ansi]);
2090 static text_color_t
2091 ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
2093 if (tem->tvs_flags & TEM_ATTR_BRIGHT_FG ||
2094 tem->tvs_flags & TEM_ATTR_BOLD) {
2095 return (brt_xlate[ansi]);
2096 } else {
2097 return (dim_xlate[ansi]);
2102 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2104 void
2105 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2106 text_color_t *bg, uint8_t flag)
2108 if (tem->tvs_flags & flag) {
2109 *fg = ansi_fg_to_solaris(tem,
2110 tem->tvs_bg_color);
2111 *bg = ansi_bg_to_solaris(tem,
2112 tem->tvs_fg_color);
2113 } else {
2114 *fg = ansi_fg_to_solaris(tem,
2115 tem->tvs_fg_color);
2116 *bg = ansi_bg_to_solaris(tem,
2117 tem->tvs_bg_color);
2122 * Clear a rectangle of screen for pixel mode.
2124 * arguments:
2125 * row: start row#
2126 * nrows: the number of rows to clear
2127 * offset_y: the offset of height in pixels to begin clear
2128 * col: start col#
2129 * ncols: the number of cols to clear
2130 * offset_x: the offset of width in pixels to begin clear
2131 * scroll_up: whether this function is called during sroll up,
2132 * which is called only once.
2134 void
2135 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2136 screen_pos_t row, int nrows, int offset_y,
2137 screen_pos_t col, int ncols, int offset_x,
2138 boolean_t sroll_up, cred_t *credp,
2139 enum called_from called_from)
2141 struct vis_consdisplay da;
2142 int i, j;
2143 int row_add = 0;
2144 text_color_t fg_color;
2145 text_color_t bg_color;
2147 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2148 called_from == CALLED_FROM_STANDALONE);
2150 if (sroll_up)
2151 row_add = tems.ts_c_dimension.height - 1;
2153 da.width = tems.ts_font.width;
2154 da.height = tems.ts_font.height;
2156 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2158 tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
2159 da.data = (uchar_t *)tem->tvs_pix_data;
2161 for (i = 0; i < nrows; i++, row++) {
2162 da.row = (row + row_add) * da.height + offset_y;
2163 da.col = col * da.width + offset_x;
2164 for (j = 0; j < ncols; j++) {
2165 tems_safe_display(&da, credp, called_from);
2166 da.col += da.width;
2172 * virtual screen operations
2174 static void
2175 tem_safe_virtual_display(struct tem_vt_state *tem, unsigned char *string,
2176 int count, screen_pos_t row, screen_pos_t col,
2177 text_color_t fg_color, text_color_t bg_color)
2179 int i, width;
2180 unsigned char *addr;
2181 text_color_t *pfgcolor;
2182 text_color_t *pbgcolor;
2184 if (row < 0 || row >= tems.ts_c_dimension.height ||
2185 col < 0 || col >= tems.ts_c_dimension.width ||
2186 col + count > tems.ts_c_dimension.width)
2187 return;
2189 width = tems.ts_c_dimension.width;
2190 addr = tem->tvs_screen_buf + (row * width + col);
2191 pfgcolor = tem->tvs_fg_buf + (row * width + col);
2192 pbgcolor = tem->tvs_bg_buf + (row * width + col);
2193 for (i = 0; i < count; i++) {
2194 *addr++ = string[i];
2195 *pfgcolor++ = fg_color;
2196 *pbgcolor++ = bg_color;
2200 static void
2201 i_virtual_copy(unsigned char *base,
2202 screen_pos_t s_col, screen_pos_t s_row,
2203 screen_pos_t e_col, screen_pos_t e_row,
2204 screen_pos_t t_col, screen_pos_t t_row)
2206 unsigned char *from;
2207 unsigned char *to;
2208 int cnt;
2209 screen_size_t chars_per_row;
2210 unsigned char *to_row_start;
2211 unsigned char *from_row_start;
2212 screen_size_t rows_to_move;
2213 int cols = tems.ts_c_dimension.width;
2215 chars_per_row = e_col - s_col + 1;
2216 rows_to_move = e_row - s_row + 1;
2218 to_row_start = base + ((t_row * cols) + t_col);
2219 from_row_start = base + ((s_row * cols) + s_col);
2221 if (to_row_start < from_row_start) {
2222 while (rows_to_move-- > 0) {
2223 to = to_row_start;
2224 from = from_row_start;
2225 to_row_start += cols;
2226 from_row_start += cols;
2227 for (cnt = chars_per_row; cnt-- > 0; )
2228 *to++ = *from++;
2230 } else {
2232 * Offset to the end of the region and copy backwards.
2234 cnt = rows_to_move * cols + chars_per_row;
2235 to_row_start += cnt;
2236 from_row_start += cnt;
2238 while (rows_to_move-- > 0) {
2239 to_row_start -= cols;
2240 from_row_start -= cols;
2241 to = to_row_start;
2242 from = from_row_start;
2243 for (cnt = chars_per_row; cnt-- > 0; )
2244 *--to = *--from;
2249 static void
2250 tem_safe_virtual_copy(struct tem_vt_state *tem,
2251 screen_pos_t s_col, screen_pos_t s_row,
2252 screen_pos_t e_col, screen_pos_t e_row,
2253 screen_pos_t t_col, screen_pos_t t_row)
2255 screen_size_t chars_per_row;
2256 screen_size_t rows_to_move;
2257 int rows = tems.ts_c_dimension.height;
2258 int cols = tems.ts_c_dimension.width;
2260 if (s_col < 0 || s_col >= cols ||
2261 s_row < 0 || s_row >= rows ||
2262 e_col < 0 || e_col >= cols ||
2263 e_row < 0 || e_row >= rows ||
2264 t_col < 0 || t_col >= cols ||
2265 t_row < 0 || t_row >= rows ||
2266 s_col > e_col ||
2267 s_row > e_row)
2268 return;
2270 chars_per_row = e_col - s_col + 1;
2271 rows_to_move = e_row - s_row + 1;
2273 /* More sanity checks. */
2274 if (t_row + rows_to_move > rows ||
2275 t_col + chars_per_row > cols)
2276 return;
2278 i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
2279 e_col, e_row, t_col, t_row);
2281 /* text_color_t is the same size as char */
2282 i_virtual_copy((unsigned char *)tem->tvs_fg_buf,
2283 s_col, s_row, e_col, e_row, t_col, t_row);
2284 i_virtual_copy((unsigned char *)tem->tvs_bg_buf,
2285 s_col, s_row, e_col, e_row, t_col, t_row);
2289 static void
2290 tem_safe_virtual_cls(struct tem_vt_state *tem,
2291 int count, screen_pos_t row, screen_pos_t col)
2293 text_color_t fg_color;
2294 text_color_t bg_color;
2296 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2297 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col,
2298 fg_color, bg_color);
2302 * only blank screen, not clear our screen buffer
2304 void
2305 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2306 enum called_from called_from)
2308 int row;
2310 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2311 called_from == CALLED_FROM_STANDALONE);
2313 if (tems.ts_display_mode == VIS_PIXEL) {
2314 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2315 return;
2318 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2319 tem_safe_callback_cls(tem,
2320 tems.ts_c_dimension.width,
2321 row, 0, credp, called_from);
2326 * unblank screen with associated tem from its screen buffer
2328 void
2329 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2330 enum called_from called_from)
2332 text_color_t fg_color, fg_last;
2333 text_color_t bg_color, bg_last;
2334 size_t tc_size = sizeof (text_color_t);
2335 int row, col, count, col_start;
2336 int width;
2337 unsigned char *buf;
2339 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2340 called_from == CALLED_FROM_STANDALONE);
2342 if (tems.ts_display_mode == VIS_PIXEL)
2343 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2345 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2347 width = tems.ts_c_dimension.width;
2350 * Display data in tvs_screen_buf to the actual framebuffer in a
2351 * row by row way.
2352 * When dealing with one row, output data with the same foreground
2353 * and background color all together.
2355 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2356 buf = tem->tvs_screen_buf + (row * width);
2357 count = col_start = 0;
2358 for (col = 0; col < width; col++) {
2359 fg_color =
2360 tem->tvs_fg_buf[(row * width + col) * tc_size];
2361 bg_color =
2362 tem->tvs_bg_buf[(row * width + col) * tc_size];
2363 if (col == 0) {
2364 fg_last = fg_color;
2365 bg_last = bg_color;
2368 if ((fg_color != fg_last) || (bg_color != bg_last)) {
2370 * Call the primitive to render this data.
2372 tem_safe_callback_display(tem,
2373 buf, count, row, col_start,
2374 fg_last, bg_last, credp, called_from);
2375 buf += count;
2376 count = 1;
2377 col_start = col;
2378 fg_last = fg_color;
2379 bg_last = bg_color;
2380 } else {
2381 count++;
2385 if (col_start == (width - 1))
2386 continue;
2389 * Call the primitive to render this data.
2391 tem_safe_callback_display(tem,
2392 buf, count, row, col_start,
2393 fg_last, bg_last, credp, called_from);
2396 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);