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 */
30
31 /*
32 * Polled I/O safe ANSI terminal emulator module;
33 * Supporting TERM types 'sun' and 'sun-color, parsing
34 * ANSI x3.64 escape sequences, and the like. (See wscons(7d)
35 * for more information).
36 *
37 * IMPORTANT:
38 *
39 * The functions in this file *must* be able to function in
40 * standalone mode, ie. on a quiesced system. In that state,
41 * access is single threaded, only one CPU is running.
42 * System services are NOT available.
43 *
44 * The following restrictions pertain to every function
45 * in this file:
46 *
47 * - CANNOT use the DDI or LDI interfaces
48 * - CANNOT call system services
49 * - CANNOT use mutexes
50 * - CANNOT wait for interrupts
51 * - CANNOT allocate memory
52 *
53 * All non-static functions in this file which:
54 * - Operates on tems and tem_vt_state
55 * - Not only called from standalone mode, i.e. has
56 * a "calledfrom" argument
57 * should assert this at the beginning:
58 *
59 * ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
60 * called_from == CALLED_FROM_STANDALONE);
61 */
62
63 #include <sys/types.h>
64 #include <sys/ascii.h>
65 #include <sys/visual_io.h>
66 #include <sys/font.h>
67 #include <sys/tem.h>
68 #include <sys/tem_impl.h>
69 #include <sys/ksynch.h>
70 #include <sys/sysmacros.h>
71 #include <sys/mutex.h>
72 #include <sys/note.h>
73 #include <sys/t_lock.h>
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,
260 enum called_from called_from)
261 {
262 /*
263 * Check for UTF-8 code points. In case of error fall back to
264 * 8-bit code. As we only have 8859-1 fonts for console, this will set
265 * the limits on what chars we actually can display, therefore we
266 * have to return to this code once we have solved the font issue.
267 */
268 if ((c & 0x80) == 0x00) {
269 /* One-byte sequence. */
270 tem_safe_input_partial(tem, credp, called_from);
271 tem_safe_parse(tem, c, credp, called_from);
272 return;
273 }
274 if ((c & 0xe0) == 0xc0) {
275 /* Two-byte sequence. */
276 tem_safe_input_partial(tem, credp, called_from);
277 tem->tvs_utf8_left = 1;
278 tem->tvs_utf8_partial = c;
279 return;
280 }
281 if ((c & 0xf0) == 0xe0) {
282 /* Three-byte sequence. */
283 tem_safe_input_partial(tem, credp, called_from);
284 tem->tvs_utf8_left = 2;
285 tem->tvs_utf8_partial = c;
286 return;
287 }
288 if ((c & 0xf8) == 0xf0) {
289 /* Four-byte sequence. */
290 tem_safe_input_partial(tem, credp, called_from);
291 tem->tvs_utf8_left = 3;
292 tem->tvs_utf8_partial = c;
293 return;
294 }
295 if ((c & 0xc0) == 0x80) {
296 /* Invalid state? */
297 if (tem->tvs_utf8_left == 0) {
298 tem_safe_parse(tem, c, credp, called_from);
299 return;
300 }
301 tem->tvs_utf8_left--;
302 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
303 if (tem->tvs_utf8_left == 0) {
304 tem_char_t v, u;
305 uint8_t b;
306
307 /*
308 * Transform the sequence of 2 to 4 bytes to
309 * unicode number.
310 */
311 v = 0;
312 u = tem->tvs_utf8_partial;
313 b = (u >> 24) & 0xff;
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(
354 struct tem_vt_state *tem,
355 uchar_t *buf,
356 int len,
357 cred_t *credp,
358 enum called_from called_from)
359 {
360
361 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
362 called_from == CALLED_FROM_STANDALONE);
363
364 if (tem->tvs_isactive)
365 tem_safe_callback_cursor(tem,
366 VIS_HIDE_CURSOR, credp, called_from);
367
368 for (; len > 0; len--, buf++)
369 tem_safe_input_byte(tem, *buf, credp, called_from);
370
371 /*
372 * Send the data we just got to the framebuffer.
373 */
374 tem_safe_send_data(tem, credp, called_from);
375
376 if (tem->tvs_isactive)
377 tem_safe_callback_cursor(tem,
378 VIS_DISPLAY_CURSOR, credp, called_from);
379 }
380
381 /*
382 * Display an rectangular image on the frame buffer using the
383 * mechanism appropriate for the system state being called
384 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
385 */
386 static void
387 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
388 enum called_from called_from)
389 {
390 if (called_from == CALLED_FROM_STANDALONE)
391 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
392 else
393 tems_display_layered(pda, credp);
394 }
395
396 /*
397 * Copy a rectangle from one location to another on the frame buffer
398 * using the mechanism appropriate for the system state being called
399 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
400 */
401 void
402 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
403 enum called_from called_from)
404 {
405 if (called_from == CALLED_FROM_STANDALONE)
406 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
407 else
408 tems_copy_layered(pca, credp);
409 }
410
411 /*
412 * Display or hide a rectangular block text cursor of a specificsize
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:
454 /*
455 * tem_safe_send_data(tem, credp, called_from);
456 * tem_safe_new_line(tem, credp, called_from);
457 * break;
458 */
459
460 case A_VT:
461 tem_safe_send_data(tem, credp, called_from);
462 tem_safe_lf(tem, credp, called_from);
463 break;
464
465 case A_FF:
466 tem_safe_send_data(tem, credp, called_from);
467 tem_safe_cls(tem, credp, called_from);
468 break;
469
470 case A_CR:
471 tem_safe_send_data(tem, credp, called_from);
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
525 for (i = 0; i < count; i++) {
526 if (tem->tvs_params[i] == -1)
527 tem->tvs_params[i] = newparam;
528 }
529 }
530
531
532 /*
533 * select graphics mode based on the param vals stored in a_params
534 */
535 static void
536 tem_safe_selgraph(struct tem_vt_state *tem)
537 {
538 int curparam;
539 int count = 0;
540 int param;
541
542 tem->tvs_state = A_STATE_START;
543
544 curparam = tem->tvs_curparam;
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
620 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
621 break;
622
623 case 40: /* black (grey) background */
624 case 41: /* red (light red) background */
625 case 42: /* green (light green) background */
626 case 43: /* brown (yellow) background */
627 case 44: /* blue (light blue) background */
628 case 45: /* magenta (light magenta) background */
629 case 46: /* cyan (light cyan) background */
630 case 47: /* white (bright white) background */
631 tem->tvs_bg_color = param - 40;
632 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
633 break;
634
635 case 49:
636 /*
637 * Reset the background colour and brightness.
638 */
639 tem->tvs_bg_color = tems.ts_init_color.bg_color;
640 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
641 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
642 else
643 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
644 break;
645
646 case 90: /* black (grey) foreground */
647 case 91: /* red (light red) foreground */
648 case 92: /* green (light green) foreground */
649 case 93: /* brown (yellow) foreground */
650 case 94: /* blue (light blue) foreground */
651 case 95: /* magenta (light magenta) foreground */
652 case 96: /* cyan (light cyan) foreground */
653 case 97: /* white (bright white) foreground */
654 tem->tvs_fg_color = param - 90;
655 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
656 break;
657
658 case 100: /* black (grey) background */
659 case 101: /* red (light red) background */
660 case 102: /* green (light green) background */
661 case 103: /* brown (yellow) background */
662 case 104: /* blue (light blue) background */
663 case 105: /* magenta (light magenta) background */
664 case 106: /* cyan (light cyan) background */
665 case 107: /* white (bright white) background */
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 */
707 tem_safe_setparam(tem, 1, 1);
708 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
709 credp, called_from);
710 break;
711
712 case 'A': /* cursor up */
713 tem_safe_setparam(tem, 1, 1);
714 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
715 credp, called_from);
716 break;
717
718 case 'd': /* VPA - vertical position absolute */
719 tem_safe_setparam(tem, 1, 1);
720 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
721 credp, called_from);
722 break;
723
724 case 'e': /* VPR - vertical position relative */
725 case 'B': /* cursor down */
726 tem_safe_setparam(tem, 1, 1);
727 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
728 credp, called_from);
729 break;
730
731 case 'a': /* HPR - horizontal position relative */
732 case 'C': /* cursor right */
733 tem_safe_setparam(tem, 1, 1);
734 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
735 credp, called_from);
736 break;
737
738 case '`': /* HPA - horizontal position absolute */
739 tem_safe_setparam(tem, 1, 1);
740 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
741 credp, called_from);
742 break;
743
744 case 'D': /* cursor left */
745 tem_safe_setparam(tem, 1, 1);
746 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
747 credp, called_from);
748 break;
749
750 case 'E': /* CNL cursor next line */
751 tem_safe_setparam(tem, 1, 1);
752 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
753 credp, called_from);
754 break;
755
756 case 'F': /* CPL cursor previous line */
757 tem_safe_setparam(tem, 1, 1);
758 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
759 credp, called_from);
760 break;
761
762 case 'G': /* cursor horizontal position */
763 tem_safe_setparam(tem, 1, 1);
764 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
765 credp, called_from);
766 break;
767
768 case 'g': /* clear tabs */
769 tem_safe_setparam(tem, 1, 0);
770 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
771 break;
772
773 case 'f': /* HVP Horizontal and Vertical Position */
774 case 'H': /* CUP position cursor */
775 tem_safe_setparam(tem, 2, 1);
776 tem_safe_mv_cursor(tem,
777 tem->tvs_params[0] - 1,
778 tem->tvs_params[1] - 1,
779 credp, called_from);
780 break;
781
782 case 'I': /* CHT - Cursor Horizontal Tab */
783 /* Not implemented */
784 break;
785
786 case 'J': /* ED - Erase in Display */
787 tem_safe_send_data(tem, credp, called_from);
788 tem_safe_setparam(tem, 1, 0);
789 switch (tem->tvs_params[0]) {
790 case 0:
791 /* erase cursor to end of screen */
792 /* FIRST erase cursor to end of line */
793 tem_safe_clear_chars(tem,
794 tems.ts_c_dimension.width -
795 tem->tvs_c_cursor.col,
796 tem->tvs_c_cursor.row,
797 tem->tvs_c_cursor.col, credp, called_from);
798
799 /* THEN erase lines below the cursor */
800 for (row = tem->tvs_c_cursor.row + 1;
801 row < tems.ts_c_dimension.height;
802 row++) {
803 tem_safe_clear_chars(tem,
804 tems.ts_c_dimension.width,
805 row, 0, credp, called_from);
806 }
807 break;
808
809 case 1:
810 /* erase beginning of screen to cursor */
811 /* FIRST erase lines above the cursor */
812 for (row = 0;
813 row < tem->tvs_c_cursor.row;
814 row++) {
815 tem_safe_clear_chars(tem,
816 tems.ts_c_dimension.width,
817 row, 0, credp, called_from);
818 }
819 /* THEN erase beginning of line to cursor */
820 tem_safe_clear_chars(tem,
821 tem->tvs_c_cursor.col + 1,
822 tem->tvs_c_cursor.row,
823 0, credp, called_from);
824 break;
825
826 case 2:
827 /* erase whole screen */
828 for (row = 0;
829 row < tems.ts_c_dimension.height;
830 row++) {
831 tem_safe_clear_chars(tem,
832 tems.ts_c_dimension.width,
833 row, 0, credp, called_from);
834 }
835 break;
836 }
837 break;
838
839 case 'K': /* EL - Erase in Line */
840 tem_safe_send_data(tem, credp, called_from);
841 tem_safe_setparam(tem, 1, 0);
842 switch (tem->tvs_params[0]) {
843 case 0:
844 /* erase cursor to end of line */
845 tem_safe_clear_chars(tem,
846 (tems.ts_c_dimension.width -
847 tem->tvs_c_cursor.col),
848 tem->tvs_c_cursor.row,
849 tem->tvs_c_cursor.col,
850 credp, called_from);
851 break;
852
853 case 1:
854 /* erase beginning of line to cursor */
855 tem_safe_clear_chars(tem,
856 tem->tvs_c_cursor.col + 1,
857 tem->tvs_c_cursor.row,
858 0, credp, called_from);
859 break;
860
861 case 2:
862 /* erase whole line */
863 tem_safe_clear_chars(tem,
864 tems.ts_c_dimension.width,
865 tem->tvs_c_cursor.row,
866 0, credp, called_from);
867 break;
868 }
869 break;
870
871 case 'L': /* insert line */
872 tem_safe_send_data(tem, credp, called_from);
873 tem_safe_setparam(tem, 1, 1);
874 tem_safe_scroll(tem,
875 tem->tvs_c_cursor.row,
876 tems.ts_c_dimension.height - 1,
877 tem->tvs_params[0], TEM_SCROLL_DOWN,
878 credp, called_from);
879 break;
880
881 case 'M': /* delete line */
882 tem_safe_send_data(tem, credp, called_from);
883 tem_safe_setparam(tem, 1, 1);
884 tem_safe_scroll(tem,
885 tem->tvs_c_cursor.row,
886 tems.ts_c_dimension.height - 1,
887 tem->tvs_params[0], TEM_SCROLL_UP,
888 credp, called_from);
889 break;
890
891 case 'P': /* DCH - delete char */
892 tem_safe_setparam(tem, 1, 1);
893 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
894 credp, called_from);
895 break;
896
897 case 'S': /* scroll up */
898 tem_safe_send_data(tem, credp, called_from);
899 tem_safe_setparam(tem, 1, 1);
900 tem_safe_scroll(tem, 0,
901 tems.ts_c_dimension.height - 1,
902 tem->tvs_params[0], TEM_SCROLL_UP,
903 credp, called_from);
904 break;
905
906 case 'T': /* scroll down */
907 tem_safe_send_data(tem, credp, called_from);
908 tem_safe_setparam(tem, 1, 1);
909 tem_safe_scroll(tem, 0,
910 tems.ts_c_dimension.height - 1,
911 tem->tvs_params[0], TEM_SCROLL_DOWN,
912 credp, called_from);
913 break;
914
915 case 'X': /* erase char */
916 tem_safe_setparam(tem, 1, 1);
917 tem_safe_clear_chars(tem,
918 tem->tvs_params[0],
919 tem->tvs_c_cursor.row,
920 tem->tvs_c_cursor.col,
921 credp, called_from);
922 break;
923
924 case 'Z': /* cursor backward tabulation */
925 tem_safe_setparam(tem, 1, 1);
926
927 /*
928 * Rule exception - We do sanity checking here.
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);
1080 }
1081
1082 static void
1083 tem_safe_lf(struct tem_vt_state *tem,
1084 cred_t *credp, enum called_from called_from)
1085 {
1086 int row;
1087
1088 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1089 MUTEX_HELD(&tem->tvs_lock));
1090
1091 /*
1092 * Sanity checking notes:
1093 * . a_nscroll was validated when it was set.
1094 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
1095 * will prevent anything bad from happening.
1096 */
1097 row = tem->tvs_c_cursor.row + 1;
1098
1099 if (row >= tems.ts_c_dimension.height) {
1100 if (tem->tvs_nscroll != 0) {
1101 tem_safe_scroll(tem, 0,
1102 tems.ts_c_dimension.height - 1,
1103 tem->tvs_nscroll, TEM_SCROLL_UP,
1104 credp, called_from);
1105 row = tems.ts_c_dimension.height -
1106 tem->tvs_nscroll;
1107 } else { /* no scroll */
1108 /*
1109 * implement Esc[#r when # is zero. This means no
1110 * scroll but just return cursor to top of screen,
1111 * do not clear screen.
1112 */
1113 row = 0;
1114 }
1115 }
1116
1117 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
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"
1230 * definition does not exist anywhere in
1231 * /etc/termcap.
1232 * However, having no coherent
1233 * definition of reset, we have not
1234 * implemented it.
1235 */
1236
1237 /*
1238 * Original code
1239 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1240 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1241 * tem->tvs_state = A_STATE_START;
1242 */
1243
1244 tem->tvs_state = A_STATE_START;
1245 return;
1246 case 'u':
1247 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1248 tem->tvs_r_cursor.col, credp, called_from);
1249 tem->tvs_state = A_STATE_START;
1250 return;
1251 case 'p': /* sunbow */
1252 tem_safe_send_data(tem, credp, called_from);
1253 /*
1254 * Don't set anything if we are
1255 * already as we want to be.
1256 */
1257 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1258 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1259 /*
1260 * If we have switched the characters to be the
1261 * inverse from the screen, then switch them as
1262 * well to keep them the inverse of the screen.
1263 */
1264 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1265 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1266 else
1267 tem->tvs_flags |= TEM_ATTR_REVERSE;
1268 }
1269 tem_safe_cls(tem, credp, called_from);
1270 tem->tvs_state = A_STATE_START;
1271 return;
1272 case 'q': /* sunwob */
1273 tem_safe_send_data(tem, credp, called_from);
1274 /*
1275 * Don't set anything if we are
1276 * already where as we want to be.
1277 */
1278 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1279 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1280 /*
1281 * If we have switched the characters to be the
1282 * inverse from the screen, then switch them as
1283 * well to keep them the inverse of the screen.
1284 */
1285 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1286 tem->tvs_flags |= TEM_ATTR_REVERSE;
1287 else
1288 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1289 }
1290
1291 tem_safe_cls(tem, credp, called_from);
1292 tem->tvs_state = A_STATE_START;
1293 return;
1294 case 'r': /* sunscrl */
1295 /*
1296 * Rule exception: check for validity here.
1297 */
1298 tem->tvs_nscroll = tem->tvs_paramval;
1299 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
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,
1348 tem->tvs_r_cursor.col, credp, called_from);
1349 /* check for control chars */
1350 } else if (ch < ' ') {
1351 tem_safe_control(tem, ch, credp, called_from);
1352 } else {
1353 tem_safe_outch(tem, ch, credp, called_from);
1354 }
1355 }
1356 }
1357
1358 /* ARGSUSED */
1359 static void
1360 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1361 {
1362 if (called_from == CALLED_FROM_STANDALONE)
1363 (void) beep_polled(BEEP_CONSOLE);
1364 else
1365 (void) beep(BEEP_CONSOLE);
1366 }
1367
1368
1369 static void
1370 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1371 int direction, cred_t *credp, enum called_from called_from)
1372 {
1373 int row;
1374 int lines_affected;
1375
1376 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1377 called_from == CALLED_FROM_STANDALONE);
1378
1379 lines_affected = end - start + 1;
1380 if (count > lines_affected)
1381 count = lines_affected;
1382 if (count <= 0)
1383 return;
1384
1385 switch (direction) {
1386 case TEM_SCROLL_UP:
1387 if (count < lines_affected) {
1388 tem_safe_copy_area(tem, 0, start + count,
1389 tems.ts_c_dimension.width - 1, end,
1390 0, start, credp, called_from);
1391 }
1392 for (row = (end - count) + 1; row <= end; row++) {
1393 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1394 row, 0, credp, called_from);
1395 }
1396 break;
1397
1398 case TEM_SCROLL_DOWN:
1399 if (count < lines_affected) {
1400 tem_safe_copy_area(tem, 0, start,
1401 tems.ts_c_dimension.width - 1,
1402 end - count, 0, start + count,
1403 credp, called_from);
1404 }
1405 for (row = start; row < start + count; row++) {
1406 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1407 row, 0, credp, called_from);
1408 }
1409 break;
1410 }
1411 }
1412
1413 static void
1414 tem_safe_copy_area(struct tem_vt_state *tem,
1415 screen_pos_t s_col, screen_pos_t s_row,
1416 screen_pos_t e_col, screen_pos_t e_row,
1417 screen_pos_t t_col, screen_pos_t t_row,
1418 cred_t *credp, enum called_from called_from)
1419 {
1420 int rows;
1421 int cols;
1422
1423 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1424 called_from == CALLED_FROM_STANDALONE);
1425
1426 if (s_col < 0 || s_row < 0 ||
1427 e_col < 0 || e_row < 0 ||
1428 t_col < 0 || t_row < 0 ||
1429 s_col >= tems.ts_c_dimension.width ||
1430 e_col >= tems.ts_c_dimension.width ||
1431 t_col >= tems.ts_c_dimension.width ||
1432 s_row >= tems.ts_c_dimension.height ||
1433 e_row >= tems.ts_c_dimension.height ||
1434 t_row >= tems.ts_c_dimension.height)
1435 return;
1436
1437 if (s_row > e_row || s_col > e_col)
1438 return;
1439
1440 rows = e_row - s_row + 1;
1441 cols = e_col - s_col + 1;
1442 if (t_row + rows > tems.ts_c_dimension.height ||
1443 t_col + cols > tems.ts_c_dimension.width)
1444 return;
1445
1446 tem_safe_virtual_copy(tem,
1447 s_col, s_row,
1448 e_col, e_row,
1449 t_col, t_row);
1450
1451 if (!tem->tvs_isactive)
1452 return;
1453
1454 tem_safe_callback_copy(tem, s_col, s_row,
1455 e_col, e_row, t_col, t_row, credp, called_from);
1456 }
1457
1458 static void
1459 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1460 screen_pos_t col, cred_t *credp, enum called_from called_from)
1461 {
1462 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1463 called_from == CALLED_FROM_STANDALONE);
1464
1465 if (row < 0 || row >= tems.ts_c_dimension.height ||
1466 col < 0 || col >= tems.ts_c_dimension.width ||
1467 count < 0)
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
1736 * because OBP's term may have a bigger terminal window than that of
1737 * our kernel console term. So we need to clear OBP output garbage outside
1738 * of our kernel console term at a proper time, which is when the first
1739 * row output of our kernel console term scrolls at the first screen line.
1740 *
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)) ||
1834 called_from == CALLED_FROM_STANDALONE);
1835
1836 if (tems.ts_display_mode == VIS_TEXT) {
1837 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1838 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1839 row, 0, credp, called_from);
1840 }
1841 tem->tvs_c_cursor.row = 0;
1842 tem->tvs_c_cursor.col = 0;
1843 tem_safe_align_cursor(tem);
1844 return;
1845 }
1846
1847 ASSERT(tems.ts_display_mode == VIS_PIXEL);
1848
1849 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1850 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
1851 }
1852 tem->tvs_c_cursor.row = 0;
1853 tem->tvs_c_cursor.col = 0;
1854 tem_safe_align_cursor(tem);
1855
1856 if (!tem->tvs_isactive)
1857 return;
1858
1859 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
1860 }
1861
1862 static void
1863 tem_safe_back_tab(struct tem_vt_state *tem,
1864 cred_t *credp, enum called_from called_from)
1865 {
1866 int i;
1867 screen_pos_t tabstop;
1868
1869 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1870 called_from == CALLED_FROM_STANDALONE);
1871
1872 tabstop = 0;
1873
1874 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
1875 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
1876 tabstop = tem->tvs_tabs[i];
1877 break;
1878 }
1879 }
1880
1881 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1882 tabstop, credp, called_from);
1883 }
1884
1885 static void
1886 tem_safe_tab(struct tem_vt_state *tem,
1887 cred_t *credp, enum called_from called_from)
1888 {
1889 int i;
1890 screen_pos_t tabstop;
1891
1892 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1893 called_from == CALLED_FROM_STANDALONE);
1894
1895 tabstop = tems.ts_c_dimension.width - 1;
1896
1897 for (i = 0; i < tem->tvs_ntabs; i++) {
1898 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1899 tabstop = tem->tvs_tabs[i];
1900 break;
1901 }
1902 }
1903
1904 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1905 tabstop, credp, called_from);
1906 }
1907
1908 static void
1909 tem_safe_set_tab(struct tem_vt_state *tem)
1910 {
1911 int i;
1912 int j;
1913
1914 if (tem->tvs_ntabs == TEM_MAXTAB)
1915 return;
1916 if (tem->tvs_ntabs == 0 ||
1917 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
1918 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
1919 return;
1920 }
1921 for (i = 0; i < tem->tvs_ntabs; i++) {
1922 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
1923 return;
1924 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1925 for (j = tem->tvs_ntabs - 1; j >= i; j--)
1926 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
1927 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
1928 tem->tvs_ntabs++;
1929 return;
1930 }
1931 }
1932 }
1933
1934 static void
1935 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
1936 {
1937 int i;
1938 int j;
1939
1940 switch (action) {
1941 case 3: /* clear all tabs */
1942 tem->tvs_ntabs = 0;
1943 break;
1944 case 0: /* clr tab at cursor */
1945
1946 for (i = 0; i < tem->tvs_ntabs; i++) {
1947 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
1948 tem->tvs_ntabs--;
1949 for (j = i; j < tem->tvs_ntabs; j++)
1950 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
1951 return;
1952 }
1953 }
1954 break;
1955 }
1956 }
1957
1958 static void
1959 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
1960 cred_t *credp, enum called_from called_from)
1961 {
1962 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1963 called_from == CALLED_FROM_STANDALONE);
1964
1965 /*
1966 * Sanity check and bounds enforcement. Out of bounds requests are
1967 * clipped to the screen boundaries. This seems to be what SPARC
1968 * does.
1969 */
1970 if (row < 0)
1971 row = 0;
1972 if (row >= tems.ts_c_dimension.height)
1973 row = tems.ts_c_dimension.height - 1;
1974 if (col < 0)
1975 col = 0;
1976 if (col >= tems.ts_c_dimension.width)
1977 col = tems.ts_c_dimension.width - 1;
1978
1979 tem_safe_send_data(tem, credp, called_from);
1980 tem->tvs_c_cursor.row = (screen_pos_t)row;
1981 tem->tvs_c_cursor.col = (screen_pos_t)col;
1982 tem_safe_align_cursor(tem);
1983 }
1984
1985 /* ARGSUSED */
1986 void
1987 tem_safe_reset_emulator(struct tem_vt_state *tem,
1988 cred_t *credp, enum called_from called_from,
1989 boolean_t init_color)
1990 {
1991 int j;
1992
1993 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1994 called_from == CALLED_FROM_STANDALONE);
1995
1996 tem->tvs_c_cursor.row = 0;
1997 tem->tvs_c_cursor.col = 0;
1998 tem->tvs_r_cursor.row = 0;
1999 tem->tvs_r_cursor.col = 0;
2000 tem->tvs_s_cursor.row = 0;
2001 tem->tvs_s_cursor.col = 0;
2002 tem->tvs_outindex = 0;
2003 tem->tvs_state = A_STATE_START;
2004 tem->tvs_gotparam = B_FALSE;
2005 tem->tvs_curparam = 0;
2006 tem->tvs_paramval = 0;
2007 tem->tvs_nscroll = 1;
2008
2009 if (init_color) {
2010 /* use initial settings */
2011 tem->tvs_fg_color = tems.ts_init_color.fg_color;
2012 tem->tvs_bg_color = tems.ts_init_color.bg_color;
2013 tem->tvs_flags = tems.ts_init_color.a_flags;
2014 }
2015
2016 /*
2017 * set up the initial tab stops
2018 */
2019 tem->tvs_ntabs = 0;
2020 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
2021 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
2022
2023 for (j = 0; j < TEM_MAXPARAMS; j++)
2024 tem->tvs_params[j] = 0;
2025 }
2026
2027 void
2028 tem_safe_reset_display(struct tem_vt_state *tem,
2029 cred_t *credp, enum called_from called_from,
2030 boolean_t clear_txt, boolean_t init_color)
2031 {
2032 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2033 called_from == CALLED_FROM_STANDALONE);
2034
2035 tem_safe_reset_emulator(tem, credp, called_from, init_color);
2036
2037 if (clear_txt) {
2038 if (tem->tvs_isactive)
2039 tem_safe_callback_cursor(tem,
2040 VIS_HIDE_CURSOR, credp, called_from);
2041
2042 tem_safe_cls(tem, credp, called_from);
2043
2044 if (tem->tvs_isactive)
2045 tem_safe_callback_cursor(tem,
2046 VIS_DISPLAY_CURSOR, credp, called_from);
2047 }
2048 }
2049
2050 static void
2051 tem_safe_shift(
2052 struct tem_vt_state *tem,
2053 int count,
2054 int direction,
2055 cred_t *credp,
2056 enum called_from called_from)
2057 {
2058 int rest_of_line;
2059
2060 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2061 called_from == CALLED_FROM_STANDALONE);
2062
2063 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
2064 if (count > rest_of_line)
2065 count = rest_of_line;
2066
2067 if (count <= 0)
2068 return;
2069
2070 switch (direction) {
2071 case TEM_SHIFT_LEFT:
2072 if (count < rest_of_line) {
2073 tem_safe_copy_area(tem,
2074 tem->tvs_c_cursor.col + count,
2075 tem->tvs_c_cursor.row,
2076 tems.ts_c_dimension.width - 1,
2077 tem->tvs_c_cursor.row,
2078 tem->tvs_c_cursor.col,
2079 tem->tvs_c_cursor.row,
2080 credp, called_from);
2081 }
2082
2083 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
2084 (tems.ts_c_dimension.width - count), credp,
2085 called_from);
2086 break;
2087 case TEM_SHIFT_RIGHT:
2088 if (count < rest_of_line) {
2089 tem_safe_copy_area(tem,
2090 tem->tvs_c_cursor.col,
2091 tem->tvs_c_cursor.row,
2092 tems.ts_c_dimension.width - count - 1,
2093 tem->tvs_c_cursor.row,
2094 tem->tvs_c_cursor.col + count,
2095 tem->tvs_c_cursor.row,
2096 credp, called_from);
2097 }
2098
2099 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
2100 tem->tvs_c_cursor.col, credp, called_from);
2101 break;
2102 }
2103 }
2104
2105 void
2106 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
2107 cred_t *credp, enum called_from called_from)
2108 {
2109 struct vis_conscursor ca;
2110
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 /*
2441 * Offset to the end of the region and copy backwards.
2442 */
2443 cnt = rows_to_move * cols + chars_per_row;
2444 to_row_start += cnt;
2445 from_row_start += cnt;
2446
2447 while (rows_to_move-- > 0) {
2448 to_row_start -= cols;
2449 from_row_start -= cols;
2450 to = to_row_start;
2451 from = from_row_start;
2452 for (cnt = chars_per_row; cnt-- > 0; )
2453 *--to = *--from;
2454 }
2455 }
2456 }
2457
2458 static void
2459 tem_safe_virtual_copy(struct tem_vt_state *tem,
2460 screen_pos_t s_col, screen_pos_t s_row,
2461 screen_pos_t e_col, screen_pos_t e_row,
2462 screen_pos_t t_col, screen_pos_t t_row)
2463 {
2464 screen_size_t chars_per_row;
2465 screen_size_t rows_to_move;
2466 int rows = tems.ts_c_dimension.height;
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 }