tem: light color handling is broken
[unleashed.git] / usr / src / uts / common / io / tem_safe.c
blob63dfe52a344decf051f7186867a37aa148f995aa
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) (pixel32_t)( \
175 cmap4_to_24.red[pix4] << 16 | \
176 cmap4_to_24.green[pix4] << 8 | \
177 cmap4_to_24.blue[pix4])
180 * Fonts are statically linked with this module. At some point an
181 * RFE might be desireable to allow dynamic font loading. The
182 * original intention to facilitate dynamic fonts can be seen
183 * by examining the data structures and set_font(). As much of
184 * the original code is retained but modified to be suited to
185 * traversing a list of static fonts.
187 extern struct fontlist fonts[];
189 #define DEFAULT_FONT_DATA font_data_12x22
191 extern bitmap_data_t font_data_12x22;
192 extern bitmap_data_t font_data_7x14;
193 extern bitmap_data_t font_data_6x10;
195 * Must be sorted by font size in descending order
197 struct fontlist fonts[] = {
198 { &font_data_12x22, NULL },
199 { &font_data_7x14, NULL },
200 { &font_data_6x10, NULL },
201 { NULL, NULL }
204 #define INVERSE(ch) (ch ^ 0xff)
206 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
207 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
208 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
209 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
210 #define tem_safe_callback_bit2pix(tem, c, fg, bg) { \
211 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
212 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c), (fg), (bg));\
215 void
216 tem_safe_check_first_time(
217 struct tem_vt_state *tem,
218 cred_t *credp,
219 enum called_from called_from)
221 static int first_time = 1;
223 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
224 called_from == CALLED_FROM_STANDALONE);
227 * Realign the console cursor. We did this in tem_init().
228 * However, drivers in the console stream may emit additional
229 * messages before we are ready. This causes text overwrite
230 * on the screen. This is a workaround.
232 if (!first_time)
233 return;
235 first_time = 0;
236 if (tems.ts_display_mode == VIS_TEXT) {
237 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
238 tem_safe_align_cursor(tem);
243 * This entry point handles output requests from restricted contexts like
244 * kmdb, where services like mutexes are not available. This function
245 * is entered when OBP or when a kernel debugger (such as kmdb)
246 * are generating console output. In those cases, power management
247 * concerns are handled by the abort sequence initiation (ie. when
248 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
249 * It is also entered when the kernel is panicing.
251 void
252 tem_safe_polled_write(
253 tem_vt_state_t tem_arg,
254 uchar_t *buf,
255 int len)
257 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
259 #ifdef __lock_lint
260 _NOTE(NO_COMPETING_THREADS_NOW)
261 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
262 #endif
264 if (!tem->tvs_initialized) {
265 return;
268 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
269 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
274 * This is the main entry point into the terminal emulator.
276 * For each data message coming downstream, ANSI assumes that it is composed
277 * of ASCII characters, which are treated as a byte-stream input to the
278 * parsing state machine. All data is parsed immediately -- there is
279 * no enqueing.
281 void
282 tem_safe_terminal_emulate(
283 struct tem_vt_state *tem,
284 uchar_t *buf,
285 int len,
286 cred_t *credp,
287 enum called_from called_from)
290 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
291 called_from == CALLED_FROM_STANDALONE);
293 if (tem->tvs_isactive)
294 tem_safe_callback_cursor(tem,
295 VIS_HIDE_CURSOR, credp, called_from);
297 for (; len > 0; len--, buf++)
298 tem_safe_parse(tem, *buf, credp, called_from);
301 * Send the data we just got to the framebuffer.
303 tem_safe_send_data(tem, credp, called_from);
305 if (tem->tvs_isactive)
306 tem_safe_callback_cursor(tem,
307 VIS_DISPLAY_CURSOR, credp, called_from);
311 * Display an rectangular image on the frame buffer using the
312 * mechanism appropriate for the system state being called
313 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
315 static void
316 tems_safe_display(
317 struct vis_consdisplay *pda,
318 cred_t *credp,
319 enum called_from called_from)
321 if (called_from == CALLED_FROM_STANDALONE)
322 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
323 else
324 tems_display_layered(pda, credp);
328 * Copy a rectangle from one location to another on the frame buffer
329 * using the mechanism appropriate for the system state being called
330 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
332 void
333 tems_safe_copy(
334 struct vis_conscopy *pca,
335 cred_t *credp,
336 enum called_from called_from)
338 if (called_from == CALLED_FROM_STANDALONE)
339 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
340 else
341 tems_copy_layered(pca, credp);
345 * Display or hide a rectangular block text cursor of a specificsize
346 * at a specific location on frame buffer* using the mechanism
347 * appropriate for the system state being called from, quisced or
348 * normal (ie. use polled I/O vs. layered ioctls).
350 static void
351 tems_safe_cursor(
352 struct vis_conscursor *pca,
353 cred_t *credp,
354 enum called_from called_from)
356 if (called_from == CALLED_FROM_STANDALONE)
357 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
358 else
359 tems_cursor_layered(pca, credp);
363 * send the appropriate control message or set state based on the
364 * value of the control character ch
367 static void
368 tem_safe_control(
369 struct tem_vt_state *tem,
370 uchar_t ch,
371 cred_t *credp,
372 enum called_from called_from)
374 tem->tvs_state = A_STATE_START;
375 switch (ch) {
376 case A_BEL:
377 tem_safe_bell(tem, called_from);
378 break;
380 case A_BS:
381 tem_safe_mv_cursor(tem,
382 tem->tvs_c_cursor.row,
383 tem->tvs_c_cursor.col - 1,
384 credp, called_from);
385 break;
387 case A_HT:
388 tem_safe_tab(tem, credp, called_from);
389 break;
391 case A_NL:
393 * tem_safe_send_data(tem, credp, called_from);
394 * tem_safe_new_line(tem, credp, called_from);
395 * break;
398 case A_VT:
399 tem_safe_send_data(tem, credp, called_from);
400 tem_safe_lf(tem, credp, called_from);
401 break;
403 case A_FF:
404 tem_safe_send_data(tem, credp, called_from);
405 tem_safe_cls(tem, credp, called_from);
406 break;
408 case A_CR:
409 tem_safe_send_data(tem, credp, called_from);
410 tem_safe_cr(tem);
411 break;
413 case A_ESC:
414 tem->tvs_state = A_STATE_ESC;
415 break;
417 case A_CSI:
419 int i;
420 tem->tvs_curparam = 0;
421 tem->tvs_paramval = 0;
422 tem->tvs_gotparam = B_FALSE;
423 /* clear the parameters */
424 for (i = 0; i < TEM_MAXPARAMS; i++)
425 tem->tvs_params[i] = -1;
426 tem->tvs_state = A_STATE_CSI;
428 break;
430 case A_GS:
431 tem_safe_back_tab(tem, credp, called_from);
432 break;
434 default:
435 break;
441 * if parameters [0..count - 1] are not set, set them to the value
442 * of newparam.
445 static void
446 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
448 int i;
450 for (i = 0; i < count; i++) {
451 if (tem->tvs_params[i] == -1)
452 tem->tvs_params[i] = newparam;
458 * select graphics mode based on the param vals stored in a_params
460 static void
461 tem_safe_selgraph(struct tem_vt_state *tem)
463 int curparam;
464 int count = 0;
465 int param;
467 tem->tvs_state = A_STATE_START;
469 curparam = tem->tvs_curparam;
470 do {
471 param = tem->tvs_params[count];
473 switch (param) {
474 case -1:
475 case 0:
476 /* reset to initial normal settings */
477 tem->tvs_fg_color = tems.ts_init_color.fg_color;
478 tem->tvs_bg_color = tems.ts_init_color.bg_color;
479 tem->tvs_flags = tems.ts_init_color.a_flags;
480 break;
482 case 1: /* Bold Intense */
483 tem->tvs_flags |= TEM_ATTR_BOLD;
484 break;
486 case 2: /* Faint Intense */
487 tem->tvs_flags &= ~TEM_ATTR_BOLD;
488 break;
490 case 5: /* Blink */
491 tem->tvs_flags |= TEM_ATTR_BLINK;
492 break;
494 case 7: /* Reverse video */
495 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
496 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
497 } else {
498 tem->tvs_flags |= TEM_ATTR_REVERSE;
500 break;
502 case 30: /* black (grey) foreground */
503 case 31: /* red (light red) foreground */
504 case 32: /* green (light green) foreground */
505 case 33: /* brown (yellow) foreground */
506 case 34: /* blue (light blue) foreground */
507 case 35: /* magenta (light magenta) foreground */
508 case 36: /* cyan (light cyan) foreground */
509 case 37: /* white (bright white) foreground */
510 tem->tvs_fg_color = param - 30;
511 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
512 break;
514 case 39:
516 * Reset the foreground colour and brightness.
518 tem->tvs_fg_color = tems.ts_init_color.fg_color;
519 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
520 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
521 else
522 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
523 break;
525 case 40: /* black (grey) background */
526 case 41: /* red (light red) background */
527 case 42: /* green (light green) background */
528 case 43: /* brown (yellow) background */
529 case 44: /* blue (light blue) background */
530 case 45: /* magenta (light magenta) background */
531 case 46: /* cyan (light cyan) background */
532 case 47: /* white (bright white) background */
533 tem->tvs_bg_color = param - 40;
534 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
535 break;
537 case 49:
539 * Reset the background colour and brightness.
541 tem->tvs_bg_color = tems.ts_init_color.bg_color;
542 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
543 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
544 else
545 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
546 break;
548 case 90: /* black (grey) foreground */
549 case 91: /* red (light red) foreground */
550 case 92: /* green (light green) foreground */
551 case 93: /* brown (yellow) foreground */
552 case 94: /* blue (light blue) foreground */
553 case 95: /* magenta (light magenta) foreground */
554 case 96: /* cyan (light cyan) foreground */
555 case 97: /* white (bright white) foreground */
556 tem->tvs_fg_color = param - 90;
557 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
558 break;
560 case 100: /* black (grey) background */
561 case 101: /* red (light red) background */
562 case 102: /* green (light green) background */
563 case 103: /* brown (yellow) background */
564 case 104: /* blue (light blue) background */
565 case 105: /* magenta (light magenta) background */
566 case 106: /* cyan (light cyan) background */
567 case 107: /* white (bright white) background */
568 tem->tvs_bg_color = param - 100;
569 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
570 break;
572 default:
573 break;
575 count++;
576 curparam--;
578 } while (curparam > 0);
582 * perform the appropriate action for the escape sequence
584 * General rule: This code does not validate the arguments passed.
585 * It assumes that the next lower level will do so.
587 static void
588 tem_safe_chkparam(
589 struct tem_vt_state *tem,
590 uchar_t ch,
591 cred_t *credp,
592 enum called_from called_from)
594 int i;
595 int row;
596 int col;
598 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
599 MUTEX_HELD(&tem->tvs_lock));
601 row = tem->tvs_c_cursor.row;
602 col = tem->tvs_c_cursor.col;
604 switch (ch) {
606 case 'm': /* select terminal graphics mode */
607 tem_safe_send_data(tem, credp, called_from);
608 tem_safe_selgraph(tem);
609 break;
611 case '@': /* insert char */
612 tem_safe_setparam(tem, 1, 1);
613 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
614 credp, called_from);
615 break;
617 case 'A': /* cursor up */
618 tem_safe_setparam(tem, 1, 1);
619 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
620 credp, called_from);
621 break;
623 case 'd': /* VPA - vertical position absolute */
624 tem_safe_setparam(tem, 1, 1);
625 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
626 credp, called_from);
627 break;
629 case 'e': /* VPR - vertical position relative */
630 case 'B': /* cursor down */
631 tem_safe_setparam(tem, 1, 1);
632 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
633 credp, called_from);
634 break;
636 case 'a': /* HPR - horizontal position relative */
637 case 'C': /* cursor right */
638 tem_safe_setparam(tem, 1, 1);
639 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
640 credp, called_from);
641 break;
643 case '`': /* HPA - horizontal position absolute */
644 tem_safe_setparam(tem, 1, 1);
645 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
646 credp, called_from);
647 break;
649 case 'D': /* cursor left */
650 tem_safe_setparam(tem, 1, 1);
651 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
652 credp, called_from);
653 break;
655 case 'E': /* CNL cursor next line */
656 tem_safe_setparam(tem, 1, 1);
657 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
658 credp, called_from);
659 break;
661 case 'F': /* CPL cursor previous line */
662 tem_safe_setparam(tem, 1, 1);
663 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
664 credp, called_from);
665 break;
667 case 'G': /* cursor horizontal position */
668 tem_safe_setparam(tem, 1, 1);
669 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
670 credp, called_from);
671 break;
673 case 'g': /* clear tabs */
674 tem_safe_setparam(tem, 1, 0);
675 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
676 break;
678 case 'f': /* HVP Horizontal and Vertical Position */
679 case 'H': /* CUP position cursor */
680 tem_safe_setparam(tem, 2, 1);
681 tem_safe_mv_cursor(tem,
682 tem->tvs_params[0] - 1,
683 tem->tvs_params[1] - 1,
684 credp, called_from);
685 break;
687 case 'I': /* CHT - Cursor Horizontal Tab */
688 /* Not implemented */
689 break;
691 case 'J': /* ED - Erase in Display */
692 tem_safe_send_data(tem, credp, called_from);
693 tem_safe_setparam(tem, 1, 0);
694 switch (tem->tvs_params[0]) {
695 case 0:
696 /* erase cursor to end of screen */
697 /* FIRST erase cursor to end of line */
698 tem_safe_clear_chars(tem,
699 tems.ts_c_dimension.width -
700 tem->tvs_c_cursor.col,
701 tem->tvs_c_cursor.row,
702 tem->tvs_c_cursor.col, credp, called_from);
704 /* THEN erase lines below the cursor */
705 for (row = tem->tvs_c_cursor.row + 1;
706 row < tems.ts_c_dimension.height;
707 row++) {
708 tem_safe_clear_chars(tem,
709 tems.ts_c_dimension.width,
710 row, 0, credp, called_from);
712 break;
714 case 1:
715 /* erase beginning of screen to cursor */
716 /* FIRST erase lines above the cursor */
717 for (row = 0;
718 row < tem->tvs_c_cursor.row;
719 row++) {
720 tem_safe_clear_chars(tem,
721 tems.ts_c_dimension.width,
722 row, 0, credp, called_from);
724 /* THEN erase beginning of line to cursor */
725 tem_safe_clear_chars(tem,
726 tem->tvs_c_cursor.col + 1,
727 tem->tvs_c_cursor.row,
728 0, credp, called_from);
729 break;
731 case 2:
732 /* erase whole screen */
733 for (row = 0;
734 row < tems.ts_c_dimension.height;
735 row++) {
736 tem_safe_clear_chars(tem,
737 tems.ts_c_dimension.width,
738 row, 0, credp, called_from);
740 break;
742 break;
744 case 'K': /* EL - Erase in Line */
745 tem_safe_send_data(tem, credp, called_from);
746 tem_safe_setparam(tem, 1, 0);
747 switch (tem->tvs_params[0]) {
748 case 0:
749 /* erase cursor to end of line */
750 tem_safe_clear_chars(tem,
751 (tems.ts_c_dimension.width -
752 tem->tvs_c_cursor.col),
753 tem->tvs_c_cursor.row,
754 tem->tvs_c_cursor.col,
755 credp, called_from);
756 break;
758 case 1:
759 /* erase beginning of line to cursor */
760 tem_safe_clear_chars(tem,
761 tem->tvs_c_cursor.col + 1,
762 tem->tvs_c_cursor.row,
763 0, credp, called_from);
764 break;
766 case 2:
767 /* erase whole line */
768 tem_safe_clear_chars(tem,
769 tems.ts_c_dimension.width,
770 tem->tvs_c_cursor.row,
771 0, credp, called_from);
772 break;
774 break;
776 case 'L': /* insert line */
777 tem_safe_send_data(tem, credp, called_from);
778 tem_safe_setparam(tem, 1, 1);
779 tem_safe_scroll(tem,
780 tem->tvs_c_cursor.row,
781 tems.ts_c_dimension.height - 1,
782 tem->tvs_params[0], TEM_SCROLL_DOWN,
783 credp, called_from);
784 break;
786 case 'M': /* delete line */
787 tem_safe_send_data(tem, credp, called_from);
788 tem_safe_setparam(tem, 1, 1);
789 tem_safe_scroll(tem,
790 tem->tvs_c_cursor.row,
791 tems.ts_c_dimension.height - 1,
792 tem->tvs_params[0], TEM_SCROLL_UP,
793 credp, called_from);
794 break;
796 case 'P': /* DCH - delete char */
797 tem_safe_setparam(tem, 1, 1);
798 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
799 credp, called_from);
800 break;
802 case 'S': /* scroll up */
803 tem_safe_send_data(tem, credp, called_from);
804 tem_safe_setparam(tem, 1, 1);
805 tem_safe_scroll(tem, 0,
806 tems.ts_c_dimension.height - 1,
807 tem->tvs_params[0], TEM_SCROLL_UP,
808 credp, called_from);
809 break;
811 case 'T': /* scroll down */
812 tem_safe_send_data(tem, credp, called_from);
813 tem_safe_setparam(tem, 1, 1);
814 tem_safe_scroll(tem, 0,
815 tems.ts_c_dimension.height - 1,
816 tem->tvs_params[0], TEM_SCROLL_DOWN,
817 credp, called_from);
818 break;
820 case 'X': /* erase char */
821 tem_safe_setparam(tem, 1, 1);
822 tem_safe_clear_chars(tem,
823 tem->tvs_params[0],
824 tem->tvs_c_cursor.row,
825 tem->tvs_c_cursor.col,
826 credp, called_from);
827 break;
829 case 'Z': /* cursor backward tabulation */
830 tem_safe_setparam(tem, 1, 1);
833 * Rule exception - We do sanity checking here.
835 * Restrict the count to a sane value to keep from
836 * looping for a long time. There can't be more than one
837 * tab stop per column, so use that as a limit.
839 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
840 tem->tvs_params[0] = tems.ts_c_dimension.width;
842 for (i = 0; i < tem->tvs_params[0]; i++)
843 tem_safe_back_tab(tem, credp, called_from);
844 break;
846 tem->tvs_state = A_STATE_START;
851 * Gather the parameters of an ANSI escape sequence
853 static void
854 tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
855 cred_t *credp, enum called_from called_from)
857 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
858 MUTEX_HELD(&tem->tvs_lock));
860 if (ch >= '0' && ch <= '9') {
861 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
862 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
863 return; /* Return immediately */
864 } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
865 tem->tvs_state == A_STATE_CSI_QMARK) {
866 tem->tvs_state = A_STATE_START;
867 } else {
868 if (tem->tvs_curparam < TEM_MAXPARAMS) {
869 if (tem->tvs_gotparam) {
870 /* get the parameter value */
871 tem->tvs_params[tem->tvs_curparam] =
872 tem->tvs_paramval;
874 tem->tvs_curparam++;
877 if (ch == ';') {
878 /* Restart parameter search */
879 tem->tvs_gotparam = B_FALSE;
880 tem->tvs_paramval = 0; /* No parame value yet */
881 } else {
882 /* Handle escape sequence */
883 tem_safe_chkparam(tem, ch, credp, called_from);
889 * Add character to internal buffer.
890 * When its full, send it to the next layer.
893 static void
894 tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
895 cred_t *credp, enum called_from called_from)
898 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
899 called_from == CALLED_FROM_STANDALONE);
901 /* buffer up the character until later */
903 tem->tvs_outbuf[tem->tvs_outindex++] = ch;
904 tem->tvs_c_cursor.col++;
905 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
906 tem_safe_send_data(tem, credp, called_from);
907 tem_safe_new_line(tem, credp, called_from);
911 static void
912 tem_safe_new_line(struct tem_vt_state *tem,
913 cred_t *credp, enum called_from called_from)
915 tem_safe_cr(tem);
916 tem_safe_lf(tem, credp, called_from);
919 static void
920 tem_safe_cr(struct tem_vt_state *tem)
922 tem->tvs_c_cursor.col = 0;
923 tem_safe_align_cursor(tem);
926 static void
927 tem_safe_lf(struct tem_vt_state *tem,
928 cred_t *credp, enum called_from called_from)
930 int row;
932 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
933 MUTEX_HELD(&tem->tvs_lock));
936 * Sanity checking notes:
937 * . a_nscroll was validated when it was set.
938 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
939 * will prevent anything bad from happening.
941 row = tem->tvs_c_cursor.row + 1;
943 if (row >= tems.ts_c_dimension.height) {
944 if (tem->tvs_nscroll != 0) {
945 tem_safe_scroll(tem, 0,
946 tems.ts_c_dimension.height - 1,
947 tem->tvs_nscroll, TEM_SCROLL_UP,
948 credp, called_from);
949 row = tems.ts_c_dimension.height -
950 tem->tvs_nscroll;
951 } else { /* no scroll */
953 * implement Esc[#r when # is zero. This means no
954 * scroll but just return cursor to top of screen,
955 * do not clear screen.
957 row = 0;
961 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
962 credp, called_from);
964 if (tem->tvs_nscroll == 0) {
965 /* erase rest of cursor line */
966 tem_safe_clear_chars(tem,
967 tems.ts_c_dimension.width -
968 tem->tvs_c_cursor.col,
969 tem->tvs_c_cursor.row,
970 tem->tvs_c_cursor.col,
971 credp, called_from);
975 tem_safe_align_cursor(tem);
978 static void
979 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
980 enum called_from called_from)
982 text_color_t fg_color;
983 text_color_t bg_color;
985 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
986 MUTEX_HELD(&tem->tvs_lock));
988 if (tem->tvs_outindex == 0) {
989 tem_safe_align_cursor(tem);
990 return;
993 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_REVERSE);
994 tem_safe_virtual_display(tem,
995 tem->tvs_outbuf, tem->tvs_outindex,
996 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
997 fg_color, bg_color);
999 if (tem->tvs_isactive) {
1001 * Call the primitive to render this data.
1003 tem_safe_callback_display(tem,
1004 tem->tvs_outbuf, tem->tvs_outindex,
1005 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1006 fg_color, bg_color,
1007 credp, called_from);
1010 tem->tvs_outindex = 0;
1012 tem_safe_align_cursor(tem);
1017 * We have just done something to the current output point. Reset the start
1018 * point for the buffered data in a_outbuf. There shouldn't be any data
1019 * buffered yet.
1021 static void
1022 tem_safe_align_cursor(struct tem_vt_state *tem)
1024 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1025 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1029 * State machine parser based on the current state and character input
1030 * major terminations are to control character or normal character
1033 static void
1034 tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
1035 cred_t *credp, enum called_from called_from)
1037 int i;
1039 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1040 MUTEX_HELD(&tem->tvs_lock));
1042 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1043 if (ch == A_CSI || ch == A_ESC || ch < ' ') {
1044 /* Control */
1045 tem_safe_control(tem, ch, credp, called_from);
1046 } else {
1047 /* Display */
1048 tem_safe_outch(tem, ch, credp, called_from);
1050 return;
1053 /* In <ESC> sequence */
1054 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1055 if (tem->tvs_state != A_STATE_CSI) {
1056 tem_safe_getparams(tem, ch, credp, called_from);
1057 return;
1060 switch (ch) {
1061 case '?':
1062 tem->tvs_state = A_STATE_CSI_QMARK;
1063 return;
1064 case '=':
1065 tem->tvs_state = A_STATE_CSI_EQUAL;
1066 return;
1067 case 's':
1069 * As defined below, this sequence
1070 * saves the cursor. However, Sun
1071 * defines ESC[s as reset. We resolved
1072 * the conflict by selecting reset as it
1073 * is exported in the termcap file for
1074 * sun-mon, while the "save cursor"
1075 * definition does not exist anywhere in
1076 * /etc/termcap.
1077 * However, having no coherent
1078 * definition of reset, we have not
1079 * implemented it.
1083 * Original code
1084 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1085 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1086 * tem->tvs_state = A_STATE_START;
1089 tem->tvs_state = A_STATE_START;
1090 return;
1091 case 'u':
1092 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1093 tem->tvs_r_cursor.col, credp, called_from);
1094 tem->tvs_state = A_STATE_START;
1095 return;
1096 case 'p': /* sunbow */
1097 tem_safe_send_data(tem, credp, called_from);
1099 * Don't set anything if we are
1100 * already as we want to be.
1102 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1103 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1105 * If we have switched the characters to be the
1106 * inverse from the screen, then switch them as
1107 * well to keep them the inverse of the screen.
1109 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1110 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1111 else
1112 tem->tvs_flags |= TEM_ATTR_REVERSE;
1114 tem_safe_cls(tem, credp, called_from);
1115 tem->tvs_state = A_STATE_START;
1116 return;
1117 case 'q': /* sunwob */
1118 tem_safe_send_data(tem, credp, called_from);
1120 * Don't set anything if we are
1121 * already where as we want to be.
1123 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1124 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1126 * If we have switched the characters to be the
1127 * inverse from the screen, then switch them as
1128 * well to keep them the inverse of the screen.
1130 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1131 tem->tvs_flags |= TEM_ATTR_REVERSE;
1132 else
1133 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1136 tem_safe_cls(tem, credp, called_from);
1137 tem->tvs_state = A_STATE_START;
1138 return;
1139 case 'r': /* sunscrl */
1141 * Rule exception: check for validity here.
1143 tem->tvs_nscroll = tem->tvs_paramval;
1144 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
1145 tem->tvs_nscroll = tems.ts_c_dimension.height;
1146 if (tem->tvs_nscroll < 0)
1147 tem->tvs_nscroll = 1;
1148 tem->tvs_state = A_STATE_START;
1149 return;
1150 default:
1151 tem_safe_getparams(tem, ch, credp, called_from);
1152 return;
1156 /* Previous char was <ESC> */
1157 if (ch == '[') {
1158 tem->tvs_curparam = 0;
1159 tem->tvs_paramval = 0;
1160 tem->tvs_gotparam = B_FALSE;
1161 /* clear the parameters */
1162 for (i = 0; i < TEM_MAXPARAMS; i++)
1163 tem->tvs_params[i] = -1;
1164 tem->tvs_state = A_STATE_CSI;
1165 } else if (ch == 'Q') { /* <ESC>Q ? */
1166 tem->tvs_state = A_STATE_START;
1167 } else if (ch == 'C') { /* <ESC>C ? */
1168 tem->tvs_state = A_STATE_START;
1169 } else {
1170 tem->tvs_state = A_STATE_START;
1171 if (ch == 'c') {
1172 /* ESC c resets display */
1173 tem_safe_reset_display(tem, credp, called_from,
1174 B_TRUE, B_TRUE);
1175 } else if (ch == 'H') {
1176 /* ESC H sets a tab */
1177 tem_safe_set_tab(tem);
1178 } else if (ch == '7') {
1179 /* ESC 7 Save Cursor position */
1180 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1181 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1182 } else if (ch == '8') {
1183 /* ESC 8 Restore Cursor position */
1184 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1185 tem->tvs_r_cursor.col, credp, called_from);
1186 /* check for control chars */
1187 } else if (ch < ' ') {
1188 tem_safe_control(tem, ch, credp, called_from);
1189 } else {
1190 tem_safe_outch(tem, ch, credp, called_from);
1195 /* ARGSUSED */
1196 static void
1197 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1199 if (called_from == CALLED_FROM_STANDALONE)
1200 (void) beep_polled(BEEP_CONSOLE);
1201 else
1202 (void) beep(BEEP_CONSOLE);
1206 static void
1207 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1208 int direction, cred_t *credp, enum called_from called_from)
1210 int row;
1211 int lines_affected;
1213 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1214 called_from == CALLED_FROM_STANDALONE);
1216 lines_affected = end - start + 1;
1217 if (count > lines_affected)
1218 count = lines_affected;
1219 if (count <= 0)
1220 return;
1222 switch (direction) {
1223 case TEM_SCROLL_UP:
1224 if (count < lines_affected) {
1225 tem_safe_copy_area(tem, 0, start + count,
1226 tems.ts_c_dimension.width - 1, end,
1227 0, start, credp, called_from);
1229 for (row = (end - count) + 1; row <= end; row++) {
1230 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1231 row, 0, credp, called_from);
1233 break;
1235 case TEM_SCROLL_DOWN:
1236 if (count < lines_affected) {
1237 tem_safe_copy_area(tem, 0, start,
1238 tems.ts_c_dimension.width - 1,
1239 end - count, 0, start + count,
1240 credp, called_from);
1242 for (row = start; row < start + count; row++) {
1243 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1244 row, 0, credp, called_from);
1246 break;
1250 static void
1251 tem_safe_copy_area(struct tem_vt_state *tem,
1252 screen_pos_t s_col, screen_pos_t s_row,
1253 screen_pos_t e_col, screen_pos_t e_row,
1254 screen_pos_t t_col, screen_pos_t t_row,
1255 cred_t *credp, enum called_from called_from)
1257 int rows;
1258 int cols;
1260 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1261 called_from == CALLED_FROM_STANDALONE);
1263 if (s_col < 0 || s_row < 0 ||
1264 e_col < 0 || e_row < 0 ||
1265 t_col < 0 || t_row < 0 ||
1266 s_col >= tems.ts_c_dimension.width ||
1267 e_col >= tems.ts_c_dimension.width ||
1268 t_col >= tems.ts_c_dimension.width ||
1269 s_row >= tems.ts_c_dimension.height ||
1270 e_row >= tems.ts_c_dimension.height ||
1271 t_row >= tems.ts_c_dimension.height)
1272 return;
1274 if (s_row > e_row || s_col > e_col)
1275 return;
1277 rows = e_row - s_row + 1;
1278 cols = e_col - s_col + 1;
1279 if (t_row + rows > tems.ts_c_dimension.height ||
1280 t_col + cols > tems.ts_c_dimension.width)
1281 return;
1283 tem_safe_virtual_copy(tem,
1284 s_col, s_row,
1285 e_col, e_row,
1286 t_col, t_row);
1288 if (!tem->tvs_isactive)
1289 return;
1291 tem_safe_callback_copy(tem, s_col, s_row,
1292 e_col, e_row, t_col, t_row, credp, called_from);
1295 static void
1296 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1297 screen_pos_t col, cred_t *credp, enum called_from called_from)
1299 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1300 called_from == CALLED_FROM_STANDALONE);
1302 if (row < 0 || row >= tems.ts_c_dimension.height ||
1303 col < 0 || col >= tems.ts_c_dimension.width ||
1304 count < 0)
1305 return;
1308 * Note that very large values of "count" could cause col+count
1309 * to overflow, so we check "count" independently.
1311 if (count > tems.ts_c_dimension.width ||
1312 col + count > tems.ts_c_dimension.width)
1313 count = tems.ts_c_dimension.width - col;
1315 tem_safe_virtual_cls(tem, count, row, col);
1317 if (!tem->tvs_isactive)
1318 return;
1320 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1323 /*ARGSUSED*/
1324 void
1325 tem_safe_text_display(struct tem_vt_state *tem, uchar_t *string,
1326 int count, screen_pos_t row, screen_pos_t col,
1327 text_color_t fg_color, text_color_t bg_color,
1328 cred_t *credp, enum called_from called_from)
1330 struct vis_consdisplay da;
1332 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1333 called_from == CALLED_FROM_STANDALONE);
1335 da.data = string;
1336 da.width = (screen_size_t)count;
1337 da.row = row;
1338 da.col = col;
1340 da.fg_color = fg_color;
1341 da.bg_color = bg_color;
1343 tems_safe_display(&da, credp, called_from);
1347 * This function is used to blit a rectangular color image,
1348 * unperturbed on the underlying framebuffer, to render
1349 * icons and pictures. The data is a pixel pattern that
1350 * fills a rectangle bounded to the width and height parameters.
1351 * The color pixel data must to be pre-adjusted by the caller
1352 * for the current video depth.
1354 * This function is unused now.
1356 /*ARGSUSED*/
1357 static void
1358 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1359 int height, int width, screen_pos_t row, screen_pos_t col,
1360 cred_t *credp, enum called_from called_from)
1362 struct vis_consdisplay da;
1364 mutex_enter(&tems.ts_lock);
1365 mutex_enter(&tem->tvs_lock);
1367 da.data = image;
1368 da.width = (screen_size_t)width;
1369 da.height = (screen_size_t)height;
1370 da.row = row;
1371 da.col = col;
1373 tems_safe_display(&da, credp, called_from);
1375 mutex_exit(&tem->tvs_lock);
1376 mutex_exit(&tems.ts_lock);
1380 /*ARGSUSED*/
1381 void
1382 tem_safe_text_copy(struct tem_vt_state *tem,
1383 screen_pos_t s_col, screen_pos_t s_row,
1384 screen_pos_t e_col, screen_pos_t e_row,
1385 screen_pos_t t_col, screen_pos_t t_row,
1386 cred_t *credp, enum called_from called_from)
1388 struct vis_conscopy da;
1390 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1391 called_from == CALLED_FROM_STANDALONE);
1393 da.s_row = s_row;
1394 da.s_col = s_col;
1395 da.e_row = e_row;
1396 da.e_col = e_col;
1397 da.t_row = t_row;
1398 da.t_col = t_col;
1400 tems_safe_copy(&da, credp, called_from);
1403 void
1404 tem_safe_text_cls(struct tem_vt_state *tem,
1405 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1406 enum called_from called_from)
1408 struct vis_consdisplay da;
1410 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1411 called_from == CALLED_FROM_STANDALONE);
1413 da.data = tems.ts_blank_line;
1414 da.width = (screen_size_t)count;
1415 da.row = row;
1416 da.col = col;
1418 tem_safe_get_color(tem, &da.fg_color, &da.bg_color,
1419 TEM_ATTR_SCREEN_REVERSE);
1420 tems_safe_display(&da, credp, called_from);
1425 void
1426 tem_safe_pix_display(struct tem_vt_state *tem,
1427 uchar_t *string, int count,
1428 screen_pos_t row, screen_pos_t col,
1429 text_color_t fg_color, text_color_t bg_color,
1430 cred_t *credp, enum called_from called_from)
1432 struct vis_consdisplay da;
1433 int i;
1435 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1436 called_from == CALLED_FROM_STANDALONE);
1438 da.data = (uchar_t *)tem->tvs_pix_data;
1439 da.width = tems.ts_font.width;
1440 da.height = tems.ts_font.height;
1441 da.row = (row * da.height) + tems.ts_p_offset.y;
1442 da.col = (col * da.width) + tems.ts_p_offset.x;
1444 for (i = 0; i < count; i++) {
1445 tem_safe_callback_bit2pix(tem, string[i], fg_color, bg_color);
1446 tems_safe_display(&da, credp, called_from);
1447 da.col += da.width;
1451 void
1452 tem_safe_pix_copy(struct tem_vt_state *tem,
1453 screen_pos_t s_col, screen_pos_t s_row,
1454 screen_pos_t e_col, screen_pos_t e_row,
1455 screen_pos_t t_col, screen_pos_t t_row,
1456 cred_t *credp,
1457 enum called_from called_from)
1459 struct vis_conscopy ma;
1460 static boolean_t need_clear = B_TRUE;
1462 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1463 called_from == CALLED_FROM_STANDALONE);
1465 if (need_clear && tem->tvs_first_line > 0) {
1467 * Clear OBP output above our kernel console term
1468 * when our kernel console term begins to scroll up,
1469 * we hope it is user friendly.
1470 * (Also see comments on tem_safe_pix_clear_prom_output)
1472 * This is only one time call.
1474 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1476 need_clear = B_FALSE;
1478 ma.s_row = s_row * tems.ts_font.height + tems.ts_p_offset.y;
1479 ma.e_row = (e_row + 1) * tems.ts_font.height + tems.ts_p_offset.y - 1;
1480 ma.t_row = t_row * tems.ts_font.height + tems.ts_p_offset.y;
1483 * Check if we're in process of clearing OBP's columns area,
1484 * which only happens when term scrolls up a whole line.
1486 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1487 e_col == tems.ts_c_dimension.width - 1) {
1489 * We need to clear OBP's columns area outside our kernel
1490 * console term. So that we set ma.e_col to entire row here.
1492 ma.s_col = s_col * tems.ts_font.width;
1493 ma.e_col = tems.ts_p_dimension.width - 1;
1495 ma.t_col = t_col * tems.ts_font.width;
1496 } else {
1497 ma.s_col = s_col * tems.ts_font.width + tems.ts_p_offset.x;
1498 ma.e_col = (e_col + 1) * tems.ts_font.width +
1499 tems.ts_p_offset.x - 1;
1500 ma.t_col = t_col * tems.ts_font.width + tems.ts_p_offset.x;
1503 tems_safe_copy(&ma, credp, called_from);
1505 if (tem->tvs_first_line > 0 && t_row < s_row) {
1506 /* We have scrolled up (s_row - t_row) rows. */
1507 tem->tvs_first_line -= (s_row - t_row);
1508 if (tem->tvs_first_line <= 0) {
1509 /* All OBP rows have been cleared. */
1510 tem->tvs_first_line = 0;
1516 void
1517 tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
1518 unsigned char fg, unsigned char bg)
1520 void (*fp)(struct tem_vt_state *, unsigned char,
1521 unsigned char, unsigned char);
1523 switch (tems.ts_pdepth) {
1524 case 4:
1525 fp = bit_to_pix4;
1526 break;
1527 case 8:
1528 fp = bit_to_pix8;
1529 break;
1530 case 24:
1531 case 32:
1532 fp = bit_to_pix24;
1535 fp(tem, c, fg, bg);
1540 * This function only clears count of columns in one row
1542 void
1543 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
1544 screen_pos_t row, screen_pos_t col, cred_t *credp,
1545 enum called_from called_from)
1547 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1548 called_from == CALLED_FROM_STANDALONE);
1550 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
1551 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
1555 * This function clears OBP output above our kernel console term area
1556 * because OBP's term may have a bigger terminal window than that of
1557 * our kernel console term. So we need to clear OBP output garbage outside
1558 * of our kernel console term at a proper time, which is when the first
1559 * row output of our kernel console term scrolls at the first screen line.
1561 * _________________________________
1562 * | _____________________ | ---> OBP's bigger term window
1563 * | | | |
1564 * |___| | |
1565 * | | | | |
1566 * | | | | |
1567 * |_|_|___________________|_______|
1568 * | | | ---> first line
1569 * | |___________________|---> our kernel console term window
1571 * |---> columns area to be cleared
1573 * This function only takes care of the output above our kernel console term,
1574 * and tem_prom_scroll_up takes care of columns area outside of our kernel
1575 * console term.
1577 static void
1578 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1579 enum called_from called_from)
1581 int nrows, ncols, width, height;
1583 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1584 called_from == CALLED_FROM_STANDALONE);
1586 width = tems.ts_font.width;
1587 height = tems.ts_font.height;
1589 nrows = (tems.ts_p_offset.y + (height - 1))/ height;
1590 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1592 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1593 B_FALSE, credp, called_from);
1597 * clear the whole screen for pixel mode, just clear the
1598 * physical screen.
1600 void
1601 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1602 enum called_from called_from)
1604 int nrows, ncols, width, height;
1606 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1607 called_from == CALLED_FROM_STANDALONE);
1609 width = tems.ts_font.width;
1610 height = tems.ts_font.height;
1612 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1613 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1615 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1616 B_FALSE, credp, called_from);
1619 * Since the whole screen is cleared, we don't need
1620 * to clear OBP output later.
1622 if (tem->tvs_first_line > 0)
1623 tem->tvs_first_line = 0;
1627 * clear the whole screen, including the virtual screen buffer,
1628 * and reset the cursor to start point.
1630 static void
1631 tem_safe_cls(struct tem_vt_state *tem,
1632 cred_t *credp, enum called_from called_from)
1634 int row;
1636 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1637 called_from == CALLED_FROM_STANDALONE);
1639 if (tems.ts_display_mode == VIS_TEXT) {
1640 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1641 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1642 row, 0, credp, called_from);
1644 tem->tvs_c_cursor.row = 0;
1645 tem->tvs_c_cursor.col = 0;
1646 tem_safe_align_cursor(tem);
1647 return;
1650 ASSERT(tems.ts_display_mode == VIS_PIXEL);
1652 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1653 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
1655 tem->tvs_c_cursor.row = 0;
1656 tem->tvs_c_cursor.col = 0;
1657 tem_safe_align_cursor(tem);
1659 if (!tem->tvs_isactive)
1660 return;
1662 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
1665 static void
1666 tem_safe_back_tab(struct tem_vt_state *tem,
1667 cred_t *credp, enum called_from called_from)
1669 int i;
1670 screen_pos_t tabstop;
1672 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1673 called_from == CALLED_FROM_STANDALONE);
1675 tabstop = 0;
1677 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
1678 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
1679 tabstop = tem->tvs_tabs[i];
1680 break;
1684 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1685 tabstop, credp, called_from);
1688 static void
1689 tem_safe_tab(struct tem_vt_state *tem,
1690 cred_t *credp, enum called_from called_from)
1692 int i;
1693 screen_pos_t tabstop;
1695 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1696 called_from == CALLED_FROM_STANDALONE);
1698 tabstop = tems.ts_c_dimension.width - 1;
1700 for (i = 0; i < tem->tvs_ntabs; i++) {
1701 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1702 tabstop = tem->tvs_tabs[i];
1703 break;
1707 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1708 tabstop, credp, called_from);
1711 static void
1712 tem_safe_set_tab(struct tem_vt_state *tem)
1714 int i;
1715 int j;
1717 if (tem->tvs_ntabs == TEM_MAXTAB)
1718 return;
1719 if (tem->tvs_ntabs == 0 ||
1720 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
1721 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
1722 return;
1724 for (i = 0; i < tem->tvs_ntabs; i++) {
1725 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
1726 return;
1727 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1728 for (j = tem->tvs_ntabs - 1; j >= i; j--)
1729 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
1730 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
1731 tem->tvs_ntabs++;
1732 return;
1737 static void
1738 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
1740 int i;
1741 int j;
1743 switch (action) {
1744 case 3: /* clear all tabs */
1745 tem->tvs_ntabs = 0;
1746 break;
1747 case 0: /* clr tab at cursor */
1749 for (i = 0; i < tem->tvs_ntabs; i++) {
1750 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
1751 tem->tvs_ntabs--;
1752 for (j = i; j < tem->tvs_ntabs; j++)
1753 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
1754 return;
1757 break;
1761 static void
1762 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
1763 cred_t *credp, enum called_from called_from)
1765 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1766 called_from == CALLED_FROM_STANDALONE);
1769 * Sanity check and bounds enforcement. Out of bounds requests are
1770 * clipped to the screen boundaries. This seems to be what SPARC
1771 * does.
1773 if (row < 0)
1774 row = 0;
1775 if (row >= tems.ts_c_dimension.height)
1776 row = tems.ts_c_dimension.height - 1;
1777 if (col < 0)
1778 col = 0;
1779 if (col >= tems.ts_c_dimension.width)
1780 col = tems.ts_c_dimension.width - 1;
1782 tem_safe_send_data(tem, credp, called_from);
1783 tem->tvs_c_cursor.row = (screen_pos_t)row;
1784 tem->tvs_c_cursor.col = (screen_pos_t)col;
1785 tem_safe_align_cursor(tem);
1788 /* ARGSUSED */
1789 void
1790 tem_safe_reset_emulator(struct tem_vt_state *tem,
1791 cred_t *credp, enum called_from called_from,
1792 boolean_t init_color)
1794 int j;
1796 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1797 called_from == CALLED_FROM_STANDALONE);
1799 tem->tvs_c_cursor.row = 0;
1800 tem->tvs_c_cursor.col = 0;
1801 tem->tvs_r_cursor.row = 0;
1802 tem->tvs_r_cursor.col = 0;
1803 tem->tvs_s_cursor.row = 0;
1804 tem->tvs_s_cursor.col = 0;
1805 tem->tvs_outindex = 0;
1806 tem->tvs_state = A_STATE_START;
1807 tem->tvs_gotparam = B_FALSE;
1808 tem->tvs_curparam = 0;
1809 tem->tvs_paramval = 0;
1810 tem->tvs_nscroll = 1;
1812 if (init_color) {
1813 /* use initial settings */
1814 tem->tvs_fg_color = tems.ts_init_color.fg_color;
1815 tem->tvs_bg_color = tems.ts_init_color.bg_color;
1816 tem->tvs_flags = tems.ts_init_color.a_flags;
1820 * set up the initial tab stops
1822 tem->tvs_ntabs = 0;
1823 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
1824 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
1826 for (j = 0; j < TEM_MAXPARAMS; j++)
1827 tem->tvs_params[j] = 0;
1830 void
1831 tem_safe_reset_display(struct tem_vt_state *tem,
1832 cred_t *credp, enum called_from called_from,
1833 boolean_t clear_txt, boolean_t init_color)
1835 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1836 called_from == CALLED_FROM_STANDALONE);
1838 tem_safe_reset_emulator(tem, credp, called_from, init_color);
1840 if (clear_txt) {
1841 if (tem->tvs_isactive)
1842 tem_safe_callback_cursor(tem,
1843 VIS_HIDE_CURSOR, credp, called_from);
1845 tem_safe_cls(tem, credp, called_from);
1847 if (tem->tvs_isactive)
1848 tem_safe_callback_cursor(tem,
1849 VIS_DISPLAY_CURSOR, credp, called_from);
1853 static void
1854 tem_safe_shift(
1855 struct tem_vt_state *tem,
1856 int count,
1857 int direction,
1858 cred_t *credp,
1859 enum called_from called_from)
1861 int rest_of_line;
1863 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1864 called_from == CALLED_FROM_STANDALONE);
1866 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
1867 if (count > rest_of_line)
1868 count = rest_of_line;
1870 if (count <= 0)
1871 return;
1873 switch (direction) {
1874 case TEM_SHIFT_LEFT:
1875 if (count < rest_of_line) {
1876 tem_safe_copy_area(tem,
1877 tem->tvs_c_cursor.col + count,
1878 tem->tvs_c_cursor.row,
1879 tems.ts_c_dimension.width - 1,
1880 tem->tvs_c_cursor.row,
1881 tem->tvs_c_cursor.col,
1882 tem->tvs_c_cursor.row,
1883 credp, called_from);
1886 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1887 (tems.ts_c_dimension.width - count), credp,
1888 called_from);
1889 break;
1890 case TEM_SHIFT_RIGHT:
1891 if (count < rest_of_line) {
1892 tem_safe_copy_area(tem,
1893 tem->tvs_c_cursor.col,
1894 tem->tvs_c_cursor.row,
1895 tems.ts_c_dimension.width - count - 1,
1896 tem->tvs_c_cursor.row,
1897 tem->tvs_c_cursor.col + count,
1898 tem->tvs_c_cursor.row,
1899 credp, called_from);
1902 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1903 tem->tvs_c_cursor.col, credp, called_from);
1904 break;
1908 void
1909 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
1910 cred_t *credp, enum called_from called_from)
1912 struct vis_conscursor ca;
1914 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1915 called_from == CALLED_FROM_STANDALONE);
1917 ca.row = tem->tvs_c_cursor.row;
1918 ca.col = tem->tvs_c_cursor.col;
1919 ca.action = action;
1921 tems_safe_cursor(&ca, credp, called_from);
1923 if (action == VIS_GET_CURSOR) {
1924 tem->tvs_c_cursor.row = ca.row;
1925 tem->tvs_c_cursor.col = ca.col;
1929 void
1930 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
1931 cred_t *credp, enum called_from called_from)
1933 struct vis_conscursor ca;
1935 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1936 called_from == CALLED_FROM_STANDALONE);
1938 ca.row = tem->tvs_c_cursor.row * tems.ts_font.height +
1939 tems.ts_p_offset.y;
1940 ca.col = tem->tvs_c_cursor.col * tems.ts_font.width +
1941 tems.ts_p_offset.x;
1942 ca.width = tems.ts_font.width;
1943 ca.height = tems.ts_font.height;
1944 if (tems.ts_pdepth == 8 || tems.ts_pdepth == 4) {
1945 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
1946 ca.fg_color.mono = TEM_TEXT_WHITE;
1947 ca.bg_color.mono = TEM_TEXT_BLACK;
1948 } else {
1949 ca.fg_color.mono = TEM_TEXT_BLACK;
1950 ca.bg_color.mono = TEM_TEXT_WHITE;
1952 } else if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32) {
1953 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
1954 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
1955 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
1956 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
1958 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
1959 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
1960 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
1961 } else {
1962 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
1963 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
1964 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
1966 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
1967 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
1968 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
1972 ca.action = action;
1974 tems_safe_cursor(&ca, credp, called_from);
1977 #define BORDER_PIXELS 10
1978 void
1979 set_font(struct font *f, short *rows, short *cols, short height, short width)
1981 bitmap_data_t *font_selected = NULL;
1982 struct fontlist *fl;
1985 * Find best font for these dimensions, or use default
1987 * A 1 pixel border is the absolute minimum we could have
1988 * as a border around the text window (BORDER_PIXELS = 2),
1989 * however a slightly larger border not only looks better
1990 * but for the fonts currently statically built into the
1991 * emulator causes much better font selection for the
1992 * normal range of screen resolutions.
1994 for (fl = fonts; fl->data; fl++) {
1995 if ((((*rows * fl->data->height) + BORDER_PIXELS) <= height) &&
1996 (((*cols * fl->data->width) + BORDER_PIXELS) <= width)) {
1997 font_selected = fl->data;
1998 break;
2002 * The minus 2 is to make sure we have at least a 1 pixel
2003 * boarder around the entire screen.
2005 if (font_selected == NULL) {
2006 if (((*rows * DEFAULT_FONT_DATA.height) > height) ||
2007 ((*cols * DEFAULT_FONT_DATA.width) > width)) {
2008 *rows = (height - 2) / DEFAULT_FONT_DATA.height;
2009 *cols = (width - 2) / DEFAULT_FONT_DATA.width;
2011 font_selected = &DEFAULT_FONT_DATA;
2014 f->width = font_selected->width;
2015 f->height = font_selected->height;
2016 bcopy((caddr_t)font_selected->encoding, (caddr_t)f->char_ptr,
2017 sizeof (f->char_ptr));
2018 f->image_data = font_selected->image;
2023 * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte
2024 * for each 2 bits of input bitmap. It inverts the input bits before
2025 * doing the output translation, for reverse video.
2027 * Assuming foreground is 0001 and background is 0000...
2028 * An input data byte of 0x53 will output the bit pattern
2029 * 00000001 00000001 00000000 00010001.
2032 static void
2033 bit_to_pix4(
2034 struct tem_vt_state *tem,
2035 uchar_t c,
2036 text_color_t fg_color,
2037 text_color_t bg_color)
2039 int row;
2040 int byte;
2041 int i;
2042 uint8_t *cp;
2043 uint8_t data;
2044 uint8_t nibblett;
2045 int bytes_wide;
2046 uint8_t *dest;
2048 dest = (uint8_t *)tem->tvs_pix_data;
2050 cp = tems.ts_font.char_ptr[c];
2051 bytes_wide = (tems.ts_font.width + 7) / 8;
2053 for (row = 0; row < tems.ts_font.height; row++) {
2054 for (byte = 0; byte < bytes_wide; byte++) {
2055 data = *cp++;
2056 for (i = 0; i < 4; i++) {
2057 nibblett = (data >> ((3-i) * 2)) & 0x3;
2058 switch (nibblett) {
2059 case 0x0:
2060 *dest++ = bg_color << 4 | bg_color;
2061 break;
2062 case 0x1:
2063 *dest++ = bg_color << 4 | fg_color;
2064 break;
2065 case 0x2:
2066 *dest++ = fg_color << 4 | bg_color;
2067 break;
2068 case 0x3:
2069 *dest++ = fg_color << 4 | fg_color;
2070 break;
2078 * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte
2079 * for each bit of input bitmap. It inverts the input bits before
2080 * doing the output translation, for reverse video.
2082 * Assuming foreground is 00000001 and background is 00000000...
2083 * An input data byte of 0x53 will output the bit pattern
2084 * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
2087 static void
2088 bit_to_pix8(
2089 struct tem_vt_state *tem,
2090 uchar_t c,
2091 text_color_t fg_color,
2092 text_color_t bg_color)
2094 int row;
2095 int byte;
2096 int i;
2097 uint8_t *cp;
2098 uint8_t data;
2099 int bytes_wide;
2100 uint8_t mask;
2101 int bitsleft, nbits;
2102 uint8_t *dest;
2104 dest = (uint8_t *)tem->tvs_pix_data;
2106 cp = tems.ts_font.char_ptr[c];
2107 bytes_wide = (tems.ts_font.width + 7) / 8;
2109 for (row = 0; row < tems.ts_font.height; row++) {
2110 bitsleft = tems.ts_font.width;
2111 for (byte = 0; byte < bytes_wide; byte++) {
2112 data = *cp++;
2113 mask = 0x80;
2114 nbits = MIN(8, bitsleft);
2115 bitsleft -= nbits;
2116 for (i = 0; i < nbits; i++) {
2117 *dest++ = (data & mask ? fg_color: bg_color);
2118 mask = mask >> 1;
2125 * bit_to_pix24 is for 24-bit frame buffers. It will write four output bytes
2126 * for each bit of input bitmap. It inverts the input bits before
2127 * doing the output translation, for reverse video. Note that each
2128 * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
2129 * high-order byte set to zero.
2131 * Assuming foreground is 00000000 11111111 11111111 11111111
2132 * and background is 00000000 00000000 00000000 00000000
2133 * An input data byte of 0x53 will output the bit pattern
2135 * 00000000 00000000 00000000 00000000
2136 * 00000000 11111111 11111111 11111111
2137 * 00000000 00000000 00000000 00000000
2138 * 00000000 11111111 11111111 11111111
2139 * 00000000 00000000 00000000 00000000
2140 * 00000000 00000000 00000000 00000000
2141 * 00000000 11111111 11111111 11111111
2142 * 00000000 11111111 11111111 11111111
2145 typedef uint32_t pixel32_t;
2147 static void
2148 bit_to_pix24(
2149 struct tem_vt_state *tem,
2150 uchar_t c,
2151 text_color_t fg_color4,
2152 text_color_t bg_color4)
2154 int row;
2155 int byte;
2156 int i;
2157 uint8_t *cp;
2158 uint8_t data;
2159 int bytes_wide;
2160 int bitsleft, nbits;
2162 pixel32_t fg_color32, bg_color32, *destp;
2164 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2166 fg_color32 = PIX4TO32(fg_color4);
2167 bg_color32 = PIX4TO32(bg_color4);
2169 destp = (pixel32_t *)tem->tvs_pix_data;
2170 cp = tems.ts_font.char_ptr[c];
2171 bytes_wide = (tems.ts_font.width + 7) / 8;
2173 for (row = 0; row < tems.ts_font.height; row++) {
2174 bitsleft = tems.ts_font.width;
2175 for (byte = 0; byte < bytes_wide; byte++) {
2176 data = *cp++;
2177 nbits = MIN(8, bitsleft);
2178 bitsleft -= nbits;
2179 for (i = 0; i < nbits; i++) {
2180 *destp++ = ((data << i) & 0x80 ?
2181 fg_color32 : bg_color32);
2187 static text_color_t
2188 ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
2190 if (tem->tvs_flags & TEM_ATTR_BRIGHT_BG)
2191 return (brt_xlate[ansi]);
2192 else
2193 return (dim_xlate[ansi]);
2196 static text_color_t
2197 ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
2199 if (tem->tvs_flags & TEM_ATTR_BRIGHT_FG ||
2200 tem->tvs_flags & TEM_ATTR_BOLD) {
2201 return (brt_xlate[ansi]);
2202 } else {
2203 return (dim_xlate[ansi]);
2208 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2210 void
2211 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2212 text_color_t *bg, uint8_t flag)
2214 if (tem->tvs_flags & flag) {
2215 *fg = ansi_fg_to_solaris(tem,
2216 tem->tvs_bg_color);
2217 *bg = ansi_bg_to_solaris(tem,
2218 tem->tvs_fg_color);
2219 } else {
2220 *fg = ansi_fg_to_solaris(tem,
2221 tem->tvs_fg_color);
2222 *bg = ansi_bg_to_solaris(tem,
2223 tem->tvs_bg_color);
2228 * Clear a rectangle of screen for pixel mode.
2230 * arguments:
2231 * row: start row#
2232 * nrows: the number of rows to clear
2233 * offset_y: the offset of height in pixels to begin clear
2234 * col: start col#
2235 * ncols: the number of cols to clear
2236 * offset_x: the offset of width in pixels to begin clear
2237 * scroll_up: whether this function is called during sroll up,
2238 * which is called only once.
2240 void
2241 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2242 screen_pos_t row, int nrows, int offset_y,
2243 screen_pos_t col, int ncols, int offset_x,
2244 boolean_t sroll_up, cred_t *credp,
2245 enum called_from called_from)
2247 struct vis_consdisplay da;
2248 int i, j;
2249 int row_add = 0;
2250 text_color_t fg_color;
2251 text_color_t bg_color;
2253 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2254 called_from == CALLED_FROM_STANDALONE);
2256 if (sroll_up)
2257 row_add = tems.ts_c_dimension.height - 1;
2259 da.width = tems.ts_font.width;
2260 da.height = tems.ts_font.height;
2262 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2264 tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
2265 da.data = (uchar_t *)tem->tvs_pix_data;
2267 for (i = 0; i < nrows; i++, row++) {
2268 da.row = (row + row_add) * da.height + offset_y;
2269 da.col = col * da.width + offset_x;
2270 for (j = 0; j < ncols; j++) {
2271 tems_safe_display(&da, credp, called_from);
2272 da.col += da.width;
2278 * virtual screen operations
2280 static void
2281 tem_safe_virtual_display(struct tem_vt_state *tem, unsigned char *string,
2282 int count, screen_pos_t row, screen_pos_t col,
2283 text_color_t fg_color, text_color_t bg_color)
2285 int i, width;
2286 unsigned char *addr;
2287 text_color_t *pfgcolor;
2288 text_color_t *pbgcolor;
2290 if (row < 0 || row >= tems.ts_c_dimension.height ||
2291 col < 0 || col >= tems.ts_c_dimension.width ||
2292 col + count > tems.ts_c_dimension.width)
2293 return;
2295 width = tems.ts_c_dimension.width;
2296 addr = tem->tvs_screen_buf + (row * width + col);
2297 pfgcolor = tem->tvs_fg_buf + (row * width + col);
2298 pbgcolor = tem->tvs_bg_buf + (row * width + col);
2299 for (i = 0; i < count; i++) {
2300 *addr++ = string[i];
2301 *pfgcolor++ = fg_color;
2302 *pbgcolor++ = bg_color;
2306 static void
2307 i_virtual_copy(unsigned char *base,
2308 screen_pos_t s_col, screen_pos_t s_row,
2309 screen_pos_t e_col, screen_pos_t e_row,
2310 screen_pos_t t_col, screen_pos_t t_row)
2312 unsigned char *from;
2313 unsigned char *to;
2314 int cnt;
2315 screen_size_t chars_per_row;
2316 unsigned char *to_row_start;
2317 unsigned char *from_row_start;
2318 screen_size_t rows_to_move;
2319 int cols = tems.ts_c_dimension.width;
2321 chars_per_row = e_col - s_col + 1;
2322 rows_to_move = e_row - s_row + 1;
2324 to_row_start = base + ((t_row * cols) + t_col);
2325 from_row_start = base + ((s_row * cols) + s_col);
2327 if (to_row_start < from_row_start) {
2328 while (rows_to_move-- > 0) {
2329 to = to_row_start;
2330 from = from_row_start;
2331 to_row_start += cols;
2332 from_row_start += cols;
2333 for (cnt = chars_per_row; cnt-- > 0; )
2334 *to++ = *from++;
2336 } else {
2338 * Offset to the end of the region and copy backwards.
2340 cnt = rows_to_move * cols + chars_per_row;
2341 to_row_start += cnt;
2342 from_row_start += cnt;
2344 while (rows_to_move-- > 0) {
2345 to_row_start -= cols;
2346 from_row_start -= cols;
2347 to = to_row_start;
2348 from = from_row_start;
2349 for (cnt = chars_per_row; cnt-- > 0; )
2350 *--to = *--from;
2355 static void
2356 tem_safe_virtual_copy(struct tem_vt_state *tem,
2357 screen_pos_t s_col, screen_pos_t s_row,
2358 screen_pos_t e_col, screen_pos_t e_row,
2359 screen_pos_t t_col, screen_pos_t t_row)
2361 screen_size_t chars_per_row;
2362 screen_size_t rows_to_move;
2363 int rows = tems.ts_c_dimension.height;
2364 int cols = tems.ts_c_dimension.width;
2366 if (s_col < 0 || s_col >= cols ||
2367 s_row < 0 || s_row >= rows ||
2368 e_col < 0 || e_col >= cols ||
2369 e_row < 0 || e_row >= rows ||
2370 t_col < 0 || t_col >= cols ||
2371 t_row < 0 || t_row >= rows ||
2372 s_col > e_col ||
2373 s_row > e_row)
2374 return;
2376 chars_per_row = e_col - s_col + 1;
2377 rows_to_move = e_row - s_row + 1;
2379 /* More sanity checks. */
2380 if (t_row + rows_to_move > rows ||
2381 t_col + chars_per_row > cols)
2382 return;
2384 i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
2385 e_col, e_row, t_col, t_row);
2387 /* text_color_t is the same size as char */
2388 i_virtual_copy((unsigned char *)tem->tvs_fg_buf,
2389 s_col, s_row, e_col, e_row, t_col, t_row);
2390 i_virtual_copy((unsigned char *)tem->tvs_bg_buf,
2391 s_col, s_row, e_col, e_row, t_col, t_row);
2395 static void
2396 tem_safe_virtual_cls(struct tem_vt_state *tem,
2397 int count, screen_pos_t row, screen_pos_t col)
2399 text_color_t fg_color;
2400 text_color_t bg_color;
2402 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2403 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col,
2404 fg_color, bg_color);
2408 * only blank screen, not clear our screen buffer
2410 void
2411 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2412 enum called_from called_from)
2414 int row;
2416 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2417 called_from == CALLED_FROM_STANDALONE);
2419 if (tems.ts_display_mode == VIS_PIXEL) {
2420 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2421 return;
2424 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2425 tem_safe_callback_cls(tem,
2426 tems.ts_c_dimension.width,
2427 row, 0, credp, called_from);
2432 * unblank screen with associated tem from its screen buffer
2434 void
2435 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2436 enum called_from called_from)
2438 text_color_t fg_color, fg_last;
2439 text_color_t bg_color, bg_last;
2440 size_t tc_size = sizeof (text_color_t);
2441 int row, col, count, col_start;
2442 int width;
2443 unsigned char *buf;
2445 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2446 called_from == CALLED_FROM_STANDALONE);
2448 if (tems.ts_display_mode == VIS_PIXEL)
2449 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2451 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2453 width = tems.ts_c_dimension.width;
2456 * Display data in tvs_screen_buf to the actual framebuffer in a
2457 * row by row way.
2458 * When dealing with one row, output data with the same foreground
2459 * and background color all together.
2461 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2462 buf = tem->tvs_screen_buf + (row * width);
2463 count = col_start = 0;
2464 for (col = 0; col < width; col++) {
2465 fg_color =
2466 tem->tvs_fg_buf[(row * width + col) * tc_size];
2467 bg_color =
2468 tem->tvs_bg_buf[(row * width + col) * tc_size];
2469 if (col == 0) {
2470 fg_last = fg_color;
2471 bg_last = bg_color;
2474 if ((fg_color != fg_last) || (bg_color != bg_last)) {
2476 * Call the primitive to render this data.
2478 tem_safe_callback_display(tem,
2479 buf, count, row, col_start,
2480 fg_last, bg_last, credp, called_from);
2481 buf += count;
2482 count = 1;
2483 col_start = col;
2484 fg_last = fg_color;
2485 bg_last = bg_color;
2486 } else {
2487 count++;
2491 if (col_start == (width - 1))
2492 continue;
2495 * Call the primitive to render this data.
2497 tem_safe_callback_display(tem,
2498 buf, count, row, col_start,
2499 fg_last, bg_last, credp, called_from);
2502 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);