1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2016 Joyent, Inc.
29 * Copyright 2021 Toomas Soome <tsoome@me.com>
30 * Copyright 2021 RackTop Systems, Inc.
31 */
32
33 /*
34 * Polled I/O safe ANSI terminal emulator module;
35 * Supporting TERM types 'sun' and 'sun-color, parsing
36 * ANSI x3.64 escape sequences, and the like. (See wscons(4D)
37 * for more information).
38 *
39 * IMPORTANT:
40 *
41 * The functions in this file *must* be able to function in
42 * standalone mode, ie. on a quiesced system. In that state,
43 * access is single threaded, only one CPU is running.
44 * System services are NOT available.
45 *
46 * The following restrictions pertain to every function
47 * in this file:
48 *
49 * - CANNOT use the DDI or LDI interfaces
50 * - CANNOT call system services
51 * - CANNOT use mutexes
52 * - CANNOT wait for interrupts
53 * - CANNOT allocate memory
54 *
55 * All non-static functions in this file which:
56 * - Operates on tems and tem_vt_state
57 * - Not only called from standalone mode, i.e. has
58 * a "calledfrom" argument
59 * should assert this at the beginning:
60 *
61 * ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
62 * called_from == CALLED_FROM_STANDALONE);
63 *
64 * Color support:
65 * Text mode can only support standard system colors, 4-bit [0-15] indexed.
66 * On framebuffer devices, we can aditionally use [16-255] or truecolor.
67 * Additional colors can be used via CSI 38 and CSI 48 sequences.
68 * CSI 38/48;5 is using indexed colors [0-255], CSI 38/48;2 does
69 * specify color by RGB triple.
70 *
71 * While sending glyphs to display, we need to process glyph attributes:
72 * TEM_ATTR_BOLD will cause BOLD font to be used (or BRIGHT color if we
73 * we use indexed color [0-7]).
74 * We ignore TEM_ATTR_BRIGHT_FG/TEM_ATTR_BRIGHT_BG with RGB colors.
75 * TEM_ATTR_REVERSE and TEM_ATTR_SCREEN_REVERSE will cause fg and bg to be
76 * swapped.
77 */
78
79 #include <sys/types.h>
80 #include <sys/ascii.h>
81 #include <sys/visual_io.h>
82 #include <sys/font.h>
83 #include <sys/tem.h>
84 #include <sys/tem_impl.h>
85 #include <sys/ksynch.h>
86 #include <sys/sysmacros.h>
87 #include <sys/mutex.h>
88 #include <sys/note.h>
89 #include <sys/t_lock.h>
90
91 tem_safe_callbacks_t tem_safe_text_callbacks = {
92 &tem_safe_text_display,
93 &tem_safe_text_copy,
94 &tem_safe_text_cursor,
95 NULL,
96 &tem_safe_text_cls
97 };
98 tem_safe_callbacks_t tem_safe_pix_callbacks = {
99 &tem_safe_pix_display,
100 &tem_safe_pix_copy,
101 &tem_safe_pix_cursor,
102 &tem_safe_pix_bit2pix,
103 &tem_safe_pix_cls
104 };
105
106 static void tem_safe_control(struct tem_vt_state *, tem_char_t,
107 cred_t *, enum called_from);
108 static void tem_safe_setparam(struct tem_vt_state *, int, int);
109 static void tem_safe_selgraph(struct tem_vt_state *);
110 static void tem_safe_chkparam(struct tem_vt_state *, tem_char_t,
111 cred_t *, enum called_from);
112 static void tem_safe_getparams(struct tem_vt_state *, tem_char_t,
113 cred_t *, enum called_from);
114 static void tem_safe_outch(struct tem_vt_state *, tem_char_t,
115 cred_t *, enum called_from);
116 static void tem_safe_parse(struct tem_vt_state *, tem_char_t,
117 cred_t *, enum called_from);
118
119 static void tem_safe_new_line(struct tem_vt_state *,
120 cred_t *, enum called_from);
121 static void tem_safe_cr(struct tem_vt_state *);
122 static void tem_safe_lf(struct tem_vt_state *,
123 cred_t *, enum called_from);
124 static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
125 enum called_from);
126 static void tem_safe_cls(struct tem_vt_state *,
127 cred_t *, enum called_from);
128 static void tem_safe_tab(struct tem_vt_state *,
129 cred_t *, enum called_from);
130 static void tem_safe_back_tab(struct tem_vt_state *,
131 cred_t *, enum called_from);
132 static void tem_safe_clear_tabs(struct tem_vt_state *, int);
133 static void tem_safe_set_tab(struct tem_vt_state *);
134 static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
135 cred_t *, enum called_from);
136 static void tem_safe_shift(struct tem_vt_state *, int, int,
137 cred_t *, enum called_from);
138 static void tem_safe_scroll(struct tem_vt_state *, int, int,
139 int, int, cred_t *, enum called_from);
140 static void tem_safe_clear_chars(struct tem_vt_state *tem,
141 int count, screen_pos_t row, screen_pos_t col,
142 cred_t *credp, enum called_from called_from);
143 static void tem_safe_copy_area(struct tem_vt_state *tem,
144 screen_pos_t s_col, screen_pos_t s_row,
145 screen_pos_t e_col, screen_pos_t e_row,
146 screen_pos_t t_col, screen_pos_t t_row,
147 cred_t *credp, enum called_from called_from);
148 #if 0
149 /* Currently unused */
150 static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
151 int, int, screen_pos_t, screen_pos_t,
152 cred_t *, enum called_from);
153 #endif
154 static void tem_safe_bell(struct tem_vt_state *tem,
155 enum called_from called_from);
156 static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
157 cred_t *credp, enum called_from called_from);
158 static void tem_safe_get_color(struct tem_vt_state *,
159 text_color_t *, text_color_t *, term_char_t *);
160 static void tem_safe_set_color(text_color_t *, color_t *);
161
162 static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
163 screen_pos_t);
164 static void tem_safe_virtual_display(struct tem_vt_state *,
165 term_char_t *, int, screen_pos_t, screen_pos_t);
166 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
167 screen_pos_t, screen_pos_t, screen_pos_t,
168 screen_pos_t, screen_pos_t);
169 static void tem_safe_align_cursor(struct tem_vt_state *tem);
170 static void bit_to_pix4(struct tem_vt_state *tem, tem_char_t c,
171 text_color_t fg_color, text_color_t bg_color);
172 static void bit_to_pix8(struct tem_vt_state *tem, tem_char_t c,
173 text_color_t fg_color, text_color_t bg_color);
174 static void bit_to_pix16(struct tem_vt_state *tem, tem_char_t c,
175 text_color_t fg_color, text_color_t bg_color);
176 static void bit_to_pix24(struct tem_vt_state *tem, tem_char_t c,
177 text_color_t fg_color, text_color_t bg_color);
178 static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c,
179 text_color_t fg_color, text_color_t bg_color);
180
181 #define PIX4TO32(pix4) (uint32_t)( \
182 cmap4_to_24.red[pix4] << 16 | \
183 cmap4_to_24.green[pix4] << 8 | \
184 cmap4_to_24.blue[pix4])
185
186 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
187 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
188 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
189 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
190 #define tem_safe_callback_bit2pix(tem, c) { \
191 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
192 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c));\
193 }
194
195 void
tem_safe_check_first_time(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)196 tem_safe_check_first_time(
197 struct tem_vt_state *tem,
198 cred_t *credp,
199 enum called_from called_from)
200 {
201 static int first_time = 1;
202
203 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
204 called_from == CALLED_FROM_STANDALONE);
205
206 /*
207 * Realign the console cursor. We did this in tem_init().
208 * However, drivers in the console stream may emit additional
209 * messages before we are ready. This causes text overwrite
210 * on the screen. This is a workaround.
211 */
212 if (!first_time)
213 return;
214
215 first_time = 0;
216 if (tems.ts_display_mode == VIS_TEXT)
217 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
218 else
219 tem_safe_pix_cursor(tem, VIS_GET_CURSOR, credp, called_from);
220 tem_safe_align_cursor(tem);
221 }
222
223 /*
224 * This entry point handles output requests from restricted contexts like
225 * kmdb, where services like mutexes are not available. This function
226 * is entered when OBP or when a kernel debugger (such as kmdb)
227 * are generating console output. In those cases, power management
228 * concerns are handled by the abort sequence initiation (ie. when
229 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
230 * It is also entered when the kernel is panicing.
231 */
232 void
tem_safe_polled_write(tem_vt_state_t tem_arg,uchar_t * buf,int len)233 tem_safe_polled_write(
234 tem_vt_state_t tem_arg,
235 uchar_t *buf,
236 int len)
237 {
238 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
239
240 #ifdef __lock_lint
241 _NOTE(NO_COMPETING_THREADS_NOW)
242 _NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
243 #endif
244
245 if (!tem->tvs_initialized) {
246 return;
247 }
248
249 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
250 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
251 }
252
253 /* Process partial UTF-8 sequence. */
254 static void
tem_safe_input_partial(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)255 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
256 enum called_from called_from)
257 {
258 unsigned i;
259 uint8_t c;
260
261 if (tem->tvs_utf8_left == 0)
262 return;
263
264 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
265 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
266 if (c != 0) {
267 tem_safe_parse(tem, c, credp, called_from);
268 }
269 }
270 tem->tvs_utf8_left = 0;
271 tem->tvs_utf8_partial = 0;
272 }
273
274 /*
275 * Handle UTF-8 sequences.
276 */
277 static void
tem_safe_input_byte(struct tem_vt_state * tem,uchar_t c,cred_t * credp,enum called_from called_from)278 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
279 enum called_from called_from)
280 {
281 /*
282 * Check for UTF-8 code points. In case of error fall back to
283 * 8-bit code. As we only have 8859-1 fonts for console, this will set
284 * the limits on what chars we actually can display, therefore we
285 * have to return to this code once we have solved the font issue.
286 */
287 if ((c & 0x80) == 0x00) {
288 /* One-byte sequence. */
289 tem_safe_input_partial(tem, credp, called_from);
290 tem_safe_parse(tem, c, credp, called_from);
291 return;
292 }
293 if ((c & 0xe0) == 0xc0) {
294 /* Two-byte sequence. */
295 tem_safe_input_partial(tem, credp, called_from);
296 tem->tvs_utf8_left = 1;
297 tem->tvs_utf8_partial = c;
298 return;
299 }
300 if ((c & 0xf0) == 0xe0) {
301 /* Three-byte sequence. */
302 tem_safe_input_partial(tem, credp, called_from);
303 tem->tvs_utf8_left = 2;
304 tem->tvs_utf8_partial = c;
305 return;
306 }
307 if ((c & 0xf8) == 0xf0) {
308 /* Four-byte sequence. */
309 tem_safe_input_partial(tem, credp, called_from);
310 tem->tvs_utf8_left = 3;
311 tem->tvs_utf8_partial = c;
312 return;
313 }
314 if ((c & 0xc0) == 0x80) {
315 /* Invalid state? */
316 if (tem->tvs_utf8_left == 0) {
317 tem_safe_parse(tem, c, credp, called_from);
318 return;
319 }
320 tem->tvs_utf8_left--;
321 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
322 if (tem->tvs_utf8_left == 0) {
323 tem_char_t v, u;
324 uint8_t b;
325
326 /*
327 * Transform the sequence of 2 to 4 bytes to
328 * unicode number.
329 */
330 v = 0;
331 u = tem->tvs_utf8_partial;
332 b = (u >> 24) & 0xff;
333 if (b != 0) { /* Four-byte sequence */
334 v = b & 0x07;
335 b = (u >> 16) & 0xff;
336 v = (v << 6) | (b & 0x3f);
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 >> 16) & 0xff) != 0) {
342 v = b & 0x0f; /* Three-byte sequence */
343 b = (u >> 8) & 0xff;
344 v = (v << 6) | (b & 0x3f);
345 b = u & 0xff;
346 v = (v << 6) | (b & 0x3f);
347 } else if ((b = (u >> 8) & 0xff) != 0) {
348 v = b & 0x1f; /* Two-byte sequence */
349 b = u & 0xff;
350 v = (v << 6) | (b & 0x3f);
351 }
352
353 tem_safe_parse(tem, v, credp, called_from);
354 tem->tvs_utf8_partial = 0;
355 }
356 return;
357 }
358 /* Anything left is illegal in UTF-8 sequence. */
359 tem_safe_input_partial(tem, credp, called_from);
360 tem_safe_parse(tem, c, credp, called_from);
361 }
362
363 /*
364 * This is the main entry point into the terminal emulator.
365 *
366 * For each data message coming downstream, ANSI assumes that it is composed
367 * of ASCII characters, which are treated as a byte-stream input to the
368 * parsing state machine. All data is parsed immediately -- there is
369 * no enqueing.
370 */
371 void
tem_safe_terminal_emulate(struct tem_vt_state * tem,uchar_t * buf,int len,cred_t * credp,enum called_from called_from)372 tem_safe_terminal_emulate(
373 struct tem_vt_state *tem,
374 uchar_t *buf,
375 int len,
376 cred_t *credp,
377 enum called_from called_from)
378 {
379
380 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
381 called_from == CALLED_FROM_STANDALONE);
382
383 if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
384 tem_safe_callback_cursor(tem,
385 VIS_HIDE_CURSOR, credp, called_from);
386
387 for (; len > 0; len--, buf++)
388 tem_safe_input_byte(tem, *buf, credp, called_from);
389
390 /*
391 * Send the data we just got to the framebuffer.
392 */
393 tem_safe_send_data(tem, credp, called_from);
394
395 if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
396 tem_safe_callback_cursor(tem,
397 VIS_DISPLAY_CURSOR, credp, called_from);
398 }
399
400 /*
401 * Display an rectangular image on the frame buffer using the
402 * mechanism appropriate for the system state being called
403 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
404 */
405 static void
tems_safe_display(struct vis_consdisplay * pda,cred_t * credp,enum called_from called_from)406 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
407 enum called_from called_from)
408 {
409 if (called_from == CALLED_FROM_STANDALONE)
410 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
411 else
412 tems_display_layered(pda, credp);
413 }
414
415 /*
416 * Copy a rectangle from one location to another on the frame buffer
417 * using the mechanism appropriate for the system state being called
418 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
419 */
420 void
tems_safe_copy(struct vis_conscopy * pca,cred_t * credp,enum called_from called_from)421 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
422 enum called_from called_from)
423 {
424 if (called_from == CALLED_FROM_STANDALONE)
425 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
426 else
427 tems_copy_layered(pca, credp);
428 }
429
430 /*
431 * Display or hide a rectangular block text cursor of a specificsize
432 * at a specific location on frame buffer* using the mechanism
433 * appropriate for the system state being called from, quisced or
434 * normal (ie. use polled I/O vs. layered ioctls).
435 */
436 static void
tems_safe_cursor(struct vis_conscursor * pca,cred_t * credp,enum called_from called_from)437 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
438 enum called_from called_from)
439 {
440 if (called_from == CALLED_FROM_STANDALONE)
441 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
442 else
443 tems_cursor_layered(pca, credp);
444 }
445
446 /*
447 * send the appropriate control message or set state based on the
448 * value of the control character ch
449 */
450
451 static void
tem_safe_control(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)452 tem_safe_control(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
453 enum called_from called_from)
454 {
455 tem->tvs_state = A_STATE_START;
456 switch (ch) {
457 case A_BEL:
458 tem_safe_bell(tem, called_from);
459 break;
460
461 case A_BS:
462 tem_safe_mv_cursor(tem,
463 tem->tvs_c_cursor.row,
464 tem->tvs_c_cursor.col - 1,
465 credp, called_from);
466 break;
467
468 case A_HT:
469 tem_safe_tab(tem, credp, called_from);
470 break;
471
472 case A_NL:
473 /*
474 * tem_safe_send_data(tem, credp, called_from);
475 * tem_safe_new_line(tem, credp, called_from);
476 * break;
477 */
478
479 case A_VT:
480 tem_safe_send_data(tem, credp, called_from);
481 tem_safe_lf(tem, credp, called_from);
482 break;
483
484 case A_FF:
485 tem_safe_send_data(tem, credp, called_from);
486 tem_safe_cls(tem, credp, called_from);
487 break;
488
489 case A_CR:
490 tem_safe_send_data(tem, credp, called_from);
491 tem_safe_cr(tem);
492 break;
493
494 case A_ESC:
495 tem->tvs_state = A_STATE_ESC;
496 break;
497
498 case A_CSI:
499 {
500 int i;
501 tem->tvs_curparam = 0;
502 tem->tvs_paramval = 0;
503 tem->tvs_gotparam = B_FALSE;
504 /* clear the parameters */
505 for (i = 0; i < TEM_MAXPARAMS; i++)
506 tem->tvs_params[i] = -1;
507 tem->tvs_state = A_STATE_CSI;
508 }
509 break;
510
511 case A_GS:
512 tem_safe_back_tab(tem, credp, called_from);
513 break;
514
515 default:
516 break;
517 }
518 }
519
520
521 /*
522 * if parameters [0..count - 1] are not set, set them to the value
523 * of newparam.
524 */
525
526 static void
tem_safe_setparam(struct tem_vt_state * tem,int count,int newparam)527 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
528 {
529 int i;
530
531 for (i = 0; i < count; i++) {
532 if (tem->tvs_params[i] == -1)
533 tem->tvs_params[i] = newparam;
534 }
535 }
536
537 /*
538 * For colors 0-15 the tem is using color code translation
539 * from sun colors to vga (dim_xlate and brt_xlate tables, see tem_get_color).
540 * Colors 16-255 are used without translation.
541 */
542 static void
tem_select_color(struct tem_vt_state * tem,int color,boolean_t fg)543 tem_select_color(struct tem_vt_state *tem, int color, boolean_t fg)
544 {
545 if (color < 0 || color > 255)
546 return;
547
548 /* VGA text mode only does support 16 colors. */
549 if (tems.ts_display_mode == VIS_TEXT && color > 15)
550 return;
551
552 /* Switch to use indexed colors. */
553 if (fg == B_TRUE) {
554 tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
555 tem->tvs_fg_color.n = color;
556 } else {
557 tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
558 tem->tvs_bg_color.n = color;
559 }
560
561 /*
562 * For colors 0-7, make sure the BRIGHT attribute is not set.
563 */
564 if (color < 8) {
565 if (fg == B_TRUE)
566 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
567 else
568 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
569 return;
570 }
571
572 /*
573 * For colors 8-15, we use color codes 0-7 and set BRIGHT attribute.
574 */
575 if (color < 16) {
576 if (fg == B_TRUE) {
577 tem->tvs_fg_color.n -= 8;
578 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
579 } else {
580 tem->tvs_bg_color.n -= 8;
581 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
582 }
583 }
584 }
585
586 /*
587 * select graphics mode based on the param vals stored in a_params
588 */
589 static void
tem_safe_selgraph(struct tem_vt_state * tem)590 tem_safe_selgraph(struct tem_vt_state *tem)
591 {
592 int curparam;
593 int count = 0;
594 int param;
595 int r, g, b;
596
597 tem->tvs_state = A_STATE_START;
598
599 curparam = tem->tvs_curparam;
600 do {
601 param = tem->tvs_params[count];
602
603 switch (param) {
604 case -1:
605 case 0:
606 /* reset to initial normal settings */
607 tem->tvs_fg_color = tems.ts_init_color.fg_color;
608 tem->tvs_bg_color = tems.ts_init_color.bg_color;
609 tem->tvs_flags = tems.ts_init_color.a_flags;
610 break;
611
612 case 1: /* Bold Intense */
613 tem->tvs_flags |= TEM_ATTR_BOLD;
614 break;
615
616 case 2: /* Faint Intense */
617 tem->tvs_flags &= ~TEM_ATTR_BOLD;
618 break;
619
620 case 4: /* Underline */
621 tem->tvs_flags |= TEM_ATTR_UNDERLINE;
622 break;
623 case 5: /* Blink */
624 tem->tvs_flags |= TEM_ATTR_BLINK;
625 break;
626
627 case 7: /* Reverse video */
628 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
629 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
630 } else {
631 tem->tvs_flags |= TEM_ATTR_REVERSE;
632 }
633 break;
634
635 case 22: /* Remove Bold */
636 tem->tvs_flags &= ~TEM_ATTR_BOLD;
637 break;
638
639 case 24: /* Remove Underline */
640 tem->tvs_flags &= ~TEM_ATTR_UNDERLINE;
641 break;
642
643 case 25: /* Remove Blink */
644 tem->tvs_flags &= ~TEM_ATTR_BLINK;
645 break;
646
647 case 27: /* Remove Reverse */
648 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
649 tem->tvs_flags |= TEM_ATTR_REVERSE;
650 } else {
651 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
652 }
653 break;
654
655 case 30: /* black (grey) foreground */
656 case 31: /* red (light red) foreground */
657 case 32: /* green (light green) foreground */
658 case 33: /* brown (yellow) foreground */
659 case 34: /* blue (light blue) foreground */
660 case 35: /* magenta (light magenta) foreground */
661 case 36: /* cyan (light cyan) foreground */
662 case 37: /* white (bright white) foreground */
663 tem->tvs_fg_color.n = param - 30;
664 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
665 tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
666 break;
667
668 case 38:
669 /*
670 * We should have 3 parameters for 256 colors and
671 * 5 parameters for 24-bit colors.
672 */
673 if (curparam < 3) {
674 curparam = 0;
675 break;
676 }
677
678 /*
679 * 256 and truecolor needs depth at least 24, but
680 * we still need to process the sequence.
681 */
682 count++;
683 curparam--;
684 param = tem->tvs_params[count];
685 switch (param) {
686 case 2: /* RGB colors */
687 if (curparam < 4) {
688 curparam = 0;
689 break;
690 }
691 r = tem->tvs_params[++count];
692 g = tem->tvs_params[++count];
693 b = tem->tvs_params[++count];
694 curparam -= 3;
695 if (r < 0 || r > 255 || g < 0 || g > 255 ||
696 b < 0 || b > 255)
697 break;
698
699 if (tems.ts_display_mode == VIS_PIXEL &&
700 tems.ts_pdepth > 8) {
701 tem->tvs_flags |= TEM_ATTR_RGB_FG;
702 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
703 tem->tvs_fg_color.rgb.a =
704 tem->tvs_alpha;
705 tem->tvs_fg_color.rgb.r = r;
706 tem->tvs_fg_color.rgb.g = g;
707 tem->tvs_fg_color.rgb.b = b;
708 }
709 break;
710 case 5: /* 256 colors */
711 count++;
712 curparam--;
713 tem_select_color(tem, tem->tvs_params[count],
714 B_TRUE);
715 break;
716 default:
717 curparam = 0;
718 break;
719 }
720 break;
721
722 case 39:
723 /*
724 * Reset the foreground colour and brightness.
725 */
726 tem->tvs_fg_color = tems.ts_init_color.fg_color;
727 tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
728 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
729 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
730 else
731 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
732 break;
733
734 case 40: /* black (grey) background */
735 case 41: /* red (light red) background */
736 case 42: /* green (light green) background */
737 case 43: /* brown (yellow) background */
738 case 44: /* blue (light blue) background */
739 case 45: /* magenta (light magenta) background */
740 case 46: /* cyan (light cyan) background */
741 case 47: /* white (bright white) background */
742 tem->tvs_bg_color.n = param - 40;
743 tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
744 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
745 break;
746
747 case 48:
748 /*
749 * We should have 3 parameters for 256 colors and
750 * 5 parameters for 24-bit colors.
751 */
752 if (curparam < 3) {
753 curparam = 0;
754 break;
755 }
756
757 /*
758 * 256 and truecolor needs depth at least 24, but
759 * we still need to process the sequence.
760 */
761 count++;
762 curparam--;
763 param = tem->tvs_params[count];
764 switch (param) {
765 case 2: /* RGB colors */
766 if (curparam < 4) {
767 curparam = 0;
768 break;
769 }
770 r = tem->tvs_params[++count];
771 g = tem->tvs_params[++count];
772 b = tem->tvs_params[++count];
773 curparam -= 3;
774 if (r < 0 || r > 255 || g < 0 || g > 255 ||
775 b < 0 || b > 255)
776 break;
777
778 if (tems.ts_display_mode == VIS_PIXEL &&
779 tems.ts_pdepth > 8) {
780 tem->tvs_flags |= TEM_ATTR_RGB_BG;
781 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
782 tem->tvs_bg_color.rgb.a =
783 tem->tvs_alpha;
784 tem->tvs_bg_color.rgb.r = r;
785 tem->tvs_bg_color.rgb.g = g;
786 tem->tvs_bg_color.rgb.b = b;
787 }
788 break;
789 case 5: /* 256 colors */
790 count++;
791 curparam--;
792 tem_select_color(tem, tem->tvs_params[count],
793 B_FALSE);
794 break;
795 default:
796 curparam = 0;
797 break;
798 }
799 break;
800
801 case 49:
802 /*
803 * Reset the background colour and brightness.
804 */
805 tem->tvs_bg_color = tems.ts_init_color.bg_color;
806 tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
807 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
808 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
809 else
810 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
811 break;
812
813 case 90: /* black (grey) foreground */
814 case 91: /* red (light red) foreground */
815 case 92: /* green (light green) foreground */
816 case 93: /* brown (yellow) foreground */
817 case 94: /* blue (light blue) foreground */
818 case 95: /* magenta (light magenta) foreground */
819 case 96: /* cyan (light cyan) foreground */
820 case 97: /* white (bright white) foreground */
821 tem->tvs_fg_color.n = param - 90;
822 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
823 tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
824 break;
825
826 case 100: /* black (grey) background */
827 case 101: /* red (light red) background */
828 case 102: /* green (light green) background */
829 case 103: /* brown (yellow) background */
830 case 104: /* blue (light blue) background */
831 case 105: /* magenta (light magenta) background */
832 case 106: /* cyan (light cyan) background */
833 case 107: /* white (bright white) background */
834 tem->tvs_bg_color.n = param - 100;
835 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
836 tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
837 break;
838
839 default:
840 break;
841 }
842 count++;
843 curparam--;
844
845 } while (curparam > 0);
846 }
847
848 /*
849 * Handle window manipulation.
850 */
851 static void
tem_safe_window(struct tem_vt_state * tem,enum called_from called_from)852 tem_safe_window(struct tem_vt_state *tem, enum called_from called_from)
853 {
854 int curparam;
855 int param;
856 int index = 0;
857 mblk_t *bp;
858 size_t len;
859 char buf[27];
860
861 tem->tvs_state = A_STATE_START;
862 curparam = tem->tvs_curparam;
863 do {
864 param = tem->tvs_params[index];
865
866 switch (param) {
867 case 8: /* Resize window to Ps2 lines and Ps3 columns. */
868 /* We ignore this */
869 index += 2;
870 curparam -= 2;
871 break;
872
873 case 18: /* Reports terminal size in characters. */
874 if (called_from == CALLED_FROM_STANDALONE)
875 break;
876 if (!canputnext(tem->tvs_queue))
877 break;
878
879 /* Response: CSI 8 ; lines ; columns t */
880 len = snprintf(buf, sizeof (buf), "%c[8;%u;%ut",
881 0x1b, tems.ts_c_dimension.height,
882 tems.ts_c_dimension.width);
883
884 bp = allocb(len, BPRI_HI);
885 if (bp != NULL) {
886 bp->b_datap->db_type = M_CTL;
887 bcopy(buf, bp->b_wptr, len);
888 bp->b_wptr += len;
889 (void) putnext(tem->tvs_queue, bp);
890 }
891 break;
892 }
893
894 index++;
895 curparam--;
896 } while (curparam > 0);
897 }
898
899 /*
900 * perform the appropriate action for the escape sequence
901 *
902 * General rule: This code does not validate the arguments passed.
903 * It assumes that the next lower level will do so.
904 */
905 static void
tem_safe_chkparam(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)906 tem_safe_chkparam(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
907 enum called_from called_from)
908 {
909 int i;
910 int row;
911 int col;
912
913 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
914 MUTEX_HELD(&tem->tvs_lock));
915
916 row = tem->tvs_c_cursor.row;
917 col = tem->tvs_c_cursor.col;
918
919 switch (ch) {
920
921 case 'm': /* select terminal graphics mode */
922 tem_safe_send_data(tem, credp, called_from);
923 tem_safe_selgraph(tem);
924 break;
925
926 case '@': /* insert char */
927 tem_safe_setparam(tem, 1, 1);
928 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
929 credp, called_from);
930 break;
931
932 case 'A': /* cursor up */
933 tem_safe_setparam(tem, 1, 1);
934 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
935 credp, called_from);
936 break;
937
938 case 'd': /* VPA - vertical position absolute */
939 tem_safe_setparam(tem, 1, 1);
940 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
941 credp, called_from);
942 break;
943
944 case 'e': /* VPR - vertical position relative */
945 case 'B': /* cursor down */
946 tem_safe_setparam(tem, 1, 1);
947 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
948 credp, called_from);
949 break;
950
951 case 'a': /* HPR - horizontal position relative */
952 case 'C': /* cursor right */
953 tem_safe_setparam(tem, 1, 1);
954 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
955 credp, called_from);
956 break;
957
958 case '`': /* HPA - horizontal position absolute */
959 tem_safe_setparam(tem, 1, 1);
960 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
961 credp, called_from);
962 break;
963
964 case 'D': /* cursor left */
965 tem_safe_setparam(tem, 1, 1);
966 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
967 credp, called_from);
968 break;
969
970 case 'E': /* CNL cursor next line */
971 tem_safe_setparam(tem, 1, 1);
972 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
973 credp, called_from);
974 break;
975
976 case 'F': /* CPL cursor previous line */
977 tem_safe_setparam(tem, 1, 1);
978 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
979 credp, called_from);
980 break;
981
982 case 'G': /* cursor horizontal position */
983 tem_safe_setparam(tem, 1, 1);
984 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
985 credp, called_from);
986 break;
987
988 case 'g': /* clear tabs */
989 tem_safe_setparam(tem, 1, 0);
990 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
991 break;
992
993 case 'f': /* HVP Horizontal and Vertical Position */
994 case 'H': /* CUP position cursor */
995 tem_safe_setparam(tem, 2, 1);
996 tem_safe_mv_cursor(tem,
997 tem->tvs_params[0] - 1,
998 tem->tvs_params[1] - 1,
999 credp, called_from);
1000 break;
1001
1002 case 'I': /* CHT - Cursor Horizontal Tab */
1003 /* Not implemented */
1004 break;
1005
1006 case 'J': /* ED - Erase in Display */
1007 tem_safe_send_data(tem, credp, called_from);
1008 tem_safe_setparam(tem, 1, 0);
1009 switch (tem->tvs_params[0]) {
1010 case 0:
1011 /* erase cursor to end of screen */
1012 /* FIRST erase cursor to end of line */
1013 tem_safe_clear_chars(tem,
1014 tems.ts_c_dimension.width -
1015 tem->tvs_c_cursor.col,
1016 tem->tvs_c_cursor.row,
1017 tem->tvs_c_cursor.col, credp, called_from);
1018
1019 /* THEN erase lines below the cursor */
1020 for (row = tem->tvs_c_cursor.row + 1;
1021 row < tems.ts_c_dimension.height;
1022 row++) {
1023 tem_safe_clear_chars(tem,
1024 tems.ts_c_dimension.width,
1025 row, 0, credp, called_from);
1026 }
1027 break;
1028
1029 case 1:
1030 /* erase beginning of screen to cursor */
1031 /* FIRST erase lines above the cursor */
1032 for (row = 0;
1033 row < tem->tvs_c_cursor.row;
1034 row++) {
1035 tem_safe_clear_chars(tem,
1036 tems.ts_c_dimension.width,
1037 row, 0, credp, called_from);
1038 }
1039 /* THEN erase beginning of line to cursor */
1040 tem_safe_clear_chars(tem,
1041 tem->tvs_c_cursor.col + 1,
1042 tem->tvs_c_cursor.row,
1043 0, credp, called_from);
1044 break;
1045
1046 case 2:
1047 /* erase whole screen */
1048 for (row = 0;
1049 row < tems.ts_c_dimension.height;
1050 row++) {
1051 tem_safe_clear_chars(tem,
1052 tems.ts_c_dimension.width,
1053 row, 0, credp, called_from);
1054 }
1055 break;
1056 }
1057 break;
1058
1059 case 'K': /* EL - Erase in Line */
1060 tem_safe_send_data(tem, credp, called_from);
1061 tem_safe_setparam(tem, 1, 0);
1062 switch (tem->tvs_params[0]) {
1063 case 0:
1064 /* erase cursor to end of line */
1065 tem_safe_clear_chars(tem,
1066 (tems.ts_c_dimension.width -
1067 tem->tvs_c_cursor.col),
1068 tem->tvs_c_cursor.row,
1069 tem->tvs_c_cursor.col,
1070 credp, called_from);
1071 break;
1072
1073 case 1:
1074 /* erase beginning of line to cursor */
1075 tem_safe_clear_chars(tem,
1076 tem->tvs_c_cursor.col + 1,
1077 tem->tvs_c_cursor.row,
1078 0, credp, called_from);
1079 break;
1080
1081 case 2:
1082 /* erase whole line */
1083 tem_safe_clear_chars(tem,
1084 tems.ts_c_dimension.width,
1085 tem->tvs_c_cursor.row,
1086 0, credp, called_from);
1087 break;
1088 }
1089 break;
1090
1091 case 'L': /* insert line */
1092 tem_safe_send_data(tem, credp, called_from);
1093 tem_safe_setparam(tem, 1, 1);
1094 tem_safe_scroll(tem,
1095 tem->tvs_c_cursor.row,
1096 tems.ts_c_dimension.height - 1,
1097 tem->tvs_params[0], TEM_SCROLL_DOWN,
1098 credp, called_from);
1099 break;
1100
1101 case 'M': /* delete line */
1102 tem_safe_send_data(tem, credp, called_from);
1103 tem_safe_setparam(tem, 1, 1);
1104 tem_safe_scroll(tem,
1105 tem->tvs_c_cursor.row,
1106 tems.ts_c_dimension.height - 1,
1107 tem->tvs_params[0], TEM_SCROLL_UP,
1108 credp, called_from);
1109 break;
1110
1111 case 'P': /* DCH - delete char */
1112 tem_safe_setparam(tem, 1, 1);
1113 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
1114 credp, called_from);
1115 break;
1116
1117 case 'S': /* scroll up */
1118 tem_safe_send_data(tem, credp, called_from);
1119 tem_safe_setparam(tem, 1, 1);
1120 tem_safe_scroll(tem, 0,
1121 tems.ts_c_dimension.height - 1,
1122 tem->tvs_params[0], TEM_SCROLL_UP,
1123 credp, called_from);
1124 break;
1125
1126 case 'T': /* scroll down */
1127 tem_safe_send_data(tem, credp, called_from);
1128 tem_safe_setparam(tem, 1, 1);
1129 tem_safe_scroll(tem, 0,
1130 tems.ts_c_dimension.height - 1,
1131 tem->tvs_params[0], TEM_SCROLL_DOWN,
1132 credp, called_from);
1133 break;
1134
1135 case 't':
1136 tem_safe_send_data(tem, credp, called_from);
1137 tem_safe_window(tem, called_from);
1138 break;
1139
1140 case 'X': /* erase char */
1141 tem_safe_setparam(tem, 1, 1);
1142 tem_safe_clear_chars(tem,
1143 tem->tvs_params[0],
1144 tem->tvs_c_cursor.row,
1145 tem->tvs_c_cursor.col,
1146 credp, called_from);
1147 break;
1148
1149 case 'Z': /* cursor backward tabulation */
1150 tem_safe_setparam(tem, 1, 1);
1151
1152 /*
1153 * Rule exception - We do sanity checking here.
1154 *
1155 * Restrict the count to a sane value to keep from
1156 * looping for a long time. There can't be more than one
1157 * tab stop per column, so use that as a limit.
1158 */
1159 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
1160 tem->tvs_params[0] = tems.ts_c_dimension.width;
1161
1162 for (i = 0; i < tem->tvs_params[0]; i++)
1163 tem_safe_back_tab(tem, credp, called_from);
1164 break;
1165 }
1166 tem->tvs_state = A_STATE_START;
1167 }
1168
1169 static void
tem_safe_chkparam_qmark(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)1170 tem_safe_chkparam_qmark(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
1171 enum called_from called_from)
1172 {
1173 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1174 MUTEX_HELD(&tem->tvs_lock));
1175
1176 switch (ch) {
1177 case 'h': /* DEC private mode set */
1178 tem_safe_setparam(tem, 1, 1);
1179 switch (tem->tvs_params[0]) {
1180 case 7: /* Autowrap mode. */
1181 tem->tvs_stateflags |= TVS_AUTOWRAP;
1182 break;
1183
1184 case 25: /* show cursor */
1185 /*
1186 * Note that cursor is not displayed either way
1187 * at this entry point. Clearing the flag ensures
1188 * that on exit from tem_safe_terminal_emulate
1189 * we will display the cursor.
1190 */
1191 tem_safe_send_data(tem, credp, called_from);
1192 tem->tvs_cursor_hidden = B_FALSE;
1193 break;
1194 }
1195 break;
1196
1197 case 'l':
1198 /* DEC private mode reset */
1199 tem_safe_setparam(tem, 1, 1);
1200 switch (tem->tvs_params[0]) {
1201 case 7: /* Autowrap mode. */
1202 tem->tvs_stateflags &= ~TVS_AUTOWRAP;
1203 break;
1204
1205 case 25: /* hide cursor */
1206 /*
1207 * Note that the cursor is not displayed already.
1208 * This is true regardless of the flag state.
1209 * Setting this flag ensures we won't display it
1210 * on exit from tem_safe_terminal_emulate.
1211 */
1212 tem_safe_send_data(tem, credp, called_from);
1213 tem->tvs_cursor_hidden = B_TRUE;
1214 break;
1215 }
1216 break;
1217 }
1218 tem->tvs_state = A_STATE_START;
1219 }
1220
1221 /*
1222 * Gather the parameters of an ANSI escape sequence
1223 */
1224 static void
tem_safe_getparams(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)1225 tem_safe_getparams(struct tem_vt_state *tem, tem_char_t ch,
1226 cred_t *credp, enum called_from called_from)
1227 {
1228 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1229 MUTEX_HELD(&tem->tvs_lock));
1230
1231 if (ch >= '0' && ch <= '9') {
1232 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
1233 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
1234 return; /* Return immediately */
1235 } else if (tem->tvs_state == A_STATE_CSI_EQUAL) {
1236 tem->tvs_state = A_STATE_START;
1237 } else if (tem->tvs_state == A_STATE_CSI_QMARK) {
1238 if (tem->tvs_curparam < TEM_MAXPARAMS) {
1239 if (tem->tvs_gotparam) {
1240 /* get the parameter value */
1241 tem->tvs_params[tem->tvs_curparam] =
1242 tem->tvs_paramval;
1243 }
1244 tem->tvs_curparam++;
1245 }
1246 if (ch == ';') {
1247 /* Restart parameter search */
1248 tem->tvs_gotparam = B_FALSE;
1249 tem->tvs_paramval = 0; /* No parameter value yet */
1250 } else {
1251 /* Handle escape sequence */
1252 tem_safe_chkparam_qmark(tem, ch, credp, called_from);
1253 }
1254 } else {
1255 if (tem->tvs_curparam < TEM_MAXPARAMS) {
1256 if (tem->tvs_gotparam) {
1257 /* get the parameter value */
1258 tem->tvs_params[tem->tvs_curparam] =
1259 tem->tvs_paramval;
1260 }
1261 tem->tvs_curparam++;
1262 }
1263
1264 if (ch == ';') {
1265 /* Restart parameter search */
1266 tem->tvs_gotparam = B_FALSE;
1267 tem->tvs_paramval = 0; /* No parameter value yet */
1268 } else {
1269 /* Handle escape sequence */
1270 tem_safe_chkparam(tem, ch, credp, called_from);
1271 }
1272 }
1273 }
1274
1275 /*
1276 * Add character to internal buffer.
1277 * When its full, send it to the next layer.
1278 */
1279
1280 static void
tem_safe_outch(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)1281 tem_safe_outch(struct tem_vt_state *tem, tem_char_t ch,
1282 cred_t *credp, enum called_from called_from)
1283 {
1284 text_color_t fg;
1285 text_color_t bg;
1286 text_attr_t attr;
1287
1288 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1289 called_from == CALLED_FROM_STANDALONE);
1290
1291 /* We have autowrap enabled and we did wrap - get cursor to new line */
1292 if ((tem->tvs_stateflags & (TVS_AUTOWRAP | TVS_WRAPPED)) ==
1293 (TVS_AUTOWRAP | TVS_WRAPPED)) {
1294 tem_safe_new_line(tem, credp, called_from);
1295 }
1296
1297 /* buffer up the character until later */
1298 tem_safe_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE);
1299 tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr);
1300 tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg;
1301 tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg;
1302 tem->tvs_outindex++;
1303 tem->tvs_c_cursor.col++;
1304 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
1305 tem->tvs_stateflags |= TVS_WRAPPED;
1306 tem->tvs_c_cursor.col--;
1307 tem_safe_send_data(tem, credp, called_from);
1308 } else {
1309 tem->tvs_stateflags &= ~TVS_WRAPPED;
1310 }
1311 }
1312
1313 static void
tem_safe_new_line(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)1314 tem_safe_new_line(struct tem_vt_state *tem,
1315 cred_t *credp, enum called_from called_from)
1316 {
1317 tem_safe_cr(tem);
1318 tem_safe_lf(tem, credp, called_from);
1319 }
1320
1321 static void
tem_safe_cr(struct tem_vt_state * tem)1322 tem_safe_cr(struct tem_vt_state *tem)
1323 {
1324 tem->tvs_c_cursor.col = 0;
1325 tem->tvs_stateflags &= ~TVS_WRAPPED;
1326 tem_safe_align_cursor(tem);
1327 }
1328
1329 static void
tem_safe_lf(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)1330 tem_safe_lf(struct tem_vt_state *tem,
1331 cred_t *credp, enum called_from called_from)
1332 {
1333 int row;
1334
1335 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1336 MUTEX_HELD(&tem->tvs_lock));
1337
1338 tem->tvs_stateflags &= ~TVS_WRAPPED;
1339 /*
1340 * Sanity checking notes:
1341 * . a_nscroll was validated when it was set.
1342 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
1343 * will prevent anything bad from happening.
1344 */
1345 row = tem->tvs_c_cursor.row + 1;
1346
1347 if (row >= tems.ts_c_dimension.height) {
1348 if (tem->tvs_nscroll != 0) {
1349 tem_safe_scroll(tem, 0,
1350 tems.ts_c_dimension.height - 1,
1351 tem->tvs_nscroll, TEM_SCROLL_UP,
1352 credp, called_from);
1353 row = tems.ts_c_dimension.height -
1354 tem->tvs_nscroll;
1355 } else { /* no scroll */
1356 /*
1357 * implement Esc[#r when # is zero. This means no
1358 * scroll but just return cursor to top of screen,
1359 * do not clear screen.
1360 */
1361 row = 0;
1362 }
1363 }
1364
1365 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
1366 credp, called_from);
1367
1368 if (tem->tvs_nscroll == 0) {
1369 /* erase rest of cursor line */
1370 tem_safe_clear_chars(tem,
1371 tems.ts_c_dimension.width -
1372 tem->tvs_c_cursor.col,
1373 tem->tvs_c_cursor.row,
1374 tem->tvs_c_cursor.col,
1375 credp, called_from);
1376
1377 }
1378
1379 tem_safe_align_cursor(tem);
1380 }
1381
1382 static void
tem_safe_send_data(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)1383 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1384 enum called_from called_from)
1385 {
1386 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1387 MUTEX_HELD(&tem->tvs_lock));
1388
1389 if (tem->tvs_outindex == 0) {
1390 tem_safe_align_cursor(tem);
1391 return;
1392 }
1393
1394 tem_safe_virtual_display(tem,
1395 tem->tvs_outbuf, tem->tvs_outindex,
1396 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
1397
1398 if (tem->tvs_isactive) {
1399 /*
1400 * Call the primitive to render this data.
1401 */
1402 tem_safe_callback_display(tem,
1403 tem->tvs_outbuf, tem->tvs_outindex,
1404 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1405 credp, called_from);
1406 }
1407
1408 tem->tvs_outindex = 0;
1409
1410 tem_safe_align_cursor(tem);
1411 }
1412
1413
1414 /*
1415 * We have just done something to the current output point. Reset the start
1416 * point for the buffered data in a_outbuf. There shouldn't be any data
1417 * buffered yet.
1418 */
1419 static void
tem_safe_align_cursor(struct tem_vt_state * tem)1420 tem_safe_align_cursor(struct tem_vt_state *tem)
1421 {
1422 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1423 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1424 }
1425
1426 /*
1427 * State machine parser based on the current state and character input
1428 * major terminations are to control character or normal character
1429 */
1430
1431 static void
tem_safe_parse(struct tem_vt_state * tem,tem_char_t ch,cred_t * credp,enum called_from called_from)1432 tem_safe_parse(struct tem_vt_state *tem, tem_char_t ch,
1433 cred_t *credp, enum called_from called_from)
1434 {
1435 int i;
1436
1437 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1438 MUTEX_HELD(&tem->tvs_lock));
1439
1440 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1441 if (ch == A_CSI || ch == A_ESC || ch < ' ') {
1442 /* Control */
1443 tem_safe_control(tem, ch, credp, called_from);
1444 } else {
1445 /* Display */
1446 tem_safe_outch(tem, ch, credp, called_from);
1447 }
1448 return;
1449 }
1450
1451 /* In <ESC> sequence */
1452 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1453 if (tem->tvs_state != A_STATE_CSI) {
1454 tem_safe_getparams(tem, ch, credp, called_from);
1455 return;
1456 }
1457
1458 switch (ch) {
1459 case '?':
1460 tem->tvs_state = A_STATE_CSI_QMARK;
1461 return;
1462 case '=':
1463 tem->tvs_state = A_STATE_CSI_EQUAL;
1464 return;
1465 case 's':
1466 /*
1467 * As defined below, this sequence
1468 * saves the cursor. However, Sun
1469 * defines ESC[s as reset. We resolved
1470 * the conflict by selecting reset as it
1471 * is exported in the termcap file for
1472 * sun-mon, while the "save cursor"
1473 * definition does not exist anywhere in
1474 * /etc/termcap.
1475 * However, having no coherent
1476 * definition of reset, we have not
1477 * implemented it.
1478 */
1479
1480 /*
1481 * Original code
1482 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1483 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1484 * tem->tvs_state = A_STATE_START;
1485 */
1486
1487 tem->tvs_state = A_STATE_START;
1488 return;
1489 case 'u':
1490 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1491 tem->tvs_r_cursor.col, credp, called_from);
1492 tem->tvs_state = A_STATE_START;
1493 return;
1494 case 'p': /* sunbow */
1495 tem_safe_send_data(tem, credp, called_from);
1496 /*
1497 * Don't set anything if we are
1498 * already as we want to be.
1499 */
1500 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1501 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1502 /*
1503 * If we have switched the characters to be the
1504 * inverse from the screen, then switch them as
1505 * well to keep them the inverse of the screen.
1506 */
1507 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1508 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1509 else
1510 tem->tvs_flags |= TEM_ATTR_REVERSE;
1511 }
1512 tem_safe_cls(tem, credp, called_from);
1513 tem->tvs_state = A_STATE_START;
1514 return;
1515 case 'q': /* sunwob */
1516 tem_safe_send_data(tem, credp, called_from);
1517 /*
1518 * Don't set anything if we are
1519 * already where as we want to be.
1520 */
1521 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1522 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1523 /*
1524 * If we have switched the characters to be the
1525 * inverse from the screen, then switch them as
1526 * well to keep them the inverse of the screen.
1527 */
1528 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1529 tem->tvs_flags |= TEM_ATTR_REVERSE;
1530 else
1531 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1532 }
1533
1534 tem_safe_cls(tem, credp, called_from);
1535 tem->tvs_state = A_STATE_START;
1536 return;
1537 case 'r': /* sunscrl */
1538 /*
1539 * Rule exception: check for validity here.
1540 */
1541 tem->tvs_nscroll = tem->tvs_paramval;
1542 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
1543 tem->tvs_nscroll = tems.ts_c_dimension.height;
1544 if (tem->tvs_nscroll < 0)
1545 tem->tvs_nscroll = 1;
1546 tem->tvs_state = A_STATE_START;
1547 return;
1548 default:
1549 tem_safe_getparams(tem, ch, credp, called_from);
1550 return;
1551 }
1552 }
1553
1554 /* Previous char was <ESC> */
1555 if (ch == '[') {
1556 tem->tvs_curparam = 0;
1557 tem->tvs_paramval = 0;
1558 tem->tvs_gotparam = B_FALSE;
1559 /* clear the parameters */
1560 for (i = 0; i < TEM_MAXPARAMS; i++)
1561 tem->tvs_params[i] = -1;
1562 tem->tvs_state = A_STATE_CSI;
1563 } else if (ch == 'Q') { /* <ESC>Q ? */
1564 tem->tvs_state = A_STATE_START;
1565 } else if (ch == 'C') { /* <ESC>C ? */
1566 tem->tvs_state = A_STATE_START;
1567 } else {
1568 tem->tvs_state = A_STATE_START;
1569 if (ch == 'c') {
1570 /* ESC c resets display */
1571 tem_safe_reset_display(tem, credp, called_from,
1572 B_TRUE, B_TRUE);
1573 } else if (ch == 'H') {
1574 /* ESC H sets a tab */
1575 tem_safe_set_tab(tem);
1576 } else if (ch == '7') {
1577 /* ESC 7 Save Cursor position */
1578 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1579 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1580 } else if (ch == '8') {
1581 /* ESC 8 Restore Cursor position */
1582 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1583 tem->tvs_r_cursor.col, credp, called_from);
1584 /* check for control chars */
1585 } else if (ch < ' ') {
1586 tem_safe_control(tem, ch, credp, called_from);
1587 } else {
1588 tem_safe_outch(tem, ch, credp, called_from);
1589 }
1590 }
1591 }
1592
1593 /* ARGSUSED */
1594 static void
tem_safe_bell(struct tem_vt_state * tem,enum called_from called_from)1595 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1596 {
1597 if (called_from == CALLED_FROM_STANDALONE)
1598 (void) beep_polled(BEEP_CONSOLE);
1599 else
1600 (void) beep(BEEP_CONSOLE);
1601 }
1602
1603
1604 static void
tem_safe_scroll(struct tem_vt_state * tem,int start,int end,int count,int direction,cred_t * credp,enum called_from called_from)1605 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1606 int direction, cred_t *credp, enum called_from called_from)
1607 {
1608 int row;
1609 int lines_affected;
1610
1611 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1612 called_from == CALLED_FROM_STANDALONE);
1613
1614 lines_affected = end - start + 1;
1615 if (count > lines_affected)
1616 count = lines_affected;
1617 if (count <= 0)
1618 return;
1619
1620 switch (direction) {
1621 case TEM_SCROLL_UP:
1622 if (count < lines_affected) {
1623 tem_safe_copy_area(tem, 0, start + count,
1624 tems.ts_c_dimension.width - 1, end,
1625 0, start, credp, called_from);
1626 }
1627 for (row = (end - count) + 1; row <= end; row++) {
1628 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1629 row, 0, credp, called_from);
1630 }
1631 break;
1632
1633 case TEM_SCROLL_DOWN:
1634 if (count < lines_affected) {
1635 tem_safe_copy_area(tem, 0, start,
1636 tems.ts_c_dimension.width - 1,
1637 end - count, 0, start + count,
1638 credp, called_from);
1639 }
1640 for (row = start; row < start + count; row++) {
1641 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1642 row, 0, credp, called_from);
1643 }
1644 break;
1645 }
1646 }
1647
1648 static int
tem_copy_width(term_char_t * src,term_char_t * dst,int cols)1649 tem_copy_width(term_char_t *src, term_char_t *dst, int cols)
1650 {
1651 int width = cols - 1;
1652
1653 while (width >= 0) {
1654 /* We can't compare images. */
1655 if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE ||
1656 TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE)
1657 break;
1658
1659 /*
1660 * Find difference on line, compare char with its attributes
1661 * and colors.
1662 */
1663 if (src[width].tc_char != dst[width].tc_char ||
1664 src[width].tc_fg_color.n != dst[width].tc_fg_color.n ||
1665 src[width].tc_bg_color.n != dst[width].tc_bg_color.n) {
1666 break;
1667 }
1668 width--;
1669 }
1670 return (width + 1);
1671 }
1672
1673 static void
tem_safe_copy_area(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row,cred_t * credp,enum called_from called_from)1674 tem_safe_copy_area(struct tem_vt_state *tem,
1675 screen_pos_t s_col, screen_pos_t s_row,
1676 screen_pos_t e_col, screen_pos_t e_row,
1677 screen_pos_t t_col, screen_pos_t t_row,
1678 cred_t *credp, enum called_from called_from)
1679 {
1680 size_t soffset, toffset;
1681 term_char_t *src, *dst;
1682 int rows;
1683 int cols;
1684
1685 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1686 called_from == CALLED_FROM_STANDALONE);
1687
1688 if (s_col < 0 || s_row < 0 ||
1689 e_col < 0 || e_row < 0 ||
1690 t_col < 0 || t_row < 0 ||
1691 s_col >= tems.ts_c_dimension.width ||
1692 e_col >= tems.ts_c_dimension.width ||
1693 t_col >= tems.ts_c_dimension.width ||
1694 s_row >= tems.ts_c_dimension.height ||
1695 e_row >= tems.ts_c_dimension.height ||
1696 t_row >= tems.ts_c_dimension.height)
1697 return;
1698
1699 if (s_row > e_row || s_col > e_col)
1700 return;
1701
1702 rows = e_row - s_row + 1;
1703 cols = e_col - s_col + 1;
1704 if (t_row + rows > tems.ts_c_dimension.height ||
1705 t_col + cols > tems.ts_c_dimension.width)
1706 return;
1707
1708 soffset = s_col + s_row * tems.ts_c_dimension.width;
1709 toffset = t_col + t_row * tems.ts_c_dimension.width;
1710 src = tem->tvs_screen_buf + soffset;
1711 dst = tem->tvs_screen_buf + toffset;
1712
1713 /*
1714 * Copy line by line. We determine the length by comparing the
1715 * screen content from cached text in tvs_screen_buf.
1716 */
1717 if (toffset <= soffset) {
1718 for (int i = 0; i < rows; i++) {
1719 int increment = i * tems.ts_c_dimension.width;
1720 int width;
1721
1722 width = tem_copy_width(src + increment,
1723 dst + increment, cols);
1724
1725 tem_safe_virtual_copy(tem, s_col, s_row + i,
1726 e_col - cols + width, s_row + i,
1727 t_col, t_row + i);
1728
1729 if (tem->tvs_isactive) {
1730 tem_safe_callback_copy(tem, s_col, s_row + i,
1731 e_col - cols + width, s_row + i,
1732 t_col, t_row + i, credp, called_from);
1733 }
1734 }
1735 } else {
1736 for (int i = rows - 1; i >= 0; i--) {
1737 int increment = i * tems.ts_c_dimension.width;
1738 int width;
1739
1740 width = tem_copy_width(src + increment,
1741 dst + increment, cols);
1742
1743 tem_safe_virtual_copy(tem, s_col, s_row + i,
1744 e_col - cols + width, s_row + i,
1745 t_col, t_row + i);
1746
1747 if (tem->tvs_isactive) {
1748 tem_safe_callback_copy(tem, s_col, s_row + i,
1749 e_col - cols + width, s_row + i,
1750 t_col, t_row + i, credp, called_from);
1751 }
1752 }
1753 }
1754 }
1755
1756 static void
tem_safe_clear_chars(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col,cred_t * credp,enum called_from called_from)1757 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1758 screen_pos_t col, cred_t *credp, enum called_from called_from)
1759 {
1760 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1761 called_from == CALLED_FROM_STANDALONE);
1762
1763 if (row < 0 || row >= tems.ts_c_dimension.height ||
1764 col < 0 || col >= tems.ts_c_dimension.width ||
1765 count < 0)
1766 return;
1767
1768 /*
1769 * Note that very large values of "count" could cause col+count
1770 * to overflow, so we check "count" independently.
1771 */
1772 if (count > tems.ts_c_dimension.width ||
1773 col + count > tems.ts_c_dimension.width)
1774 count = tems.ts_c_dimension.width - col;
1775
1776 tem_safe_virtual_cls(tem, count, row, col);
1777
1778 if (!tem->tvs_isactive)
1779 return;
1780
1781 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1782 }
1783
1784 /*ARGSUSED*/
1785 void
tem_safe_text_display(struct tem_vt_state * tem,term_char_t * string,int count,screen_pos_t row,screen_pos_t col,cred_t * credp,enum called_from called_from)1786 tem_safe_text_display(struct tem_vt_state *tem, term_char_t *string,
1787 int count, screen_pos_t row, screen_pos_t col,
1788 cred_t *credp, enum called_from called_from)
1789 {
1790 struct vis_consdisplay da;
1791 int i;
1792 tem_char_t c;
1793 text_color_t bg, fg;
1794
1795 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1796 called_from == CALLED_FROM_STANDALONE);
1797
1798 da.data = (uint8_t *)&c;
1799 da.width = 1;
1800 da.row = row;
1801 da.col = col;
1802
1803 for (i = 0; i < count; i++) {
1804 tem_safe_get_color(tem, &fg, &bg, &string[i]);
1805 tem_safe_set_color(&fg, &da.fg_color);
1806 tem_safe_set_color(&bg, &da.bg_color);
1807 c = TEM_CHAR(string[i].tc_char);
1808 tems_safe_display(&da, credp, called_from);
1809 da.col++;
1810 }
1811 }
1812
1813 #if 0
1814 /*
1815 * This function is used to blit a rectangular color image,
1816 * unperturbed on the underlying framebuffer, to render
1817 * icons and pictures. The data is a pixel pattern that
1818 * fills a rectangle bounded to the width and height parameters.
1819 * The color pixel data must to be pre-adjusted by the caller
1820 * for the current video depth.
1821 *
1822 * This function is unused now.
1823 */
1824 /*ARGSUSED*/
1825 static void
1826 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1827 int height, int width, screen_pos_t row, screen_pos_t col,
1828 cred_t *credp, enum called_from called_from)
1829 {
1830 struct vis_consdisplay da;
1831
1832 mutex_enter(&tems.ts_lock);
1833 mutex_enter(&tem->tvs_lock);
1834
1835 da.data = image;
1836 da.width = (screen_size_t)width;
1837 da.height = (screen_size_t)height;
1838 da.row = row;
1839 da.col = col;
1840
1841 tems_safe_display(&da, credp, called_from);
1842
1843 mutex_exit(&tem->tvs_lock);
1844 mutex_exit(&tems.ts_lock);
1845 }
1846 #endif
1847
1848 /*ARGSUSED*/
1849 void
tem_safe_text_copy(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row,cred_t * credp,enum called_from called_from)1850 tem_safe_text_copy(struct tem_vt_state *tem,
1851 screen_pos_t s_col, screen_pos_t s_row,
1852 screen_pos_t e_col, screen_pos_t e_row,
1853 screen_pos_t t_col, screen_pos_t t_row,
1854 cred_t *credp, enum called_from called_from)
1855 {
1856 struct vis_conscopy da;
1857
1858 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1859 called_from == CALLED_FROM_STANDALONE);
1860
1861 da.s_row = s_row;
1862 da.s_col = s_col;
1863 da.e_row = e_row;
1864 da.e_col = e_col;
1865 da.t_row = t_row;
1866 da.t_col = t_col;
1867
1868 tems_safe_copy(&da, credp, called_from);
1869 }
1870
1871 void
tem_safe_text_cls(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col,cred_t * credp,enum called_from called_from)1872 tem_safe_text_cls(struct tem_vt_state *tem,
1873 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1874 enum called_from called_from)
1875 {
1876 text_attr_t attr;
1877 term_char_t c;
1878 int i;
1879
1880 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1881 called_from == CALLED_FROM_STANDALONE);
1882
1883 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
1884 TEM_ATTR_SCREEN_REVERSE);
1885 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
1886
1887 if (count > tems.ts_c_dimension.width ||
1888 col + count > tems.ts_c_dimension.width)
1889 count = tems.ts_c_dimension.width - col;
1890
1891 for (i = 0; i < count; i++)
1892 tems.ts_blank_line[i] = c;
1893
1894 tem_safe_text_display(tem, tems.ts_blank_line, count, row, col,
1895 credp, called_from);
1896 }
1897
1898 void
tem_safe_pix_display(struct tem_vt_state * tem,term_char_t * string,int count,screen_pos_t row,screen_pos_t col,cred_t * credp,enum called_from called_from)1899 tem_safe_pix_display(struct tem_vt_state *tem,
1900 term_char_t *string, int count,
1901 screen_pos_t row, screen_pos_t col,
1902 cred_t *credp, enum called_from called_from)
1903 {
1904 struct vis_consdisplay da;
1905 int i;
1906
1907 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1908 called_from == CALLED_FROM_STANDALONE);
1909
1910 da.data = (uchar_t *)tem->tvs_pix_data;
1911 da.width = (screen_size_t)tems.ts_font.vf_width;
1912 da.height = (screen_size_t)tems.ts_font.vf_height;
1913 da.row = (row * da.height) + tems.ts_p_offset.y;
1914 da.col = (col * da.width) + tems.ts_p_offset.x;
1915
1916 for (i = 0; i < count; i++) {
1917 /* Do not display image area */
1918 if (!TEM_ATTR_ISSET(string[i].tc_char, TEM_ATTR_IMAGE)) {
1919 tem_safe_callback_bit2pix(tem, &string[i]);
1920 tems_safe_display(&da, credp, called_from);
1921 }
1922 da.col += da.width;
1923 }
1924 }
1925
1926 void
tem_safe_pix_copy(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row,cred_t * credp,enum called_from called_from)1927 tem_safe_pix_copy(struct tem_vt_state *tem,
1928 screen_pos_t s_col, screen_pos_t s_row,
1929 screen_pos_t e_col, screen_pos_t e_row,
1930 screen_pos_t t_col, screen_pos_t t_row,
1931 cred_t *credp,
1932 enum called_from called_from)
1933 {
1934 struct vis_conscopy ma;
1935 static boolean_t need_clear = B_TRUE;
1936
1937 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1938 called_from == CALLED_FROM_STANDALONE);
1939
1940 if (need_clear && tem->tvs_first_line > 0) {
1941 /*
1942 * Clear OBP output above our kernel console term
1943 * when our kernel console term begins to scroll up,
1944 * we hope it is user friendly.
1945 * (Also see comments on tem_safe_pix_clear_prom_output)
1946 *
1947 * This is only one time call.
1948 */
1949 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1950 }
1951 need_clear = B_FALSE;
1952
1953 ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
1954 ma.e_row = (e_row + 1) * tems.ts_font.vf_height +
1955 tems.ts_p_offset.y - 1;
1956 ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
1957
1958 /*
1959 * Check if we're in process of clearing OBP's columns area,
1960 * which only happens when term scrolls up a whole line.
1961 */
1962 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1963 e_col == tems.ts_c_dimension.width - 1) {
1964 /*
1965 * We need to clear OBP's columns area outside our kernel
1966 * console term. So that we set ma.e_col to entire row here.
1967 */
1968 ma.s_col = s_col * tems.ts_font.vf_width;
1969 ma.e_col = tems.ts_p_dimension.width - 1;
1970
1971 ma.t_col = t_col * tems.ts_font.vf_width;
1972 } else {
1973 ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
1974 ma.e_col = (e_col + 1) * tems.ts_font.vf_width +
1975 tems.ts_p_offset.x - 1;
1976 ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
1977 }
1978
1979 tems_safe_copy(&ma, credp, called_from);
1980
1981 if (tem->tvs_first_line > 0 && t_row < s_row) {
1982 /* We have scrolled up (s_row - t_row) rows. */
1983 tem->tvs_first_line -= (s_row - t_row);
1984 if (tem->tvs_first_line <= 0) {
1985 /* All OBP rows have been cleared. */
1986 tem->tvs_first_line = 0;
1987 }
1988 }
1989
1990 }
1991
1992 void
tem_safe_pix_bit2pix(struct tem_vt_state * tem,term_char_t * c)1993 tem_safe_pix_bit2pix(struct tem_vt_state *tem, term_char_t *c)
1994 {
1995 text_color_t fg, bg;
1996 void (*fp)(struct tem_vt_state *, tem_char_t,
1997 text_color_t, text_color_t);
1998
1999 tem_safe_get_color(tem, &fg, &bg, c);
2000 switch (tems.ts_pdepth) {
2001 case 4:
2002 fp = bit_to_pix4;
2003 break;
2004 case 8:
2005 fp = bit_to_pix8;
2006 break;
2007 case 15:
2008 case 16:
2009 fp = bit_to_pix16;
2010 break;
2011 case 24:
2012 fp = bit_to_pix24;
2013 break;
2014 case 32:
2015 fp = bit_to_pix32;
2016 break;
2017 default:
2018 return;
2019 }
2020
2021 fp(tem, c->tc_char, fg, bg);
2022 }
2023
2024
2025 /*
2026 * This function only clears count of columns in one row
2027 */
2028 void
tem_safe_pix_cls(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col,cred_t * credp,enum called_from called_from)2029 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
2030 screen_pos_t row, screen_pos_t col, cred_t *credp,
2031 enum called_from called_from)
2032 {
2033 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2034 called_from == CALLED_FROM_STANDALONE);
2035
2036 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
2037 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
2038 }
2039
2040 /*
2041 * This function clears OBP output above our kernel console term area
2042 * because OBP's term may have a bigger terminal window than that of
2043 * our kernel console term. So we need to clear OBP output garbage outside
2044 * of our kernel console term at a proper time, which is when the first
2045 * row output of our kernel console term scrolls at the first screen line.
2046 *
2047 * _________________________________
2048 * | _____________________ | ---> OBP's bigger term window
2049 * | | | |
2050 * |___| | |
2051 * | | | | |
2052 * | | | | |
2053 * |_|_|___________________|_______|
2054 * | | | ---> first line
2055 * | |___________________|---> our kernel console term window
2056 * |
2057 * |---> columns area to be cleared
2058 *
2059 * This function only takes care of the output above our kernel console term,
2060 * and tem_prom_scroll_up takes care of columns area outside of our kernel
2061 * console term.
2062 */
2063 static void
tem_safe_pix_clear_prom_output(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2064 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
2065 enum called_from called_from)
2066 {
2067 int nrows, ncols, width, height, offset;
2068
2069 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2070 called_from == CALLED_FROM_STANDALONE);
2071
2072 width = tems.ts_font.vf_width;
2073 height = tems.ts_font.vf_height;
2074 offset = tems.ts_p_offset.y % height;
2075
2076 nrows = tems.ts_p_offset.y / height;
2077 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
2078
2079 if (nrows > 0)
2080 tem_safe_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0,
2081 B_FALSE, credp, called_from);
2082 }
2083
2084 /*
2085 * clear the whole screen for pixel mode, just clear the
2086 * physical screen.
2087 */
2088 void
tem_safe_pix_clear_entire_screen(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2089 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
2090 enum called_from called_from)
2091 {
2092 struct vis_consclear cl;
2093 text_color_t fg_color;
2094 text_color_t bg_color;
2095 text_attr_t attr;
2096 term_char_t c;
2097 int nrows, ncols, width, height;
2098
2099 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2100 called_from == CALLED_FROM_STANDALONE);
2101
2102 /* call driver first, if error, clear terminal area */
2103 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2104 TEM_ATTR_SCREEN_REVERSE);
2105 c.tc_char = TEM_ATTR(attr);
2106
2107 tem_safe_get_color(tem, &fg_color, &bg_color, &c);
2108 tem_safe_set_color(&bg_color, &cl.bg_color);
2109 if (tems_cls_layered(&cl, credp) == 0)
2110 return;
2111
2112 width = tems.ts_font.vf_width;
2113 height = tems.ts_font.vf_height;
2114
2115 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
2116 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
2117
2118 tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, 0, ncols,
2119 tems.ts_p_offset.x, B_FALSE, credp, called_from);
2120
2121 /*
2122 * Since the whole screen is cleared, we don't need
2123 * to clear OBP output later.
2124 */
2125 if (tem->tvs_first_line > 0)
2126 tem->tvs_first_line = 0;
2127 }
2128
2129 /*
2130 * clear the whole screen, including the virtual screen buffer,
2131 * and reset the cursor to start point.
2132 */
2133 static void
tem_safe_cls(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2134 tem_safe_cls(struct tem_vt_state *tem,
2135 cred_t *credp, enum called_from called_from)
2136 {
2137 int row;
2138
2139 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2140 called_from == CALLED_FROM_STANDALONE);
2141
2142 if (tems.ts_display_mode == VIS_TEXT) {
2143 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2144 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
2145 row, 0, credp, called_from);
2146 }
2147 tem->tvs_c_cursor.row = 0;
2148 tem->tvs_c_cursor.col = 0;
2149 tem_safe_align_cursor(tem);
2150 return;
2151 }
2152
2153 ASSERT(tems.ts_display_mode == VIS_PIXEL);
2154
2155 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2156 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
2157 }
2158 tem->tvs_c_cursor.row = 0;
2159 tem->tvs_c_cursor.col = 0;
2160 tem_safe_align_cursor(tem);
2161
2162 if (!tem->tvs_isactive)
2163 return;
2164
2165 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2166 }
2167
2168 static void
tem_safe_back_tab(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2169 tem_safe_back_tab(struct tem_vt_state *tem,
2170 cred_t *credp, enum called_from called_from)
2171 {
2172 int i;
2173 screen_pos_t tabstop;
2174
2175 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2176 called_from == CALLED_FROM_STANDALONE);
2177
2178 tabstop = 0;
2179
2180 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
2181 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
2182 tabstop = tem->tvs_tabs[i];
2183 break;
2184 }
2185 }
2186
2187 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
2188 tabstop, credp, called_from);
2189 }
2190
2191 static void
tem_safe_tab(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2192 tem_safe_tab(struct tem_vt_state *tem,
2193 cred_t *credp, enum called_from called_from)
2194 {
2195 size_t i;
2196 screen_pos_t tabstop;
2197
2198 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2199 called_from == CALLED_FROM_STANDALONE);
2200
2201 tabstop = tems.ts_c_dimension.width - 1;
2202
2203 for (i = 0; i < tem->tvs_ntabs; i++) {
2204 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
2205 tabstop = tem->tvs_tabs[i];
2206 break;
2207 }
2208 }
2209
2210 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
2211 tabstop, credp, called_from);
2212 }
2213
2214 static void
tem_safe_set_tab(struct tem_vt_state * tem)2215 tem_safe_set_tab(struct tem_vt_state *tem)
2216 {
2217 size_t i, j;
2218
2219 if (tem->tvs_ntabs == tem->tvs_maxtab)
2220 return;
2221 if (tem->tvs_ntabs == 0 ||
2222 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
2223 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
2224 return;
2225 }
2226 for (i = 0; i < tem->tvs_ntabs; i++) {
2227 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
2228 return;
2229 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
2230 for (j = tem->tvs_ntabs - 1; j >= i; j--)
2231 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
2232 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
2233 tem->tvs_ntabs++;
2234 return;
2235 }
2236 }
2237 }
2238
2239 static void
tem_safe_clear_tabs(struct tem_vt_state * tem,int action)2240 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
2241 {
2242 size_t i, j;
2243
2244 switch (action) {
2245 case 3: /* clear all tabs */
2246 tem->tvs_ntabs = 0;
2247 break;
2248 case 0: /* clr tab at cursor */
2249
2250 for (i = 0; i < tem->tvs_ntabs; i++) {
2251 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
2252 tem->tvs_ntabs--;
2253 for (j = i; j < tem->tvs_ntabs; j++)
2254 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
2255 return;
2256 }
2257 }
2258 break;
2259 }
2260 }
2261
2262 static void
tem_safe_mv_cursor(struct tem_vt_state * tem,int row,int col,cred_t * credp,enum called_from called_from)2263 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
2264 cred_t *credp, enum called_from called_from)
2265 {
2266 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2267 called_from == CALLED_FROM_STANDALONE);
2268
2269 /*
2270 * Sanity check and bounds enforcement. Out of bounds requests are
2271 * clipped to the screen boundaries. This seems to be what SPARC
2272 * does.
2273 */
2274 if (row < 0)
2275 row = 0;
2276 if (row >= tems.ts_c_dimension.height)
2277 row = tems.ts_c_dimension.height - 1;
2278 if (col < 0)
2279 col = 0;
2280 if (col >= tems.ts_c_dimension.width) {
2281 tem->tvs_stateflags |= TVS_WRAPPED;
2282 col = tems.ts_c_dimension.width - 1;
2283 } else {
2284 tem->tvs_stateflags &= ~TVS_WRAPPED;
2285 }
2286
2287 tem_safe_send_data(tem, credp, called_from);
2288 tem->tvs_c_cursor.row = (screen_pos_t)row;
2289 tem->tvs_c_cursor.col = (screen_pos_t)col;
2290 tem_safe_align_cursor(tem);
2291 }
2292
2293 /* ARGSUSED */
2294 void
tem_safe_reset_emulator(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from,boolean_t init_color)2295 tem_safe_reset_emulator(struct tem_vt_state *tem,
2296 cred_t *credp, enum called_from called_from,
2297 boolean_t init_color)
2298 {
2299 int j;
2300
2301 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2302 called_from == CALLED_FROM_STANDALONE);
2303
2304 tem->tvs_c_cursor.row = 0;
2305 tem->tvs_c_cursor.col = 0;
2306 tem->tvs_r_cursor.row = 0;
2307 tem->tvs_r_cursor.col = 0;
2308 tem->tvs_s_cursor.row = 0;
2309 tem->tvs_s_cursor.col = 0;
2310 tem->tvs_outindex = 0;
2311 tem->tvs_state = A_STATE_START;
2312 tem->tvs_gotparam = B_FALSE;
2313 tem->tvs_curparam = 0;
2314 tem->tvs_paramval = 0;
2315 tem->tvs_nscroll = 1;
2316
2317 if (init_color) {
2318 tem->tvs_alpha = 0xff;
2319 tem->tvs_fg_color = tems.ts_init_color.fg_color;
2320 tem->tvs_bg_color = tems.ts_init_color.bg_color;
2321 tem->tvs_flags = tems.ts_init_color.a_flags;
2322 }
2323
2324 /*
2325 * set up the initial tab stops
2326 */
2327 tem->tvs_ntabs = 0;
2328 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
2329 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
2330
2331 for (j = 0; j < TEM_MAXPARAMS; j++)
2332 tem->tvs_params[j] = 0;
2333 }
2334
2335 void
tem_safe_reset_display(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from,boolean_t clear_txt,boolean_t init_color)2336 tem_safe_reset_display(struct tem_vt_state *tem,
2337 cred_t *credp, enum called_from called_from,
2338 boolean_t clear_txt, boolean_t init_color)
2339 {
2340 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2341 called_from == CALLED_FROM_STANDALONE);
2342
2343 tem_safe_reset_emulator(tem, credp, called_from, init_color);
2344
2345 if (clear_txt) {
2346 if (tem->tvs_isactive)
2347 tem_safe_callback_cursor(tem,
2348 VIS_HIDE_CURSOR, credp, called_from);
2349
2350 tem_safe_cls(tem, credp, called_from);
2351
2352 if (tem->tvs_isactive)
2353 tem_safe_callback_cursor(tem,
2354 VIS_DISPLAY_CURSOR, credp, called_from);
2355 }
2356 }
2357
2358 static void
tem_safe_shift(struct tem_vt_state * tem,int count,int direction,cred_t * credp,enum called_from called_from)2359 tem_safe_shift(
2360 struct tem_vt_state *tem,
2361 int count,
2362 int direction,
2363 cred_t *credp,
2364 enum called_from called_from)
2365 {
2366 int rest_of_line;
2367
2368 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2369 called_from == CALLED_FROM_STANDALONE);
2370
2371 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
2372 if (count > rest_of_line)
2373 count = rest_of_line;
2374
2375 if (count <= 0)
2376 return;
2377
2378 switch (direction) {
2379 case TEM_SHIFT_LEFT:
2380 if (count < rest_of_line) {
2381 tem_safe_copy_area(tem,
2382 tem->tvs_c_cursor.col + count,
2383 tem->tvs_c_cursor.row,
2384 tems.ts_c_dimension.width - 1,
2385 tem->tvs_c_cursor.row,
2386 tem->tvs_c_cursor.col,
2387 tem->tvs_c_cursor.row,
2388 credp, called_from);
2389 }
2390
2391 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
2392 (tems.ts_c_dimension.width - count), credp,
2393 called_from);
2394 break;
2395 case TEM_SHIFT_RIGHT:
2396 if (count < rest_of_line) {
2397 tem_safe_copy_area(tem,
2398 tem->tvs_c_cursor.col,
2399 tem->tvs_c_cursor.row,
2400 tems.ts_c_dimension.width - count - 1,
2401 tem->tvs_c_cursor.row,
2402 tem->tvs_c_cursor.col + count,
2403 tem->tvs_c_cursor.row,
2404 credp, called_from);
2405 }
2406
2407 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
2408 tem->tvs_c_cursor.col, credp, called_from);
2409 break;
2410 }
2411 }
2412
2413 void
tem_safe_text_cursor(struct tem_vt_state * tem,short action,cred_t * credp,enum called_from called_from)2414 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
2415 cred_t *credp, enum called_from called_from)
2416 {
2417 struct vis_conscursor ca;
2418
2419 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2420 called_from == CALLED_FROM_STANDALONE);
2421
2422 ca.row = tem->tvs_c_cursor.row;
2423 ca.col = tem->tvs_c_cursor.col;
2424 ca.action = action;
2425
2426 tems_safe_cursor(&ca, credp, called_from);
2427
2428 if (action == VIS_GET_CURSOR) {
2429 tem->tvs_c_cursor.row = ca.row;
2430 tem->tvs_c_cursor.col = ca.col;
2431 }
2432 }
2433
2434 void
tem_safe_pix_cursor(struct tem_vt_state * tem,short action,cred_t * credp,enum called_from called_from)2435 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
2436 cred_t *credp, enum called_from called_from)
2437 {
2438 struct vis_conscursor ca;
2439 text_color_t fg, bg;
2440 term_char_t c;
2441 text_attr_t attr;
2442
2443 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2444 called_from == CALLED_FROM_STANDALONE);
2445
2446 ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height +
2447 tems.ts_p_offset.y;
2448 ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width +
2449 tems.ts_p_offset.x;
2450 ca.width = (screen_size_t)tems.ts_font.vf_width;
2451 ca.height = (screen_size_t)tems.ts_font.vf_height;
2452
2453 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2454 TEM_ATTR_REVERSE);
2455 c.tc_char = TEM_ATTR(attr);
2456
2457 tem_safe_get_color(tem, &fg, &bg, &c);
2458 tem_safe_set_color(&fg, &ca.fg_color);
2459 tem_safe_set_color(&bg, &ca.bg_color);
2460
2461 ca.action = action;
2462
2463 tems_safe_cursor(&ca, credp, called_from);
2464
2465 if (action == VIS_GET_CURSOR) {
2466 tem->tvs_c_cursor.row = 0;
2467 tem->tvs_c_cursor.col = 0;
2468
2469 if (ca.row != 0) {
2470 tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) /
2471 tems.ts_font.vf_height;
2472 }
2473 if (ca.col != 0) {
2474 tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) /
2475 tems.ts_font.vf_width;
2476 }
2477 }
2478 }
2479
2480 static void
bit_to_pix4(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)2481 bit_to_pix4(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
2482 text_color_t bg)
2483 {
2484 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2485
2486 font_bit_to_pix4(&tems.ts_font, dest, c, fg.n, bg.n);
2487 }
2488
2489 static void
bit_to_pix8(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)2490 bit_to_pix8(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
2491 text_color_t bg)
2492 {
2493 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2494
2495 font_bit_to_pix8(&tems.ts_font, dest, c, fg.n, bg.n);
2496 }
2497
2498 static void
bit_to_pix16(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)2499 bit_to_pix16(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
2500 text_color_t bg)
2501 {
2502 uint16_t *dest;
2503
2504 dest = (uint16_t *)tem->tvs_pix_data;
2505 font_bit_to_pix16(&tems.ts_font, dest, c, fg.n, bg.n);
2506 }
2507
2508 static void
bit_to_pix24(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)2509 bit_to_pix24(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
2510 text_color_t bg)
2511 {
2512 uint8_t *dest;
2513
2514 dest = (uint8_t *)tem->tvs_pix_data;
2515 font_bit_to_pix24(&tems.ts_font, dest, c, fg.n, bg.n);
2516 }
2517
2518 static void
bit_to_pix32(struct tem_vt_state * tem,tem_char_t c,text_color_t fg,text_color_t bg)2519 bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
2520 text_color_t bg)
2521 {
2522 uint32_t *dest;
2523
2524 dest = (uint32_t *)tem->tvs_pix_data;
2525 font_bit_to_pix32(&tems.ts_font, dest, c, fg.n, bg.n);
2526 }
2527
2528 /*
2529 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2530 */
2531 void
tem_safe_get_attr(struct tem_vt_state * tem,text_color_t * fg,text_color_t * bg,text_attr_t * attr,uint8_t flag)2532 tem_safe_get_attr(struct tem_vt_state *tem, text_color_t *fg,
2533 text_color_t *bg, text_attr_t *attr, uint8_t flag)
2534 {
2535 if (tem->tvs_flags & flag) {
2536 *fg = tem->tvs_bg_color;
2537 *bg = tem->tvs_fg_color;
2538 } else {
2539 *fg = tem->tvs_fg_color;
2540 *bg = tem->tvs_bg_color;
2541 }
2542
2543 if (attr != NULL)
2544 *attr = tem->tvs_flags;
2545 }
2546
2547 static void
tem_safe_get_color(struct tem_vt_state * tem,text_color_t * fg,text_color_t * bg,term_char_t * c)2548 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2549 text_color_t *bg, term_char_t *c)
2550 {
2551 boolean_t bold_font;
2552
2553 *fg = c->tc_fg_color;
2554 *bg = c->tc_bg_color;
2555
2556 bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0;
2557
2558 /*
2559 * If we have both normal and bold font components,
2560 * we use bold font for TEM_ATTR_BOLD.
2561 * The bright color is traditionally used with TEM_ATTR_BOLD,
2562 * in case there is no bold font.
2563 */
2564 if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG) &&
2565 c->tc_fg_color.n < XLATE_NCOLORS) {
2566 if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_FG) ||
2567 (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BOLD) && !bold_font))
2568 fg->n = brt_xlate[c->tc_fg_color.n];
2569 else
2570 fg->n = dim_xlate[c->tc_fg_color.n];
2571 }
2572
2573 if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG) &&
2574 c->tc_bg_color.n < XLATE_NCOLORS) {
2575 if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_BG))
2576 bg->n = brt_xlate[c->tc_bg_color.n];
2577 else
2578 bg->n = dim_xlate[c->tc_bg_color.n];
2579 }
2580
2581 if (tems.ts_display_mode == VIS_TEXT)
2582 return;
2583
2584 if (tems.ts_pdepth == 8) {
2585 /* 8-bit depth is using indexed colors. */
2586 #ifndef _HAVE_TEM_FIRMWARE
2587 fg->n = tems.ts_color_map(fg->n);
2588 bg->n = tems.ts_color_map(bg->n);
2589 #endif
2590 return;
2591 }
2592
2593 /*
2594 * Translate fg and bg to RGB colors.
2595 */
2596 if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG)) {
2597 fg->n = rgb_to_color(&rgb_info,
2598 fg->rgb.a, fg->rgb.r, fg->rgb.g, fg->rgb.b);
2599 } else {
2600 #ifdef _HAVE_TEM_FIRMWARE
2601 if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32)
2602 fg->n = PIX4TO32(fg->n);
2603 #else
2604 fg->n = rgb_color_map(&rgb_info, fg->n, tem->tvs_alpha);
2605 #endif
2606 }
2607
2608 if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG)) {
2609 bg->n = rgb_to_color(&rgb_info,
2610 bg->rgb.a, bg->rgb.r, bg->rgb.g, bg->rgb.b);
2611 } else {
2612 #ifdef _HAVE_TEM_FIRMWARE
2613 if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32)
2614 bg->n = PIX4TO32(bg->n);
2615 #else
2616 bg->n = rgb_color_map(&rgb_info, bg->n, tem->tvs_alpha);
2617 #endif
2618 }
2619 }
2620
2621 static void
tem_safe_set_color(text_color_t * t,color_t * c)2622 tem_safe_set_color(text_color_t *t, color_t *c)
2623 {
2624 switch (tems.ts_pdepth) {
2625 case 4:
2626 c->four = t->n & 0xFF;
2627 break;
2628 case 8:
2629 c->eight = t->n & 0xFF;
2630 break;
2631 case 15:
2632 case 16:
2633 c->sixteen[0] = (t->n >> 8) & 0xFF;
2634 c->sixteen[1] = t->n & 0xFF;
2635 break;
2636 case 24:
2637 c->twentyfour[0] = (t->n >> 16) & 0xFF;
2638 c->twentyfour[1] = (t->n >> 8) & 0xFF;
2639 c->twentyfour[2] = t->n & 0xFF;
2640 break;
2641 default:
2642 *(uint32_t *)c = t->n;
2643 break;
2644 }
2645 }
2646
2647 /*
2648 * Clear a rectangle of screen for pixel mode.
2649 *
2650 * arguments:
2651 * row: start row#
2652 * nrows: the number of rows to clear
2653 * offset_y: the offset of height in pixels to begin clear
2654 * col: start col#
2655 * ncols: the number of cols to clear
2656 * offset_x: the offset of width in pixels to begin clear
2657 * scroll_up: whether this function is called during sroll up,
2658 * which is called only once.
2659 */
2660 void
tem_safe_pix_cls_range(struct tem_vt_state * tem,screen_pos_t row,int nrows,int offset_y,screen_pos_t col,int ncols,int offset_x,boolean_t sroll_up,cred_t * credp,enum called_from called_from)2661 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2662 screen_pos_t row, int nrows, int offset_y,
2663 screen_pos_t col, int ncols, int offset_x,
2664 boolean_t sroll_up, cred_t *credp,
2665 enum called_from called_from)
2666 {
2667 struct vis_consdisplay da;
2668 int i, j;
2669 int row_add = 0;
2670 term_char_t c;
2671 text_attr_t attr;
2672
2673 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2674 called_from == CALLED_FROM_STANDALONE);
2675
2676 if (sroll_up)
2677 row_add = tems.ts_c_dimension.height - 1;
2678
2679 da.width = (screen_size_t)tems.ts_font.vf_width;
2680 da.height = (screen_size_t)tems.ts_font.vf_height;
2681
2682 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2683 TEM_ATTR_SCREEN_REVERSE);
2684 /* Make sure we will not draw underlines */
2685 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
2686
2687 tem_safe_callback_bit2pix(tem, &c);
2688 da.data = (uchar_t *)tem->tvs_pix_data;
2689
2690 for (i = 0; i < nrows; i++, row++) {
2691 da.row = (row + row_add) * da.height + offset_y;
2692 da.col = col * da.width + offset_x;
2693 for (j = 0; j < ncols; j++) {
2694 tems_safe_display(&da, credp, called_from);
2695 da.col += da.width;
2696 }
2697 }
2698 }
2699
2700 /*
2701 * virtual screen operations
2702 */
2703 static void
tem_safe_virtual_display(struct tem_vt_state * tem,term_char_t * string,int count,screen_pos_t row,screen_pos_t col)2704 tem_safe_virtual_display(struct tem_vt_state *tem, term_char_t *string,
2705 int count, screen_pos_t row, screen_pos_t col)
2706 {
2707 int i, width;
2708 term_char_t *addr;
2709
2710 if (row < 0 || row >= tems.ts_c_dimension.height ||
2711 col < 0 || col >= tems.ts_c_dimension.width ||
2712 col + count > tems.ts_c_dimension.width)
2713 return;
2714
2715 width = tems.ts_c_dimension.width;
2716 addr = tem->tvs_screen_buf + (row * width + col);
2717 for (i = 0; i < count; i++) {
2718 *addr++ = string[i];
2719 }
2720 }
2721
2722 static void
i_virtual_copy_tem_chars(term_char_t * base,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row)2723 i_virtual_copy_tem_chars(term_char_t *base,
2724 screen_pos_t s_col, screen_pos_t s_row,
2725 screen_pos_t e_col, screen_pos_t e_row,
2726 screen_pos_t t_col, screen_pos_t t_row)
2727 {
2728 term_char_t *from;
2729 term_char_t *to;
2730 int cnt;
2731 screen_size_t chars_per_row;
2732 term_char_t *to_row_start;
2733 term_char_t *from_row_start;
2734 screen_size_t rows_to_move;
2735 int cols = tems.ts_c_dimension.width;
2736
2737 chars_per_row = e_col - s_col + 1;
2738 rows_to_move = e_row - s_row + 1;
2739
2740 to_row_start = base + ((t_row * cols) + t_col);
2741 from_row_start = base + ((s_row * cols) + s_col);
2742
2743 if (to_row_start < from_row_start) {
2744 while (rows_to_move-- > 0) {
2745 to = to_row_start;
2746 from = from_row_start;
2747 to_row_start += cols;
2748 from_row_start += cols;
2749 for (cnt = chars_per_row; cnt-- > 0; )
2750 *to++ = *from++;
2751 }
2752 } else {
2753 /*
2754 * Offset to the end of the region and copy backwards.
2755 */
2756 cnt = rows_to_move * cols + chars_per_row;
2757 to_row_start += cnt;
2758 from_row_start += cnt;
2759
2760 while (rows_to_move-- > 0) {
2761 to_row_start -= cols;
2762 from_row_start -= cols;
2763 to = to_row_start;
2764 from = from_row_start;
2765 for (cnt = chars_per_row; cnt-- > 0; )
2766 *--to = *--from;
2767 }
2768 }
2769 }
2770
2771 static void
tem_safe_virtual_copy(struct tem_vt_state * tem,screen_pos_t s_col,screen_pos_t s_row,screen_pos_t e_col,screen_pos_t e_row,screen_pos_t t_col,screen_pos_t t_row)2772 tem_safe_virtual_copy(struct tem_vt_state *tem,
2773 screen_pos_t s_col, screen_pos_t s_row,
2774 screen_pos_t e_col, screen_pos_t e_row,
2775 screen_pos_t t_col, screen_pos_t t_row)
2776 {
2777 screen_size_t chars_per_row;
2778 screen_size_t rows_to_move;
2779 int rows = tems.ts_c_dimension.height;
2780 int cols = tems.ts_c_dimension.width;
2781
2782 if (s_col < 0 || s_col >= cols ||
2783 s_row < 0 || s_row >= rows ||
2784 e_col < 0 || e_col >= cols ||
2785 e_row < 0 || e_row >= rows ||
2786 t_col < 0 || t_col >= cols ||
2787 t_row < 0 || t_row >= rows ||
2788 s_col > e_col ||
2789 s_row > e_row)
2790 return;
2791
2792 chars_per_row = e_col - s_col + 1;
2793 rows_to_move = e_row - s_row + 1;
2794
2795 /* More sanity checks. */
2796 if (t_row + rows_to_move > rows ||
2797 t_col + chars_per_row > cols)
2798 return;
2799
2800 i_virtual_copy_tem_chars(tem->tvs_screen_buf, s_col, s_row,
2801 e_col, e_row, t_col, t_row);
2802 }
2803
2804 static void
tem_safe_virtual_cls(struct tem_vt_state * tem,int count,screen_pos_t row,screen_pos_t col)2805 tem_safe_virtual_cls(struct tem_vt_state *tem,
2806 int count, screen_pos_t row, screen_pos_t col)
2807 {
2808 int i;
2809 text_attr_t attr;
2810 term_char_t c;
2811
2812 tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
2813 TEM_ATTR_SCREEN_REVERSE);
2814 c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
2815
2816 for (i = 0; i < tems.ts_c_dimension.width; i++)
2817 tems.ts_blank_line[i] = c;
2818
2819 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col);
2820 }
2821
2822 /*
2823 * only blank screen, not clear our screen buffer
2824 */
2825 void
tem_safe_blank_screen(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2826 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2827 enum called_from called_from)
2828 {
2829 int row;
2830
2831 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2832 called_from == CALLED_FROM_STANDALONE);
2833
2834 if (tems.ts_display_mode == VIS_PIXEL) {
2835 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2836 return;
2837 }
2838
2839 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2840 tem_safe_callback_cls(tem,
2841 tems.ts_c_dimension.width,
2842 row, 0, credp, called_from);
2843 }
2844 }
2845
2846 /*
2847 * unblank screen with associated tem from its screen buffer
2848 */
2849 void
tem_safe_unblank_screen(struct tem_vt_state * tem,cred_t * credp,enum called_from called_from)2850 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2851 enum called_from called_from)
2852 {
2853 int row;
2854
2855 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2856 called_from == CALLED_FROM_STANDALONE);
2857
2858 if (tems.ts_display_mode == VIS_PIXEL)
2859 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2860
2861 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2862
2863 /*
2864 * Display data in tvs_screen_buf to the actual framebuffer in a
2865 * row by row way.
2866 * When dealing with one row, output data with the same foreground
2867 * and background color all together.
2868 */
2869 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2870 tem_safe_callback_display(tem, tem->tvs_screen_rows[row],
2871 tems.ts_c_dimension.width, row, 0, credp, called_from);
2872 }
2873
2874 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
2875 }
2876