70 #include <sys/sysmacros.h>
71 #include <sys/mutex.h>
72 #include <sys/note.h>
73 #include <sys/t_lock.h>
74
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
81 };
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
88 };
89
90
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);
103
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);
140
141 static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
142 screen_pos_t);
143 static void tem_safe_virtual_display(struct tem_vt_state *,
144 unsigned char *, int, screen_pos_t, screen_pos_t,
145 text_color_t, text_color_t);
146 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
147 screen_pos_t, screen_pos_t, screen_pos_t,
148 screen_pos_t, screen_pos_t);
149 static void tem_safe_align_cursor(struct tem_vt_state *tem);
150 static void bit_to_pix4(struct tem_vt_state *tem, uchar_t c,
151 text_color_t fg_color, text_color_t bg_color);
152 static void bit_to_pix8(struct tem_vt_state *tem, uchar_t c,
153 text_color_t fg_color, text_color_t bg_color);
154 static void bit_to_pix24(struct tem_vt_state *tem, uchar_t c,
155 text_color_t fg_color, text_color_t bg_color);
156
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 */
162
163
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 */
172 };
173
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])
178
179 #define INVERSE(ch) (ch ^ 0xff)
180
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));\
188 }
189
190 void
191 tem_safe_check_first_time(
192 struct tem_vt_state *tem,
193 cred_t *credp,
194 enum called_from called_from)
195 {
196 static int first_time = 1;
197
198 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
199 called_from == CALLED_FROM_STANDALONE);
200
201 /*
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.
206 */
207 if (!first_time)
208 return;
209
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);
214 }
215 }
216
217 /*
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.
225 */
226 void
227 tem_safe_polled_write(
228 tem_vt_state_t tem_arg,
229 uchar_t *buf,
230 int len)
231 {
232 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
233
234 #ifdef __lock_lint
235 _NOTE(NO_COMPETING_THREADS_NOW)
236 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
237 #endif
238
239 if (!tem->tvs_initialized) {
240 return;
241 }
242
243 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
244 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
245 }
246
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)
251 {
252 int i;
253 uint8_t c;
254
255 if (tem->tvs_utf8_left == 0)
256 return;
257
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);
262 }
263 }
264 tem->tvs_utf8_left = 0;
265 tem->tvs_utf8_partial = 0;
266 }
267
268 /*
269 * Handle UTF-8 sequences.
270 */
271 static void
272 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
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);
345 }
346
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;
352 }
353 return;
354 }
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);
358 }
359
360 /*
361 * This is the main entry point into the terminal emulator.
362 *
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.
367 */
368 void
369 tem_safe_terminal_emulate(
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).
432 */
433 static void
434 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
435 enum called_from called_from)
436 {
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);
441 }
442
443 /*
444 * send the appropriate control message or set state based on the
445 * value of the control character ch
446 */
447
448 static void
449 tem_safe_control(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
450 enum called_from called_from)
451 {
452 tem->tvs_state = A_STATE_START;
453 switch (ch) {
454 case A_BEL:
455 tem_safe_bell(tem, called_from);
456 break;
457
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;
464
465 case A_HT:
466 tem_safe_tab(tem, credp, called_from);
467 break;
468
469 case A_NL:
488 tem_safe_cr(tem);
489 break;
490
491 case A_ESC:
492 tem->tvs_state = A_STATE_ESC;
493 break;
494
495 case A_CSI:
496 {
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;
505 }
506 break;
507
508 case A_GS:
509 tem_safe_back_tab(tem, credp, called_from);
510 break;
511
512 default:
513 break;
514 }
515 }
516
517
518 /*
519 * if parameters [0..count - 1] are not set, set them to the value
520 * of newparam.
521 */
522
523 static void
524 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
525 {
526 int i;
527
548 do {
549 param = tem->tvs_params[count];
550
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;
559
560 case 1: /* Bold Intense */
561 tem->tvs_flags |= TEM_ATTR_BOLD;
562 break;
563
564 case 2: /* Faint Intense */
565 tem->tvs_flags &= ~TEM_ATTR_BOLD;
566 break;
567
568 case 5: /* Blink */
569 tem->tvs_flags |= TEM_ATTR_BLINK;
570 break;
571
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;
577 }
578 break;
579
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;
591
592 case 39:
593 /*
594 * Reset the foreground colour and brightness.
595 */
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
646 tem->tvs_bg_color = param - 100;
647 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
648 break;
649
650 default:
651 break;
652 }
653 count++;
654 curparam--;
655
656 } while (curparam > 0);
657 }
658
659 /*
660 * perform the appropriate action for the escape sequence
661 *
662 * General rule: This code does not validate the arguments passed.
663 * It assumes that the next lower level will do so.
664 */
665 static void
666 tem_safe_chkparam(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
667 enum called_from called_from)
668 {
669 int i;
670 int row;
671 int col;
672
673 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
674 MUTEX_HELD(&tem->tvs_lock));
675
676 row = tem->tvs_c_cursor.row;
677 col = tem->tvs_c_cursor.col;
678
679 switch (ch) {
680
681 case 'm': /* select terminal graphics mode */
682 tem_safe_send_data(tem, credp, called_from);
683 tem_safe_selgraph(tem);
684 break;
685
686 case '@': /* insert char */
909 *
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.
913 */
914 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
915 tem->tvs_params[0] = tems.ts_c_dimension.width;
916
917 for (i = 0; i < tem->tvs_params[0]; i++)
918 tem_safe_back_tab(tem, credp, called_from);
919 break;
920 }
921 tem->tvs_state = A_STATE_START;
922 }
923
924
925 /*
926 * Gather the parameters of an ANSI escape sequence
927 */
928 static void
929 tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
930 cred_t *credp, enum called_from called_from)
931 {
932 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
933 MUTEX_HELD(&tem->tvs_lock));
934
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;
948 }
949 tem->tvs_curparam++;
950 }
951
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);
959 }
960 }
961 }
962
963 /*
964 * Add character to internal buffer.
965 * When its full, send it to the next layer.
966 */
967
968 static void
969 tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
970 cred_t *credp, enum called_from called_from)
971 {
972
973 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
974 called_from == CALLED_FROM_STANDALONE);
975
976 /* buffer up the character until later */
977
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);
983 }
984 }
985
986 static void
987 tem_safe_new_line(struct tem_vt_state *tem,
988 cred_t *credp, enum called_from called_from)
989 {
990 tem_safe_cr(tem);
991 tem_safe_lf(tem, credp, called_from);
992 }
993
994 static void
995 tem_safe_cr(struct tem_vt_state *tem)
996 {
997 tem->tvs_c_cursor.col = 0;
998 tem_safe_align_cursor(tem);
1037 credp, called_from);
1038
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);
1047
1048 }
1049
1050 tem_safe_align_cursor(tem);
1051 }
1052
1053 static void
1054 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1055 enum called_from called_from)
1056 {
1057 text_color_t fg_color;
1058 text_color_t bg_color;
1059
1060 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1061 MUTEX_HELD(&tem->tvs_lock));
1062
1063 if (tem->tvs_outindex == 0) {
1064 tem_safe_align_cursor(tem);
1065 return;
1066 }
1067
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);
1073
1074 if (tem->tvs_isactive) {
1075 /*
1076 * Call the primitive to render this data.
1077 */
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);
1083 }
1084
1085 tem->tvs_outindex = 0;
1086
1087 tem_safe_align_cursor(tem);
1088 }
1089
1090
1091 /*
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.
1095 */
1096 static void
1097 tem_safe_align_cursor(struct tem_vt_state *tem)
1098 {
1099 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1100 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1101 }
1102
1103 /*
1104 * State machine parser based on the current state and character input
1105 * major terminations are to control character or normal character
1106 */
1107
1108 static void
1109 tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
1110 cred_t *credp, enum called_from called_from)
1111 {
1112 int i;
1113
1114 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1115 MUTEX_HELD(&tem->tvs_lock));
1116
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);
1124 }
1125 return;
1126 }
1127
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;
1133 }
1134
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':
1143 /*
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"
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;
1228 }
1229 }
1230
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,
1380 return;
1381
1382 /*
1383 * Note that very large values of "count" could cause col+count
1384 * to overflow, so we check "count" independently.
1385 */
1386 if (count > tems.ts_c_dimension.width ||
1387 col + count > tems.ts_c_dimension.width)
1388 count = tems.ts_c_dimension.width - col;
1389
1390 tem_safe_virtual_cls(tem, count, row, col);
1391
1392 if (!tem->tvs_isactive)
1393 return;
1394
1395 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1396 }
1397
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)
1404 {
1405 struct vis_consdisplay da;
1406
1407 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1408 called_from == CALLED_FROM_STANDALONE);
1409
1410 da.data = string;
1411 da.width = (screen_size_t)count;
1412 da.row = row;
1413 da.col = col;
1414
1415 da.fg_color = fg_color;
1416 da.bg_color = bg_color;
1417
1418 tems_safe_display(&da, credp, called_from);
1419 }
1420
1421 /*
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.
1428 *
1429 * This function is unused now.
1430 */
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)
1436 {
1437 struct vis_consdisplay da;
1438
1439 mutex_enter(&tems.ts_lock);
1440 mutex_enter(&tem->tvs_lock);
1441
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;
1447
1448 tems_safe_display(&da, credp, called_from);
1449
1450 mutex_exit(&tem->tvs_lock);
1451 mutex_exit(&tems.ts_lock);
1452 }
1453
1454
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)
1462 {
1463 struct vis_conscopy da;
1464
1465 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1466 called_from == CALLED_FROM_STANDALONE);
1467
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;
1474
1475 tems_safe_copy(&da, credp, called_from);
1476 }
1477
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)
1482 {
1483 struct vis_consdisplay da;
1484
1485 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1486 called_from == CALLED_FROM_STANDALONE);
1487
1488 da.data = tems.ts_blank_line;
1489 da.width = (screen_size_t)count;
1490 da.row = row;
1491 da.col = col;
1492
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);
1496 }
1497
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)
1504 {
1505 struct vis_consdisplay da;
1506 int i;
1507
1508 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1509 called_from == CALLED_FROM_STANDALONE);
1510
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;
1516
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;
1521 }
1522 }
1523
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)
1531 {
1532 struct vis_conscopy ma;
1533 static boolean_t need_clear = B_TRUE;
1534
1535 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1536 called_from == CALLED_FROM_STANDALONE);
1537
1538 if (need_clear && tem->tvs_first_line > 0) {
1539 /*
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)
1544 *
1545 * This is only one time call.
1546 */
1547 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1548 }
1549 need_clear = B_FALSE;
1550
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;
1554
1555 /*
1556 * Check if we're in process of clearing OBP's columns area,
1557 * which only happens when term scrolls up a whole line.
1558 */
1559 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1560 e_col == tems.ts_c_dimension.width - 1) {
1561 /*
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.
1564 */
1565 ma.s_col = s_col * tems.ts_font.width;
1566 ma.e_col = tems.ts_p_dimension.width - 1;
1567
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;
1574 }
1575
1576 tems_safe_copy(&ma, credp, called_from);
1577
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;
1584 }
1585 }
1586
1587 }
1588
1589 void
1590 tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
1591 unsigned char fg, unsigned char bg)
1592 {
1593 void (*fp)(struct tem_vt_state *, unsigned char,
1594 unsigned char, unsigned char);
1595
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;
1606 }
1607
1608 fp(tem, c, fg, bg);
1609 }
1610
1611
1612 /*
1613 * This function only clears count of columns in one row
1614 */
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)
1619 {
1620 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1621 called_from == CALLED_FROM_STANDALONE);
1622
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);
1625 }
1626
1627 /*
1628 * This function clears OBP output above our kernel console term area
1634 * _________________________________
1635 * | _____________________ | ---> OBP's bigger term window
1636 * | | | |
1637 * |___| | |
1638 * | | | | |
1639 * | | | | |
1640 * |_|_|___________________|_______|
1641 * | | | ---> first line
1642 * | |___________________|---> our kernel console term window
1643 * |
1644 * |---> columns area to be cleared
1645 *
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.
1649 */
1650 static void
1651 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1652 enum called_from called_from)
1653 {
1654 int nrows, ncols, width, height;
1655
1656 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1657 called_from == CALLED_FROM_STANDALONE);
1658
1659 width = tems.ts_font.width;
1660 height = tems.ts_font.height;
1661
1662 nrows = (tems.ts_p_offset.y + (height - 1))/ height;
1663 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1664
1665 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1666 B_FALSE, credp, called_from);
1667 }
1668
1669 /*
1670 * clear the whole screen for pixel mode, just clear the
1671 * physical screen.
1672 */
1673 void
1674 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1675 enum called_from called_from)
1676 {
1677 int nrows, ncols, width, height;
1678
1679 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1680 called_from == CALLED_FROM_STANDALONE);
1681
1682 width = tems.ts_font.width;
1683 height = tems.ts_font.height;
1684
1685 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1686 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1687
1688 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1689 B_FALSE, credp, called_from);
1690
1691 /*
1692 * Since the whole screen is cleared, we don't need
1693 * to clear OBP output later.
1694 */
1695 if (tem->tvs_first_line > 0)
1696 tem->tvs_first_line = 0;
1697 }
1698
1699 /*
1700 * clear the whole screen, including the virtual screen buffer,
1701 * and reset the cursor to start point.
1702 */
1703 static void
1704 tem_safe_cls(struct tem_vt_state *tem,
1705 cred_t *credp, enum called_from called_from)
1706 {
1707 int row;
1708
1709 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1987 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1988 called_from == CALLED_FROM_STANDALONE);
1989
1990 ca.row = tem->tvs_c_cursor.row;
1991 ca.col = tem->tvs_c_cursor.col;
1992 ca.action = action;
1993
1994 tems_safe_cursor(&ca, credp, called_from);
1995
1996 if (action == VIS_GET_CURSOR) {
1997 tem->tvs_c_cursor.row = ca.row;
1998 tem->tvs_c_cursor.col = ca.col;
1999 }
2000 }
2001
2002 void
2003 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
2004 cred_t *credp, enum called_from called_from)
2005 {
2006 struct vis_conscursor ca;
2007
2008 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2009 called_from == CALLED_FROM_STANDALONE);
2010
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;
2024 }
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;
2030
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;
2038
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;
2042 }
2043 }
2044
2045 ca.action = action;
2046
2047 tems_safe_cursor(&ca, credp, called_from);
2048 }
2049
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)
2053 {
2054 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2055 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
2056 }
2057
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)
2061 {
2062 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2063 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
2064 }
2065
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)
2069 {
2070 uint32_t fg_color32, bg_color32, *dest;
2071
2072 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2073
2074 fg_color32 = PIX4TO32(fg_color4);
2075 bg_color32 = PIX4TO32(bg_color4);
2076
2077 dest = (uint32_t *)tem->tvs_pix_data;
2078 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
2079 }
2080
2081 static text_color_t
2082 ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
2083 {
2084 if (tem->tvs_flags & TEM_ATTR_BRIGHT_BG)
2085 return (brt_xlate[ansi]);
2086 else
2087 return (dim_xlate[ansi]);
2088 }
2089
2090 static text_color_t
2091 ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
2092 {
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]);
2098 }
2099 }
2100
2101 /*
2102 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2103 */
2104 void
2105 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2106 text_color_t *bg, uint8_t flag)
2107 {
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);
2118 }
2119 }
2120
2121 /*
2122 * Clear a rectangle of screen for pixel mode.
2123 *
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.
2133 */
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)
2140 {
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;
2146
2147 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2148 called_from == CALLED_FROM_STANDALONE);
2149
2150 if (sroll_up)
2151 row_add = tems.ts_c_dimension.height - 1;
2152
2153 da.width = tems.ts_font.width;
2154 da.height = tems.ts_font.height;
2155
2156 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2157
2158 tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
2159 da.data = (uchar_t *)tem->tvs_pix_data;
2160
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;
2167 }
2168 }
2169 }
2170
2171 /*
2172 * virtual screen operations
2173 */
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)
2178 {
2179 int i, width;
2180 unsigned char *addr;
2181 text_color_t *pfgcolor;
2182 text_color_t *pbgcolor;
2183
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;
2188
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;
2197 }
2198 }
2199
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)
2205 {
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;
2214
2215 chars_per_row = e_col - s_col + 1;
2216 rows_to_move = e_row - s_row + 1;
2217
2218 to_row_start = base + ((t_row * cols) + t_col);
2219 from_row_start = base + ((s_row * cols) + s_col);
2220
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++;
2229 }
2230 } else {
2231 /*
2258 int cols = tems.ts_c_dimension.width;
2259
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;
2269
2270 chars_per_row = e_col - s_col + 1;
2271 rows_to_move = e_row - s_row + 1;
2272
2273 /* More sanity checks. */
2274 if (t_row + rows_to_move > rows ||
2275 t_col + chars_per_row > cols)
2276 return;
2277
2278 i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
2279 e_col, e_row, t_col, t_row);
2280
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);
2286
2287 }
2288
2289 static void
2290 tem_safe_virtual_cls(struct tem_vt_state *tem,
2291 int count, screen_pos_t row, screen_pos_t col)
2292 {
2293 text_color_t fg_color;
2294 text_color_t bg_color;
2295
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);
2299 }
2300
2301 /*
2302 * only blank screen, not clear our screen buffer
2303 */
2304 void
2305 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2306 enum called_from called_from)
2307 {
2308 int row;
2309
2310 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2311 called_from == CALLED_FROM_STANDALONE);
2312
2313 if (tems.ts_display_mode == VIS_PIXEL) {
2314 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2315 return;
2316 }
2317
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);
2322 }
2323 }
2324
2325 /*
2326 * unblank screen with associated tem from its screen buffer
2327 */
2328 void
2329 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2330 enum called_from called_from)
2331 {
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;
2338
2339 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2340 called_from == CALLED_FROM_STANDALONE);
2341
2342 if (tems.ts_display_mode == VIS_PIXEL)
2343 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2344
2345 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2346
2347 width = tems.ts_c_dimension.width;
2348
2349 /*
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.
2354 */
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;
2366 }
2367
2368 if ((fg_color != fg_last) || (bg_color != bg_last)) {
2369 /*
2370 * Call the primitive to render this data.
2371 */
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++;
2382 }
2383 }
2384
2385 if (col_start == (width - 1))
2386 continue;
2387
2388 /*
2389 * Call the primitive to render this data.
2390 */
2391 tem_safe_callback_display(tem,
2392 buf, count, row, col_start,
2393 fg_last, bg_last, credp, called_from);
2394 }
2395
2396 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
2397 }
|
70 #include <sys/sysmacros.h>
71 #include <sys/mutex.h>
72 #include <sys/note.h>
73 #include <sys/t_lock.h>
74
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
81 };
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
88 };
89
90 static void tem_safe_control(struct tem_vt_state *, tem_char_t,
91 cred_t *, enum called_from);
92 static void tem_safe_setparam(struct tem_vt_state *, int, int);
93 static void tem_safe_selgraph(struct tem_vt_state *);
94 static void tem_safe_chkparam(struct tem_vt_state *, tem_char_t,
95 cred_t *, enum called_from);
96 static void tem_safe_getparams(struct tem_vt_state *, tem_char_t,
97 cred_t *, enum called_from);
98 static void tem_safe_outch(struct tem_vt_state *, tem_char_t,
99 cred_t *, enum called_from);
100 static void tem_safe_parse(struct tem_vt_state *, tem_char_t,
101 cred_t *, enum called_from);
102
103 static void tem_safe_new_line(struct tem_vt_state *,
104 cred_t *, enum called_from);
105 static void tem_safe_cr(struct tem_vt_state *);
106 static void tem_safe_lf(struct tem_vt_state *,
107 cred_t *, enum called_from);
108 static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
109 enum called_from);
110 static void tem_safe_cls(struct tem_vt_state *,
111 cred_t *, enum called_from);
112 static void tem_safe_tab(struct tem_vt_state *,
113 cred_t *, enum called_from);
114 static void tem_safe_back_tab(struct tem_vt_state *,
115 cred_t *, enum called_from);
116 static void tem_safe_clear_tabs(struct tem_vt_state *, int);
117 static void tem_safe_set_tab(struct tem_vt_state *);
118 static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
119 cred_t *, enum called_from);
120 static void tem_safe_shift(struct tem_vt_state *, int, int,
121 cred_t *, enum called_from);
122 static void tem_safe_scroll(struct tem_vt_state *, int, int,
123 int, int, cred_t *, enum called_from);
124 static void tem_safe_clear_chars(struct tem_vt_state *tem,
125 int count, screen_pos_t row, screen_pos_t col,
126 cred_t *credp, enum called_from called_from);
127 static void tem_safe_copy_area(struct tem_vt_state *tem,
128 screen_pos_t s_col, screen_pos_t s_row,
129 screen_pos_t e_col, screen_pos_t e_row,
130 screen_pos_t t_col, screen_pos_t t_row,
131 cred_t *credp, enum called_from called_from);
132 static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
133 int, int, screen_pos_t, screen_pos_t,
134 cred_t *, enum called_from);
135 static void tem_safe_bell(struct tem_vt_state *tem,
136 enum called_from called_from);
137 static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
138 cred_t *credp, enum called_from called_from);
139 static void tem_safe_get_color(text_color_t *, text_color_t *, term_char_t);
140
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 term_char_t *, int, screen_pos_t, screen_pos_t);
145 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
146 screen_pos_t, screen_pos_t, screen_pos_t,
147 screen_pos_t, screen_pos_t);
148 static void tem_safe_align_cursor(struct tem_vt_state *tem);
149 static void bit_to_pix4(struct tem_vt_state *tem, tem_char_t c,
150 text_color_t fg_color, text_color_t bg_color);
151 static void bit_to_pix8(struct tem_vt_state *tem, tem_char_t c,
152 text_color_t fg_color, text_color_t bg_color);
153 static void bit_to_pix16(struct tem_vt_state *tem, tem_char_t c,
154 text_color_t fg_color, text_color_t bg_color);
155 static void bit_to_pix24(struct tem_vt_state *tem, tem_char_t c,
156 text_color_t fg_color, text_color_t bg_color);
157 static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c,
158 text_color_t fg_color, text_color_t bg_color);
159
160 #define PIX4TO32(pix4) (uint32_t)( \
161 cmap4_to_24.red[pix4] << 16 | \
162 cmap4_to_24.green[pix4] << 8 | \
163 cmap4_to_24.blue[pix4])
164
165 #define INVERSE(ch) (ch ^ 0xff)
166
167 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
168 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
169 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
170 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
171 #define tem_safe_callback_bit2pix(tem, c) { \
172 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
173 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c));\
174 }
175
176 void
177 tem_safe_check_first_time(
178 struct tem_vt_state *tem,
179 cred_t *credp,
180 enum called_from called_from)
181 {
182 static int first_time = 1;
183
184 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
185 called_from == CALLED_FROM_STANDALONE);
186
187 /*
188 * Realign the console cursor. We did this in tem_init().
189 * However, drivers in the console stream may emit additional
190 * messages before we are ready. This causes text overwrite
191 * on the screen. This is a workaround.
192 */
193 if (!first_time)
194 return;
195
196 first_time = 0;
197 if (tems.ts_display_mode == VIS_TEXT)
198 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
199 else
200 tem_safe_pix_cursor(tem, VIS_GET_CURSOR, credp, called_from);
201 tem_safe_align_cursor(tem);
202 }
203
204 /*
205 * This entry point handles output requests from restricted contexts like
206 * kmdb, where services like mutexes are not available. This function
207 * is entered when OBP or when a kernel debugger (such as kmdb)
208 * are generating console output. In those cases, power management
209 * concerns are handled by the abort sequence initiation (ie. when
210 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
211 * It is also entered when the kernel is panicing.
212 */
213 void
214 tem_safe_polled_write(
215 tem_vt_state_t tem_arg,
216 uchar_t *buf,
217 int len)
218 {
219 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
220
221 #ifdef __lock_lint
222 _NOTE(NO_COMPETING_THREADS_NOW)
223 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
224 #endif
225
226 if (!tem->tvs_initialized) {
227 return;
228 }
229
230 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
231 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
232 }
233
234 /* Process partial UTF-8 sequence. */
235 static void
236 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
237 enum called_from called_from)
238 {
239 unsigned i;
240 uint8_t c;
241
242 if (tem->tvs_utf8_left == 0)
243 return;
244
245 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
246 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
247 if (c != 0) {
248 tem_safe_parse(tem, c, credp, called_from);
249 }
250 }
251 tem->tvs_utf8_left = 0;
252 tem->tvs_utf8_partial = 0;
253 }
254
255 /*
256 * Handle UTF-8 sequences.
257 */
258 static void
259 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
314 if (b != 0) { /* Four-byte sequence */
315 v = b & 0x07;
316 b = (u >> 16) & 0xff;
317 v = (v << 6) | (b & 0x3f);
318 b = (u >> 8) & 0xff;
319 v = (v << 6) | (b & 0x3f);
320 b = u & 0xff;
321 v = (v << 6) | (b & 0x3f);
322 } else if ((b = (u >> 16) & 0xff) != 0) {
323 v = b & 0x0f; /* Three-byte sequence */
324 b = (u >> 8) & 0xff;
325 v = (v << 6) | (b & 0x3f);
326 b = u & 0xff;
327 v = (v << 6) | (b & 0x3f);
328 } else if ((b = (u >> 8) & 0xff) != 0) {
329 v = b & 0x1f; /* Two-byte sequence */
330 b = u & 0xff;
331 v = (v << 6) | (b & 0x3f);
332 }
333
334 tem_safe_parse(tem, v, credp, called_from);
335 tem->tvs_utf8_partial = 0;
336 }
337 return;
338 }
339 /* Anything left is illegal in UTF-8 sequence. */
340 tem_safe_input_partial(tem, credp, called_from);
341 tem_safe_parse(tem, c, credp, called_from);
342 }
343
344 /*
345 * This is the main entry point into the terminal emulator.
346 *
347 * For each data message coming downstream, ANSI assumes that it is composed
348 * of ASCII characters, which are treated as a byte-stream input to the
349 * parsing state machine. All data is parsed immediately -- there is
350 * no enqueing.
351 */
352 void
353 tem_safe_terminal_emulate(
413 * at a specific location on frame buffer* using the mechanism
414 * appropriate for the system state being called from, quisced or
415 * normal (ie. use polled I/O vs. layered ioctls).
416 */
417 static void
418 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
419 enum called_from called_from)
420 {
421 if (called_from == CALLED_FROM_STANDALONE)
422 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
423 else
424 tems_cursor_layered(pca, credp);
425 }
426
427 /*
428 * send the appropriate control message or set state based on the
429 * value of the control character ch
430 */
431
432 static void
433 tem_safe_control(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
434 enum called_from called_from)
435 {
436 tem->tvs_state = A_STATE_START;
437 switch (ch) {
438 case A_BEL:
439 tem_safe_bell(tem, called_from);
440 break;
441
442 case A_BS:
443 tem_safe_mv_cursor(tem,
444 tem->tvs_c_cursor.row,
445 tem->tvs_c_cursor.col - 1,
446 credp, called_from);
447 break;
448
449 case A_HT:
450 tem_safe_tab(tem, credp, called_from);
451 break;
452
453 case A_NL:
472 tem_safe_cr(tem);
473 break;
474
475 case A_ESC:
476 tem->tvs_state = A_STATE_ESC;
477 break;
478
479 case A_CSI:
480 {
481 int i;
482 tem->tvs_curparam = 0;
483 tem->tvs_paramval = 0;
484 tem->tvs_gotparam = B_FALSE;
485 /* clear the parameters */
486 for (i = 0; i < TEM_MAXPARAMS; i++)
487 tem->tvs_params[i] = -1;
488 tem->tvs_state = A_STATE_CSI;
489 }
490 break;
491
492 case A_OSC:
493 {
494 int i;
495 tem->tvs_curparam = 0;
496 tem->tvs_paramval = 0;
497 tem->tvs_gotparam = B_FALSE;
498 /* clear the parameters */
499 for (i = 0; i < TEM_MAXPARAMS; i++)
500 tem->tvs_params[i] = -1;
501 tem->tvs_state = A_STATE_OSC;
502 }
503 break;
504
505 case A_GS:
506 tem_safe_back_tab(tem, credp, called_from);
507 break;
508
509 default:
510 break;
511 }
512 }
513
514
515 /*
516 * if parameters [0..count - 1] are not set, set them to the value
517 * of newparam.
518 */
519
520 static void
521 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
522 {
523 int i;
524
545 do {
546 param = tem->tvs_params[count];
547
548 switch (param) {
549 case -1:
550 case 0:
551 /* reset to initial normal settings */
552 tem->tvs_fg_color = tems.ts_init_color.fg_color;
553 tem->tvs_bg_color = tems.ts_init_color.bg_color;
554 tem->tvs_flags = tems.ts_init_color.a_flags;
555 break;
556
557 case 1: /* Bold Intense */
558 tem->tvs_flags |= TEM_ATTR_BOLD;
559 break;
560
561 case 2: /* Faint Intense */
562 tem->tvs_flags &= ~TEM_ATTR_BOLD;
563 break;
564
565 case 4: /* Underline */
566 tem->tvs_flags |= TEM_ATTR_UNDERLINE;
567 break;
568 case 5: /* Blink */
569 tem->tvs_flags |= TEM_ATTR_BLINK;
570 break;
571
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;
577 }
578 break;
579
580 case 22: /* Remove Bold */
581 tem->tvs_flags &= ~TEM_ATTR_BOLD;
582 break;
583
584 case 24: /* Remove Underline */
585 tem->tvs_flags &= ~TEM_ATTR_UNDERLINE;
586 break;
587
588 case 25: /* Remove Blink */
589 tem->tvs_flags &= ~TEM_ATTR_BLINK;
590 break;
591
592 case 27: /* Remove Reverse */
593 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
594 tem->tvs_flags |= TEM_ATTR_REVERSE;
595 } else {
596 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
597 }
598 break;
599
600 case 30: /* black (grey) foreground */
601 case 31: /* red (light red) foreground */
602 case 32: /* green (light green) foreground */
603 case 33: /* brown (yellow) foreground */
604 case 34: /* blue (light blue) foreground */
605 case 35: /* magenta (light magenta) foreground */
606 case 36: /* cyan (light cyan) foreground */
607 case 37: /* white (bright white) foreground */
608 tem->tvs_fg_color = param - 30;
609 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
610 break;
611
612 case 39:
613 /*
614 * Reset the foreground colour and brightness.
615 */
616 tem->tvs_fg_color = tems.ts_init_color.fg_color;
617 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
618 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
619 else
666 tem->tvs_bg_color = param - 100;
667 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
668 break;
669
670 default:
671 break;
672 }
673 count++;
674 curparam--;
675
676 } while (curparam > 0);
677 }
678
679 /*
680 * perform the appropriate action for the escape sequence
681 *
682 * General rule: This code does not validate the arguments passed.
683 * It assumes that the next lower level will do so.
684 */
685 static void
686 tem_safe_chkparam(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
687 enum called_from called_from)
688 {
689 int i;
690 int row;
691 int col;
692
693 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
694 MUTEX_HELD(&tem->tvs_lock));
695
696 row = tem->tvs_c_cursor.row;
697 col = tem->tvs_c_cursor.col;
698
699 switch (ch) {
700
701 case 'm': /* select terminal graphics mode */
702 tem_safe_send_data(tem, credp, called_from);
703 tem_safe_selgraph(tem);
704 break;
705
706 case '@': /* insert char */
929 *
930 * Restrict the count to a sane value to keep from
931 * looping for a long time. There can't be more than one
932 * tab stop per column, so use that as a limit.
933 */
934 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
935 tem->tvs_params[0] = tems.ts_c_dimension.width;
936
937 for (i = 0; i < tem->tvs_params[0]; i++)
938 tem_safe_back_tab(tem, credp, called_from);
939 break;
940 }
941 tem->tvs_state = A_STATE_START;
942 }
943
944
945 /*
946 * Gather the parameters of an ANSI escape sequence
947 */
948 static void
949 tem_safe_getparams(struct tem_vt_state *tem, tem_char_t ch,
950 cred_t *credp, enum called_from called_from)
951 {
952 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
953 MUTEX_HELD(&tem->tvs_lock));
954
955 if (ch >= '0' && ch <= '9') {
956 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
957 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
958 return; /* Return immediately */
959 } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
960 tem->tvs_state == A_STATE_CSI_QMARK) {
961 tem->tvs_state = A_STATE_START;
962 } else {
963 if (tem->tvs_curparam < TEM_MAXPARAMS) {
964 if (tem->tvs_gotparam) {
965 /* get the parameter value */
966 tem->tvs_params[tem->tvs_curparam] =
967 tem->tvs_paramval;
968 }
969 tem->tvs_curparam++;
970 }
971
972 if (ch == ';') {
973 /* Restart parameter search */
974 tem->tvs_gotparam = B_FALSE;
975 tem->tvs_paramval = 0; /* No parame value yet */
976 } else {
977 /* Handle escape sequence */
978 tem_safe_chkparam(tem, ch, credp, called_from);
979 }
980 }
981 }
982
983 /*
984 * Gather the OSC string.
985 * OSC Ps ; Pt ST
986 * OSC Ps ; Pt BEL
987 * Ps is number sequence identifying the function. We only support
988 * Ps = 4 and Ps = 104.
989 * Quite obviously this is nowhere close to be done;)
990 */
991 /* ARGSUSED */
992 static void
993 tem_safe_get_oscstring(struct tem_vt_state *tem, uchar_t ch,
994 cred_t *credp __unused, enum called_from called_from)
995 {
996 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
997 MUTEX_HELD(&tem->tvs_lock));
998
999 /* Should we cancel? */
1000 if (ch == A_CAN || ch == A_SUB || ch == A_ESC) {
1001 tem->tvs_state = A_STATE_START;
1002 return;
1003 }
1004
1005 /* following two if statements will read in the numeric parameter */
1006 if (ch >= '0' && ch <= '9') {
1007 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
1008 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
1009 return; /* Return immediately */
1010 }
1011
1012 if (tem->tvs_gotparam && ch == ';') {
1013 /* get the parameter value */
1014 tem->tvs_params[tem->tvs_curparam] = tem->tvs_paramval;
1015 tem->tvs_curparam++;
1016 tem->tvs_gotparam = B_FALSE;
1017 tem->tvs_paramval = 0;
1018 }
1019
1020 if (tem->tvs_curparam == 0) {
1021 /* bad sequence */
1022 tem->tvs_state = A_STATE_START;
1023 return;
1024 }
1025 if (tem->tvs_gotparam == B_FALSE && tem->tvs_curparam > 0) {
1026 if (tem->tvs_params[0] != 4 && tem->tvs_params[0] != 104) {
1027 /* make sure tvs_params will not get filled up */
1028 tem->tvs_curparam = 1;
1029 }
1030 }
1031 if (ch == A_ST || ch == A_BEL) {
1032 /* done */
1033 tem->tvs_state = A_STATE_START;
1034 return;
1035 }
1036 }
1037
1038 /*
1039 * Add character to internal buffer.
1040 * When its full, send it to the next layer.
1041 */
1042
1043 static void
1044 tem_safe_outch(struct tem_vt_state *tem, tem_char_t ch,
1045 cred_t *credp, enum called_from called_from)
1046 {
1047 text_color_t fg;
1048 text_color_t bg;
1049 text_attr_t attr;
1050
1051 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1052 called_from == CALLED_FROM_STANDALONE);
1053
1054 /* buffer up the character until later */
1055 tem_safe_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE);
1056 tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr);
1057 tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg;
1058 tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg;
1059 tem->tvs_outindex++;
1060 tem->tvs_c_cursor.col++;
1061 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
1062 tem_safe_send_data(tem, credp, called_from);
1063 tem_safe_new_line(tem, credp, called_from);
1064 }
1065 }
1066
1067 static void
1068 tem_safe_new_line(struct tem_vt_state *tem,
1069 cred_t *credp, enum called_from called_from)
1070 {
1071 tem_safe_cr(tem);
1072 tem_safe_lf(tem, credp, called_from);
1073 }
1074
1075 static void
1076 tem_safe_cr(struct tem_vt_state *tem)
1077 {
1078 tem->tvs_c_cursor.col = 0;
1079 tem_safe_align_cursor(tem);
1118 credp, called_from);
1119
1120 if (tem->tvs_nscroll == 0) {
1121 /* erase rest of cursor line */
1122 tem_safe_clear_chars(tem,
1123 tems.ts_c_dimension.width -
1124 tem->tvs_c_cursor.col,
1125 tem->tvs_c_cursor.row,
1126 tem->tvs_c_cursor.col,
1127 credp, called_from);
1128
1129 }
1130
1131 tem_safe_align_cursor(tem);
1132 }
1133
1134 static void
1135 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1136 enum called_from called_from)
1137 {
1138 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1139 MUTEX_HELD(&tem->tvs_lock));
1140
1141 if (tem->tvs_outindex == 0) {
1142 tem_safe_align_cursor(tem);
1143 return;
1144 }
1145
1146 tem_safe_virtual_display(tem,
1147 tem->tvs_outbuf, tem->tvs_outindex,
1148 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
1149
1150 if (tem->tvs_isactive) {
1151 /*
1152 * Call the primitive to render this data.
1153 */
1154 tem_safe_callback_display(tem,
1155 tem->tvs_outbuf, tem->tvs_outindex,
1156 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1157 credp, called_from);
1158 }
1159
1160 tem->tvs_outindex = 0;
1161
1162 tem_safe_align_cursor(tem);
1163 }
1164
1165
1166 /*
1167 * We have just done something to the current output point. Reset the start
1168 * point for the buffered data in a_outbuf. There shouldn't be any data
1169 * buffered yet.
1170 */
1171 static void
1172 tem_safe_align_cursor(struct tem_vt_state *tem)
1173 {
1174 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1175 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1176 }
1177
1178 /*
1179 * State machine parser based on the current state and character input
1180 * major terminations are to control character or normal character
1181 */
1182
1183 static void
1184 tem_safe_parse(struct tem_vt_state *tem, tem_char_t ch,
1185 cred_t *credp, enum called_from called_from)
1186 {
1187 int i;
1188
1189 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1190 MUTEX_HELD(&tem->tvs_lock));
1191
1192 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1193 if (ch == A_CSI || ch == A_OSC || ch == A_ESC || ch < ' ') {
1194 /* Control */
1195 tem_safe_control(tem, ch, credp, called_from);
1196 } else {
1197 /* Display */
1198 tem_safe_outch(tem, ch, credp, called_from);
1199 }
1200 return;
1201 }
1202
1203 /* In <ESC> sequence */
1204 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1205 if (tem->tvs_state == A_STATE_OSC) {
1206 tem_safe_get_oscstring(tem, ch, credp, called_from);
1207 return;
1208 }
1209
1210 if (tem->tvs_state != A_STATE_CSI) {
1211 tem_safe_getparams(tem, ch, credp, called_from);
1212 return;
1213 }
1214
1215 switch (ch) {
1216 case '?':
1217 tem->tvs_state = A_STATE_CSI_QMARK;
1218 return;
1219 case '=':
1220 tem->tvs_state = A_STATE_CSI_EQUAL;
1221 return;
1222 case 's':
1223 /*
1224 * As defined below, this sequence
1225 * saves the cursor. However, Sun
1226 * defines ESC[s as reset. We resolved
1227 * the conflict by selecting reset as it
1228 * is exported in the termcap file for
1229 * sun-mon, while the "save cursor"
1300 tem->tvs_nscroll = tems.ts_c_dimension.height;
1301 if (tem->tvs_nscroll < 0)
1302 tem->tvs_nscroll = 1;
1303 tem->tvs_state = A_STATE_START;
1304 return;
1305 default:
1306 tem_safe_getparams(tem, ch, credp, called_from);
1307 return;
1308 }
1309 }
1310
1311 /* Previous char was <ESC> */
1312 if (ch == '[') {
1313 tem->tvs_curparam = 0;
1314 tem->tvs_paramval = 0;
1315 tem->tvs_gotparam = B_FALSE;
1316 /* clear the parameters */
1317 for (i = 0; i < TEM_MAXPARAMS; i++)
1318 tem->tvs_params[i] = -1;
1319 tem->tvs_state = A_STATE_CSI;
1320 } else if (ch == ']') {
1321 tem->tvs_curparam = 0;
1322 tem->tvs_paramval = 0;
1323 tem->tvs_gotparam = B_FALSE;
1324 /* clear the parameters */
1325 for (i = 0; i < TEM_MAXPARAMS; i++)
1326 tem->tvs_params[i] = -1;
1327 tem->tvs_state = A_STATE_OSC;
1328 } else if (ch == 'Q') { /* <ESC>Q ? */
1329 tem->tvs_state = A_STATE_START;
1330 } else if (ch == 'C') { /* <ESC>C ? */
1331 tem->tvs_state = A_STATE_START;
1332 } else {
1333 tem->tvs_state = A_STATE_START;
1334 if (ch == 'c') {
1335 /* ESC c resets display */
1336 tem_safe_reset_display(tem, credp, called_from,
1337 B_TRUE, B_TRUE);
1338 } else if (ch == 'H') {
1339 /* ESC H sets a tab */
1340 tem_safe_set_tab(tem);
1341 } else if (ch == '7') {
1342 /* ESC 7 Save Cursor position */
1343 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1344 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1345 } else if (ch == '8') {
1346 /* ESC 8 Restore Cursor position */
1347 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1468 return;
1469
1470 /*
1471 * Note that very large values of "count" could cause col+count
1472 * to overflow, so we check "count" independently.
1473 */
1474 if (count > tems.ts_c_dimension.width ||
1475 col + count > tems.ts_c_dimension.width)
1476 count = tems.ts_c_dimension.width - col;
1477
1478 tem_safe_virtual_cls(tem, count, row, col);
1479
1480 if (!tem->tvs_isactive)
1481 return;
1482
1483 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1484 }
1485
1486 /*ARGSUSED*/
1487 void
1488 tem_safe_text_display(struct tem_vt_state *tem, term_char_t *string,
1489 int count, screen_pos_t row, screen_pos_t col,
1490 cred_t *credp, enum called_from called_from)
1491 {
1492 struct vis_consdisplay da;
1493 int i;
1494 tem_char_t c;
1495
1496 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1497 called_from == CALLED_FROM_STANDALONE);
1498
1499 da.data = (uint8_t *)&c;
1500 da.width = 1;
1501 da.row = row;
1502 da.col = col;
1503
1504 for (i = 0; i < count; i++) {
1505 tem_safe_get_color(&da.fg_color, &da.bg_color, string[i]);
1506 c = TEM_CHAR(string[i].tc_char);
1507 tems_safe_display(&da, credp, called_from);
1508 da.col++;
1509 }
1510 }
1511
1512 /*
1513 * This function is used to blit a rectangular color image,
1514 * unperturbed on the underlying framebuffer, to render
1515 * icons and pictures. The data is a pixel pattern that
1516 * fills a rectangle bounded to the width and height parameters.
1517 * The color pixel data must to be pre-adjusted by the caller
1518 * for the current video depth.
1519 *
1520 * This function is unused now.
1521 */
1522 /*ARGSUSED*/
1523 static void
1524 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1525 int height, int width, screen_pos_t row, screen_pos_t col,
1526 cred_t *credp, enum called_from called_from)
1527 {
1528 struct vis_consdisplay da;
1529
1530 mutex_enter(&tems.ts_lock);
1531 mutex_enter(&tem->tvs_lock);
1532
1533 da.data = image;
1534 da.width = (screen_size_t)width;
1535 da.height = (screen_size_t)height;
1536 da.row = row;
1537 da.col = col;
1538
1539 tems_safe_display(&da, credp, called_from);
1540
1541 mutex_exit(&tem->tvs_lock);
1542 mutex_exit(&tems.ts_lock);
1543 }
1544
1545 /*ARGSUSED*/
1546 void
1547 tem_safe_text_copy(struct tem_vt_state *tem,
1548 screen_pos_t s_col, screen_pos_t s_row,
1549 screen_pos_t e_col, screen_pos_t e_row,
1550 screen_pos_t t_col, screen_pos_t t_row,
1551 cred_t *credp, enum called_from called_from)
1552 {
1553 struct vis_conscopy da;
1554
1555 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1556 called_from == CALLED_FROM_STANDALONE);
1557
1558 da.s_row = s_row;
1559 da.s_col = s_col;
1560 da.e_row = e_row;
1561 da.e_col = e_col;
1562 da.t_row = t_row;
1563 da.t_col = t_col;
1564
1565 tems_safe_copy(&da, credp, called_from);
1566 }
1567
1568 void
1569 tem_safe_text_cls(struct tem_vt_state *tem,
1570 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1571 enum called_from called_from)
1572 {
1573 text_attr_t attr;
1574 term_char_t c;
1575 int i;
1576
1577 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1578 called_from == CALLED_FROM_STANDALONE);
1579
1580 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
1581 TEM_ATTR_SCREEN_REVERSE);
1582 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
1583
1584 if (count > tems.ts_c_dimension.width ||
1585 col + count > tems.ts_c_dimension.width)
1586 count = tems.ts_c_dimension.width - col;
1587
1588 for (i = 0; i < count; i++)
1589 tems.ts_blank_line[i] = c;
1590
1591 tem_safe_text_display(tem, tems.ts_blank_line, count, row, col,
1592 credp, called_from);
1593 }
1594
1595 void
1596 tem_safe_pix_display(struct tem_vt_state *tem,
1597 term_char_t *string, int count,
1598 screen_pos_t row, screen_pos_t col,
1599 cred_t *credp, enum called_from called_from)
1600 {
1601 struct vis_consdisplay da;
1602 int i;
1603
1604 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1605 called_from == CALLED_FROM_STANDALONE);
1606
1607 da.data = (uchar_t *)tem->tvs_pix_data;
1608 da.width = (screen_size_t)tems.ts_font.vf_width;
1609 da.height = (screen_size_t)tems.ts_font.vf_height;
1610 da.row = (row * da.height) + tems.ts_p_offset.y;
1611 da.col = (col * da.width) + tems.ts_p_offset.x;
1612
1613 for (i = 0; i < count; i++) {
1614 tem_safe_callback_bit2pix(tem, string[i]);
1615 tems_safe_display(&da, credp, called_from);
1616 da.col += da.width;
1617 }
1618 }
1619
1620 void
1621 tem_safe_pix_copy(struct tem_vt_state *tem,
1622 screen_pos_t s_col, screen_pos_t s_row,
1623 screen_pos_t e_col, screen_pos_t e_row,
1624 screen_pos_t t_col, screen_pos_t t_row,
1625 cred_t *credp,
1626 enum called_from called_from)
1627 {
1628 struct vis_conscopy ma;
1629 static boolean_t need_clear = B_TRUE;
1630
1631 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1632 called_from == CALLED_FROM_STANDALONE);
1633
1634 if (need_clear && tem->tvs_first_line > 0) {
1635 /*
1636 * Clear OBP output above our kernel console term
1637 * when our kernel console term begins to scroll up,
1638 * we hope it is user friendly.
1639 * (Also see comments on tem_safe_pix_clear_prom_output)
1640 *
1641 * This is only one time call.
1642 */
1643 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1644 }
1645 need_clear = B_FALSE;
1646
1647 ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
1648 ma.e_row = (e_row + 1) * tems.ts_font.vf_height +
1649 tems.ts_p_offset.y - 1;
1650 ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
1651
1652 /*
1653 * Check if we're in process of clearing OBP's columns area,
1654 * which only happens when term scrolls up a whole line.
1655 */
1656 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1657 e_col == tems.ts_c_dimension.width - 1) {
1658 /*
1659 * We need to clear OBP's columns area outside our kernel
1660 * console term. So that we set ma.e_col to entire row here.
1661 */
1662 ma.s_col = s_col * tems.ts_font.vf_width;
1663 ma.e_col = tems.ts_p_dimension.width - 1;
1664
1665 ma.t_col = t_col * tems.ts_font.vf_width;
1666 } else {
1667 ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
1668 ma.e_col = (e_col + 1) * tems.ts_font.vf_width +
1669 tems.ts_p_offset.x - 1;
1670 ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
1671 }
1672
1673 tems_safe_copy(&ma, credp, called_from);
1674
1675 if (tem->tvs_first_line > 0 && t_row < s_row) {
1676 /* We have scrolled up (s_row - t_row) rows. */
1677 tem->tvs_first_line -= (s_row - t_row);
1678 if (tem->tvs_first_line <= 0) {
1679 /* All OBP rows have been cleared. */
1680 tem->tvs_first_line = 0;
1681 }
1682 }
1683
1684 }
1685
1686 void
1687 tem_safe_pix_bit2pix(struct tem_vt_state *tem, term_char_t c)
1688 {
1689 text_color_t fg, bg;
1690 void (*fp)(struct tem_vt_state *, tem_char_t,
1691 unsigned char, unsigned char);
1692
1693 tem_safe_get_color(&fg, &bg, c);
1694 switch (tems.ts_pdepth) {
1695 case 4:
1696 fp = bit_to_pix4;
1697 break;
1698 case 8:
1699 fp = bit_to_pix8;
1700 break;
1701 case 15:
1702 case 16:
1703 fp = bit_to_pix16;
1704 break;
1705 case 24:
1706 fp = bit_to_pix24;
1707 break;
1708 case 32:
1709 fp = bit_to_pix32;
1710 break;
1711 default:
1712 return;
1713 }
1714
1715 fp(tem, c.tc_char, fg, bg);
1716 }
1717
1718
1719 /*
1720 * This function only clears count of columns in one row
1721 */
1722 void
1723 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
1724 screen_pos_t row, screen_pos_t col, cred_t *credp,
1725 enum called_from called_from)
1726 {
1727 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1728 called_from == CALLED_FROM_STANDALONE);
1729
1730 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
1731 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
1732 }
1733
1734 /*
1735 * This function clears OBP output above our kernel console term area
1741 * _________________________________
1742 * | _____________________ | ---> OBP's bigger term window
1743 * | | | |
1744 * |___| | |
1745 * | | | | |
1746 * | | | | |
1747 * |_|_|___________________|_______|
1748 * | | | ---> first line
1749 * | |___________________|---> our kernel console term window
1750 * |
1751 * |---> columns area to be cleared
1752 *
1753 * This function only takes care of the output above our kernel console term,
1754 * and tem_prom_scroll_up takes care of columns area outside of our kernel
1755 * console term.
1756 */
1757 static void
1758 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1759 enum called_from called_from)
1760 {
1761 int nrows, ncols, width, height, offset;
1762
1763 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1764 called_from == CALLED_FROM_STANDALONE);
1765
1766 width = tems.ts_font.vf_width;
1767 height = tems.ts_font.vf_height;
1768 offset = tems.ts_p_offset.y % height;
1769
1770 nrows = tems.ts_p_offset.y / height;
1771 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1772
1773 if (nrows > 0)
1774 tem_safe_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0,
1775 B_FALSE, credp, called_from);
1776 }
1777
1778 /*
1779 * clear the whole screen for pixel mode, just clear the
1780 * physical screen.
1781 */
1782 void
1783 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1784 enum called_from called_from)
1785 {
1786 struct vis_consclear cl;
1787 text_color_t fg_color;
1788 text_color_t bg_color;
1789 text_attr_t attr;
1790 term_char_t c;
1791 int nrows, ncols, width, height;
1792
1793 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1794 called_from == CALLED_FROM_STANDALONE);
1795
1796 /* call driver first, if error, clear terminal area */
1797 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
1798 TEM_ATTR_SCREEN_REVERSE);
1799 c.tc_char = TEM_ATTR(attr);
1800
1801 tem_safe_get_color(&fg_color, &bg_color, c);
1802 cl.bg_color = bg_color;
1803 if (tems_cls_layered(&cl, credp) == 0)
1804 return;
1805
1806 width = tems.ts_font.vf_width;
1807 height = tems.ts_font.vf_height;
1808
1809 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1810 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1811
1812 tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, 0, ncols,
1813 tems.ts_p_offset.x, B_FALSE, credp, called_from);
1814
1815 /*
1816 * Since the whole screen is cleared, we don't need
1817 * to clear OBP output later.
1818 */
1819 if (tem->tvs_first_line > 0)
1820 tem->tvs_first_line = 0;
1821 }
1822
1823 /*
1824 * clear the whole screen, including the virtual screen buffer,
1825 * and reset the cursor to start point.
1826 */
1827 static void
1828 tem_safe_cls(struct tem_vt_state *tem,
1829 cred_t *credp, enum called_from called_from)
1830 {
1831 int row;
1832
1833 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2111 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2112 called_from == CALLED_FROM_STANDALONE);
2113
2114 ca.row = tem->tvs_c_cursor.row;
2115 ca.col = tem->tvs_c_cursor.col;
2116 ca.action = action;
2117
2118 tems_safe_cursor(&ca, credp, called_from);
2119
2120 if (action == VIS_GET_CURSOR) {
2121 tem->tvs_c_cursor.row = ca.row;
2122 tem->tvs_c_cursor.col = ca.col;
2123 }
2124 }
2125
2126 void
2127 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
2128 cred_t *credp, enum called_from called_from)
2129 {
2130 struct vis_conscursor ca;
2131 uint32_t color;
2132 text_color_t fg, bg;
2133 term_char_t c;
2134 text_attr_t attr;
2135
2136 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2137 called_from == CALLED_FROM_STANDALONE);
2138
2139 ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height +
2140 tems.ts_p_offset.y;
2141 ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width +
2142 tems.ts_p_offset.x;
2143 ca.width = (screen_size_t)tems.ts_font.vf_width;
2144 ca.height = (screen_size_t)tems.ts_font.vf_height;
2145
2146 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2147 TEM_ATTR_REVERSE);
2148 c.tc_char = TEM_ATTR(attr);
2149
2150 tem_safe_get_color(&fg, &bg, c);
2151
2152 switch (tems.ts_pdepth) {
2153 case 4:
2154 ca.fg_color.mono = fg;
2155 ca.bg_color.mono = bg;
2156 break;
2157 case 8:
2158 ca.fg_color.mono = tems.ts_color_map(fg);
2159 ca.bg_color.mono = tems.ts_color_map(bg);
2160 break;
2161 case 15:
2162 case 16:
2163 color = tems.ts_color_map(fg);
2164 ca.fg_color.sixteen[0] = (color >> 8) & 0xFF;
2165 ca.fg_color.sixteen[1] = color & 0xFF;
2166 color = tems.ts_color_map(bg);
2167 ca.bg_color.sixteen[0] = (color >> 8) & 0xFF;
2168 ca.bg_color.sixteen[1] = color & 0xFF;
2169 break;
2170 case 24:
2171 case 32:
2172 #ifdef _HAVE_TEM_FIRMWARE
2173 /* Keeping this block to support old binary only drivers */
2174 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2175 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2176 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2177 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2178
2179 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2180 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2181 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2182 } else {
2183 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2184 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2185 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2186
2187 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2188 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2189 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2190 }
2191 #else
2192 color = tems.ts_color_map(fg);
2193 ca.fg_color.twentyfour[0] = (color >> 16) & 0xFF;
2194 ca.fg_color.twentyfour[1] = (color >> 8) & 0xFF;
2195 ca.fg_color.twentyfour[2] = color & 0xFF;
2196 color = tems.ts_color_map(bg);
2197 ca.bg_color.twentyfour[0] = (color >> 16) & 0xFF;
2198 ca.bg_color.twentyfour[1] = (color >> 8) & 0xFF;
2199 ca.bg_color.twentyfour[2] = color & 0xFF;
2200 break;
2201 #endif
2202 }
2203
2204 ca.action = action;
2205
2206 tems_safe_cursor(&ca, credp, called_from);
2207
2208 if (action == VIS_GET_CURSOR) {
2209 tem->tvs_c_cursor.row = 0;
2210 tem->tvs_c_cursor.col = 0;
2211
2212 if (ca.row != 0) {
2213 tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) /
2214 tems.ts_font.vf_height;
2215 }
2216 if (ca.col != 0) {
2217 tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) /
2218 tems.ts_font.vf_width;
2219 }
2220 }
2221 }
2222
2223 static void
2224 bit_to_pix4(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color,
2225 text_color_t bg_color)
2226 {
2227 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2228 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
2229 }
2230
2231 static void
2232 bit_to_pix8(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color,
2233 text_color_t bg_color)
2234 {
2235 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2236
2237 fg_color = (text_color_t)tems.ts_color_map(fg_color);
2238 bg_color = (text_color_t)tems.ts_color_map(bg_color);
2239 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
2240 }
2241
2242 static void
2243 bit_to_pix16(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4,
2244 text_color_t bg_color4)
2245 {
2246 uint16_t fg_color16, bg_color16;
2247 uint16_t *dest;
2248
2249 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2250
2251 fg_color16 = (uint16_t)tems.ts_color_map(fg_color4);
2252 bg_color16 = (uint16_t)tems.ts_color_map(bg_color4);
2253
2254 dest = (uint16_t *)tem->tvs_pix_data;
2255 font_bit_to_pix16(&tems.ts_font, dest, c, fg_color16, bg_color16);
2256 }
2257
2258 static void
2259 bit_to_pix24(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4,
2260 text_color_t bg_color4)
2261 {
2262 uint32_t fg_color32, bg_color32;
2263 uint8_t *dest;
2264
2265 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2266
2267 #ifdef _HAVE_TEM_FIRMWARE
2268 fg_color32 = PIX4TO32(fg_color4);
2269 bg_color32 = PIX4TO32(bg_color4);
2270 #else
2271 fg_color32 = tems.ts_color_map(fg_color4);
2272 bg_color32 = tems.ts_color_map(bg_color4);
2273 #endif
2274
2275 dest = (uint8_t *)tem->tvs_pix_data;
2276 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
2277 }
2278
2279 static void
2280 bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, text_color_t fg_color4,
2281 text_color_t bg_color4)
2282 {
2283 uint32_t fg_color32, bg_color32, *dest;
2284
2285 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2286
2287 #ifdef _HAVE_TEM_FIRMWARE
2288 fg_color32 = PIX4TO32(fg_color4);
2289 bg_color32 = PIX4TO32(bg_color4);
2290 #else
2291 fg_color32 = ((uint32_t)0xFF << 24) | tems.ts_color_map(fg_color4);
2292 bg_color32 = ((uint32_t)0xFF << 24) | tems.ts_color_map(bg_color4);
2293 #endif
2294
2295 dest = (uint32_t *)tem->tvs_pix_data;
2296 font_bit_to_pix32(&tems.ts_font, dest, c, fg_color32, bg_color32);
2297 }
2298
2299 /*
2300 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2301 */
2302 void
2303 tem_safe_get_attr(struct tem_vt_state *tem, text_color_t *fg,
2304 text_color_t *bg, text_attr_t *attr, uint8_t flag)
2305 {
2306 if (tem->tvs_flags & flag) {
2307 *fg = tem->tvs_bg_color;
2308 *bg = tem->tvs_fg_color;
2309 } else {
2310 *fg = tem->tvs_fg_color;
2311 *bg = tem->tvs_bg_color;
2312 }
2313
2314 if (attr == NULL)
2315 return;
2316
2317 *attr = tem->tvs_flags;
2318 }
2319
2320 static void
2321 tem_safe_get_color(text_color_t *fg, text_color_t *bg, term_char_t c)
2322 {
2323 if (TEM_CHAR_ATTR(c.tc_char) & (TEM_ATTR_BRIGHT_FG | TEM_ATTR_BOLD))
2324 *fg = brt_xlate[c.tc_fg_color];
2325 else
2326 *fg = dim_xlate[c.tc_fg_color];
2327
2328 if (TEM_CHAR_ATTR(c.tc_char) & TEM_ATTR_BRIGHT_BG)
2329 *bg = brt_xlate[c.tc_bg_color];
2330 else
2331 *bg = dim_xlate[c.tc_bg_color];
2332 }
2333
2334 /*
2335 * Clear a rectangle of screen for pixel mode.
2336 *
2337 * arguments:
2338 * row: start row#
2339 * nrows: the number of rows to clear
2340 * offset_y: the offset of height in pixels to begin clear
2341 * col: start col#
2342 * ncols: the number of cols to clear
2343 * offset_x: the offset of width in pixels to begin clear
2344 * scroll_up: whether this function is called during sroll up,
2345 * which is called only once.
2346 */
2347 void
2348 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2349 screen_pos_t row, int nrows, int offset_y,
2350 screen_pos_t col, int ncols, int offset_x,
2351 boolean_t sroll_up, cred_t *credp,
2352 enum called_from called_from)
2353 {
2354 struct vis_consdisplay da;
2355 int i, j;
2356 int row_add = 0;
2357 term_char_t c;
2358 text_attr_t attr;
2359
2360 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2361 called_from == CALLED_FROM_STANDALONE);
2362
2363 if (sroll_up)
2364 row_add = tems.ts_c_dimension.height - 1;
2365
2366 da.width = (screen_size_t)tems.ts_font.vf_width;
2367 da.height = (screen_size_t)tems.ts_font.vf_height;
2368
2369 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2370 TEM_ATTR_SCREEN_REVERSE);
2371 /* Make sure we will not draw underlines */
2372 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
2373
2374 tem_safe_callback_bit2pix(tem, c);
2375 da.data = (uchar_t *)tem->tvs_pix_data;
2376
2377 for (i = 0; i < nrows; i++, row++) {
2378 da.row = (row + row_add) * da.height + offset_y;
2379 da.col = col * da.width + offset_x;
2380 for (j = 0; j < ncols; j++) {
2381 tems_safe_display(&da, credp, called_from);
2382 da.col += da.width;
2383 }
2384 }
2385 }
2386
2387 /*
2388 * virtual screen operations
2389 */
2390 static void
2391 tem_safe_virtual_display(struct tem_vt_state *tem, term_char_t *string,
2392 int count, screen_pos_t row, screen_pos_t col)
2393 {
2394 int i, width;
2395 term_char_t *addr;
2396
2397 if (row < 0 || row >= tems.ts_c_dimension.height ||
2398 col < 0 || col >= tems.ts_c_dimension.width ||
2399 col + count > tems.ts_c_dimension.width)
2400 return;
2401
2402 width = tems.ts_c_dimension.width;
2403 addr = tem->tvs_screen_buf + (row * width + col);
2404 for (i = 0; i < count; i++) {
2405 *addr++ = string[i];
2406 }
2407 }
2408
2409 static void
2410 i_virtual_copy_tem_chars(term_char_t *base,
2411 screen_pos_t s_col, screen_pos_t s_row,
2412 screen_pos_t e_col, screen_pos_t e_row,
2413 screen_pos_t t_col, screen_pos_t t_row)
2414 {
2415 term_char_t *from;
2416 term_char_t *to;
2417 int cnt;
2418 screen_size_t chars_per_row;
2419 term_char_t *to_row_start;
2420 term_char_t *from_row_start;
2421 screen_size_t rows_to_move;
2422 int cols = tems.ts_c_dimension.width;
2423
2424 chars_per_row = e_col - s_col + 1;
2425 rows_to_move = e_row - s_row + 1;
2426
2427 to_row_start = base + ((t_row * cols) + t_col);
2428 from_row_start = base + ((s_row * cols) + s_col);
2429
2430 if (to_row_start < from_row_start) {
2431 while (rows_to_move-- > 0) {
2432 to = to_row_start;
2433 from = from_row_start;
2434 to_row_start += cols;
2435 from_row_start += cols;
2436 for (cnt = chars_per_row; cnt-- > 0; )
2437 *to++ = *from++;
2438 }
2439 } else {
2440 /*
2467 int cols = tems.ts_c_dimension.width;
2468
2469 if (s_col < 0 || s_col >= cols ||
2470 s_row < 0 || s_row >= rows ||
2471 e_col < 0 || e_col >= cols ||
2472 e_row < 0 || e_row >= rows ||
2473 t_col < 0 || t_col >= cols ||
2474 t_row < 0 || t_row >= rows ||
2475 s_col > e_col ||
2476 s_row > e_row)
2477 return;
2478
2479 chars_per_row = e_col - s_col + 1;
2480 rows_to_move = e_row - s_row + 1;
2481
2482 /* More sanity checks. */
2483 if (t_row + rows_to_move > rows ||
2484 t_col + chars_per_row > cols)
2485 return;
2486
2487 i_virtual_copy_tem_chars(tem->tvs_screen_buf, s_col, s_row,
2488 e_col, e_row, t_col, t_row);
2489 }
2490
2491 static void
2492 tem_safe_virtual_cls(struct tem_vt_state *tem,
2493 int count, screen_pos_t row, screen_pos_t col)
2494 {
2495 int i;
2496 text_attr_t attr;
2497 term_char_t c;
2498
2499 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2500 TEM_ATTR_SCREEN_REVERSE);
2501 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
2502
2503 for (i = 0; i < tems.ts_c_dimension.width; i++)
2504 tems.ts_blank_line[i] = c;
2505
2506 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col);
2507 }
2508
2509 /*
2510 * only blank screen, not clear our screen buffer
2511 */
2512 void
2513 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2514 enum called_from called_from)
2515 {
2516 int row;
2517
2518 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2519 called_from == CALLED_FROM_STANDALONE);
2520
2521 if (tems.ts_display_mode == VIS_PIXEL) {
2522 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2523 return;
2524 }
2525
2526 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2527 tem_safe_callback_cls(tem,
2528 tems.ts_c_dimension.width,
2529 row, 0, credp, called_from);
2530 }
2531 }
2532
2533 /*
2534 * unblank screen with associated tem from its screen buffer
2535 */
2536 void
2537 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2538 enum called_from called_from)
2539 {
2540 int row;
2541
2542 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2543 called_from == CALLED_FROM_STANDALONE);
2544
2545 if (tems.ts_display_mode == VIS_PIXEL)
2546 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2547
2548 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2549
2550 /*
2551 * Display data in tvs_screen_buf to the actual framebuffer in a
2552 * row by row way.
2553 * When dealing with one row, output data with the same foreground
2554 * and background color all together.
2555 */
2556 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2557 tem_safe_callback_display(tem, tem->tvs_screen_rows[row],
2558 tems.ts_c_dimension.width, row, 0, credp, called_from);
2559 }
2560
2561 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
2562 }
|