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
91 static void tem_safe_control(struct tem_vt_state *, uchar_t,
92 cred_t *, enum called_from);
93 static void tem_safe_setparam(struct tem_vt_state *, int, int);
94 static void tem_safe_selgraph(struct tem_vt_state *);
95 static void tem_safe_chkparam(struct tem_vt_state *, uchar_t,
96 cred_t *, enum called_from);
97 static void tem_safe_getparams(struct tem_vt_state *, uchar_t,
98 cred_t *, enum called_from);
99 static void tem_safe_outch(struct tem_vt_state *, uchar_t,
100 cred_t *, enum called_from);
101 static void tem_safe_parse(struct tem_vt_state *, uchar_t,
102 cred_t *, enum called_from);
103
104 static void tem_safe_new_line(struct tem_vt_state *,
105 cred_t *, enum called_from);
106 static void tem_safe_cr(struct tem_vt_state *);
107 static void tem_safe_lf(struct tem_vt_state *,
108 cred_t *, enum called_from);
109 static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
110 enum called_from);
111 static void tem_safe_cls(struct tem_vt_state *,
112 cred_t *, enum called_from);
113 static void tem_safe_tab(struct tem_vt_state *,
114 cred_t *, enum called_from);
115 static void tem_safe_back_tab(struct tem_vt_state *,
116 cred_t *, enum called_from);
117 static void tem_safe_clear_tabs(struct tem_vt_state *, int);
118 static void tem_safe_set_tab(struct tem_vt_state *);
119 static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
120 cred_t *, enum called_from);
121 static void tem_safe_shift(struct tem_vt_state *, int, int,
122 cred_t *, enum called_from);
123 static void tem_safe_scroll(struct tem_vt_state *, int, int,
124 int, int, cred_t *, enum called_from);
125 static void tem_safe_clear_chars(struct tem_vt_state *tem,
126 int count, screen_pos_t row, screen_pos_t col,
127 cred_t *credp, enum called_from called_from);
128 static void tem_safe_copy_area(struct tem_vt_state *tem,
129 screen_pos_t s_col, screen_pos_t s_row,
130 screen_pos_t e_col, screen_pos_t e_row,
131 screen_pos_t t_col, screen_pos_t t_row,
132 cred_t *credp, enum called_from called_from);
133 static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
134 int, int, screen_pos_t, screen_pos_t,
135 cred_t *, enum called_from);
136 static void tem_safe_bell(struct tem_vt_state *tem,
137 enum called_from called_from);
138 static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
139 cred_t *credp, enum called_from called_from);
140
141 static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
142 screen_pos_t);
143 static void tem_safe_virtual_display(struct tem_vt_state *,
144 unsigned char *, int, screen_pos_t, screen_pos_t,
145 text_color_t, text_color_t);
146 static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
147 screen_pos_t, screen_pos_t, screen_pos_t,
148 screen_pos_t, screen_pos_t);
149 static void tem_safe_align_cursor(struct tem_vt_state *tem);
150 static void bit_to_pix4(struct tem_vt_state *tem, uchar_t c,
151 text_color_t fg_color, text_color_t bg_color);
152 static void bit_to_pix8(struct tem_vt_state *tem, uchar_t c,
153 text_color_t fg_color, text_color_t bg_color);
154 static void bit_to_pix24(struct tem_vt_state *tem, uchar_t c,
155 text_color_t fg_color, text_color_t bg_color);
156
157 /* BEGIN CSTYLED */
158 /* Bk Rd Gr Br Bl Mg Cy Wh */
159 static text_color_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 };
160 static text_color_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 };
161 /* END CSTYLED */
162
163
164 text_cmap_t cmap4_to_24 = {
165 /* BEGIN CSTYLED */
166 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
167 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */
168 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff,
169 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff,
170 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
171 /* END CSTYLED */
172 };
173
174 #define PIX4TO32(pix4) (uint32_t)( \
175 cmap4_to_24.red[pix4] << 16 | \
176 cmap4_to_24.green[pix4] << 8 | \
177 cmap4_to_24.blue[pix4])
178
179 #define INVERSE(ch) (ch ^ 0xff)
180
181 #define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
182 #define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
183 #define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
184 #define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
185 #define tem_safe_callback_bit2pix(tem, c, fg, bg) { \
186 ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
187 (void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c), (fg), (bg));\
188 }
189
190 void
191 tem_safe_check_first_time(
192 struct tem_vt_state *tem,
193 cred_t *credp,
194 enum called_from called_from)
195 {
196 static int first_time = 1;
197
198 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
199 called_from == CALLED_FROM_STANDALONE);
200
201 /*
202 * Realign the console cursor. We did this in tem_init().
203 * However, drivers in the console stream may emit additional
204 * messages before we are ready. This causes text overwrite
205 * on the screen. This is a workaround.
206 */
207 if (!first_time)
208 return;
209
210 first_time = 0;
211 if (tems.ts_display_mode == VIS_TEXT) {
212 tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
213 tem_safe_align_cursor(tem);
214 }
215 }
216
217 /*
218 * This entry point handles output requests from restricted contexts like
219 * kmdb, where services like mutexes are not available. This function
220 * is entered when OBP or when a kernel debugger (such as kmdb)
221 * are generating console output. In those cases, power management
222 * concerns are handled by the abort sequence initiation (ie. when
223 * the user hits L1+A or the equivalent to enter OBP or the debugger.).
224 * It is also entered when the kernel is panicing.
225 */
226 void
227 tem_safe_polled_write(
228 tem_vt_state_t tem_arg,
229 uchar_t *buf,
230 int len)
231 {
232 struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
233
234 if (!tem->tvs_initialized) {
235 return;
236 }
237
238 tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
239 tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
240 }
241
242 /* Process partial UTF-8 sequence. */
243 static void
244 tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
245 enum called_from called_from)
246 {
247 int i;
248 uint8_t c;
249
250 if (tem->tvs_utf8_left == 0)
251 return;
252
253 for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
254 c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
255 if (c != 0) {
256 tem_safe_parse(tem, c, credp, called_from);
257 }
258 }
259 tem->tvs_utf8_left = 0;
260 tem->tvs_utf8_partial = 0;
261 }
262
263 /*
264 * Handle UTF-8 sequences.
265 */
266 static void
267 tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
268 enum called_from called_from)
269 {
270 /*
271 * Check for UTF-8 code points. In case of error fall back to
272 * 8-bit code. As we only have 8859-1 fonts for console, this will set
273 * the limits on what chars we actually can display, therefore we
274 * have to return to this code once we have solved the font issue.
275 */
276 if ((c & 0x80) == 0x00) {
277 /* One-byte sequence. */
278 tem_safe_input_partial(tem, credp, called_from);
279 tem_safe_parse(tem, c, credp, called_from);
280 return;
281 }
282 if ((c & 0xe0) == 0xc0) {
283 /* Two-byte sequence. */
284 tem_safe_input_partial(tem, credp, called_from);
285 tem->tvs_utf8_left = 1;
286 tem->tvs_utf8_partial = c;
287 return;
288 }
289 if ((c & 0xf0) == 0xe0) {
290 /* Three-byte sequence. */
291 tem_safe_input_partial(tem, credp, called_from);
292 tem->tvs_utf8_left = 2;
293 tem->tvs_utf8_partial = c;
294 return;
295 }
296 if ((c & 0xf8) == 0xf0) {
297 /* Four-byte sequence. */
298 tem_safe_input_partial(tem, credp, called_from);
299 tem->tvs_utf8_left = 3;
300 tem->tvs_utf8_partial = c;
301 return;
302 }
303 if ((c & 0xc0) == 0x80) {
304 /* Invalid state? */
305 if (tem->tvs_utf8_left == 0) {
306 tem_safe_parse(tem, c, credp, called_from);
307 return;
308 }
309 tem->tvs_utf8_left--;
310 tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
311 if (tem->tvs_utf8_left == 0) {
312 tem_char_t v, u;
313 uint8_t b;
314
315 /*
316 * Transform the sequence of 2 to 4 bytes to
317 * unicode number.
318 */
319 v = 0;
320 u = tem->tvs_utf8_partial;
321 b = (u >> 24) & 0xff;
322 if (b != 0) { /* Four-byte sequence */
323 v = b & 0x07;
324 b = (u >> 16) & 0xff;
325 v = (v << 6) | (b & 0x3f);
326 b = (u >> 8) & 0xff;
327 v = (v << 6) | (b & 0x3f);
328 b = u & 0xff;
329 v = (v << 6) | (b & 0x3f);
330 } else if ((b = (u >> 16) & 0xff) != 0) {
331 v = b & 0x0f; /* Three-byte sequence */
332 b = (u >> 8) & 0xff;
333 v = (v << 6) | (b & 0x3f);
334 b = u & 0xff;
335 v = (v << 6) | (b & 0x3f);
336 } else if ((b = (u >> 8) & 0xff) != 0) {
337 v = b & 0x1f; /* Two-byte sequence */
338 b = u & 0xff;
339 v = (v << 6) | (b & 0x3f);
340 }
341
342 /* Use '?' as replacement if needed. */
343 if (v > 0xff)
344 v = '?';
345 tem_safe_parse(tem, v, credp, called_from);
346 tem->tvs_utf8_partial = 0;
347 }
348 return;
349 }
350 /* Anything left is illegal in UTF-8 sequence. */
351 tem_safe_input_partial(tem, credp, called_from);
352 tem_safe_parse(tem, c, credp, called_from);
353 }
354
355 /*
356 * This is the main entry point into the terminal emulator.
357 *
358 * For each data message coming downstream, ANSI assumes that it is composed
359 * of ASCII characters, which are treated as a byte-stream input to the
360 * parsing state machine. All data is parsed immediately -- there is
361 * no enqueing.
362 */
363 void
364 tem_safe_terminal_emulate(
365 struct tem_vt_state *tem,
366 uchar_t *buf,
367 int len,
368 cred_t *credp,
369 enum called_from called_from)
370 {
371
372 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
373 called_from == CALLED_FROM_STANDALONE);
374
375 if (tem->tvs_isactive)
376 tem_safe_callback_cursor(tem,
377 VIS_HIDE_CURSOR, credp, called_from);
378
379 for (; len > 0; len--, buf++)
380 tem_safe_input_byte(tem, *buf, credp, called_from);
381
382 /*
383 * Send the data we just got to the framebuffer.
384 */
385 tem_safe_send_data(tem, credp, called_from);
386
387 if (tem->tvs_isactive)
388 tem_safe_callback_cursor(tem,
389 VIS_DISPLAY_CURSOR, credp, called_from);
390 }
391
392 /*
393 * Display an rectangular image on the frame buffer using the
394 * mechanism appropriate for the system state being called
395 * from quiesced or normal (ie. use polled I/O vs. layered ioctls)
396 */
397 static void
398 tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
399 enum called_from called_from)
400 {
401 if (called_from == CALLED_FROM_STANDALONE)
402 tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
403 else
404 tems_display_layered(pda, credp);
405 }
406
407 /*
408 * Copy a rectangle from one location to another on the frame buffer
409 * using the mechanism appropriate for the system state being called
410 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls)
411 */
412 void
413 tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
414 enum called_from called_from)
415 {
416 if (called_from == CALLED_FROM_STANDALONE)
417 tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
418 else
419 tems_copy_layered(pca, credp);
420 }
421
422 /*
423 * Display or hide a rectangular block text cursor of a specificsize
424 * at a specific location on frame buffer* using the mechanism
425 * appropriate for the system state being called from, quisced or
426 * normal (ie. use polled I/O vs. layered ioctls).
427 */
428 static void
429 tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
430 enum called_from called_from)
431 {
432 if (called_from == CALLED_FROM_STANDALONE)
433 tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
434 else
435 tems_cursor_layered(pca, credp);
436 }
437
438 /*
439 * send the appropriate control message or set state based on the
440 * value of the control character ch
441 */
442
443 static void
444 tem_safe_control(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
445 enum called_from called_from)
446 {
447 tem->tvs_state = A_STATE_START;
448 switch (ch) {
449 case A_BEL:
450 tem_safe_bell(tem, called_from);
451 break;
452
453 case A_BS:
454 tem_safe_mv_cursor(tem,
455 tem->tvs_c_cursor.row,
456 tem->tvs_c_cursor.col - 1,
457 credp, called_from);
458 break;
459
460 case A_HT:
461 tem_safe_tab(tem, credp, called_from);
462 break;
463
464 case A_NL:
465 /*
466 * tem_safe_send_data(tem, credp, called_from);
467 * tem_safe_new_line(tem, credp, called_from);
468 * break;
469 */
470
471 case A_VT:
472 tem_safe_send_data(tem, credp, called_from);
473 tem_safe_lf(tem, credp, called_from);
474 break;
475
476 case A_FF:
477 tem_safe_send_data(tem, credp, called_from);
478 tem_safe_cls(tem, credp, called_from);
479 break;
480
481 case A_CR:
482 tem_safe_send_data(tem, credp, called_from);
483 tem_safe_cr(tem);
484 break;
485
486 case A_ESC:
487 tem->tvs_state = A_STATE_ESC;
488 break;
489
490 case A_CSI:
491 {
492 int i;
493 tem->tvs_curparam = 0;
494 tem->tvs_paramval = 0;
495 tem->tvs_gotparam = B_FALSE;
496 /* clear the parameters */
497 for (i = 0; i < TEM_MAXPARAMS; i++)
498 tem->tvs_params[i] = -1;
499 tem->tvs_state = A_STATE_CSI;
500 }
501 break;
502
503 case A_GS:
504 tem_safe_back_tab(tem, credp, called_from);
505 break;
506
507 default:
508 break;
509 }
510 }
511
512
513 /*
514 * if parameters [0..count - 1] are not set, set them to the value
515 * of newparam.
516 */
517
518 static void
519 tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
520 {
521 int i;
522
523 for (i = 0; i < count; i++) {
524 if (tem->tvs_params[i] == -1)
525 tem->tvs_params[i] = newparam;
526 }
527 }
528
529
530 /*
531 * select graphics mode based on the param vals stored in a_params
532 */
533 static void
534 tem_safe_selgraph(struct tem_vt_state *tem)
535 {
536 int curparam;
537 int count = 0;
538 int param;
539
540 tem->tvs_state = A_STATE_START;
541
542 curparam = tem->tvs_curparam;
543 do {
544 param = tem->tvs_params[count];
545
546 switch (param) {
547 case -1:
548 case 0:
549 /* reset to initial normal settings */
550 tem->tvs_fg_color = tems.ts_init_color.fg_color;
551 tem->tvs_bg_color = tems.ts_init_color.bg_color;
552 tem->tvs_flags = tems.ts_init_color.a_flags;
553 break;
554
555 case 1: /* Bold Intense */
556 tem->tvs_flags |= TEM_ATTR_BOLD;
557 break;
558
559 case 2: /* Faint Intense */
560 tem->tvs_flags &= ~TEM_ATTR_BOLD;
561 break;
562
563 case 5: /* Blink */
564 tem->tvs_flags |= TEM_ATTR_BLINK;
565 break;
566
567 case 7: /* Reverse video */
568 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
569 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
570 } else {
571 tem->tvs_flags |= TEM_ATTR_REVERSE;
572 }
573 break;
574
575 case 30: /* black (grey) foreground */
576 case 31: /* red (light red) foreground */
577 case 32: /* green (light green) foreground */
578 case 33: /* brown (yellow) foreground */
579 case 34: /* blue (light blue) foreground */
580 case 35: /* magenta (light magenta) foreground */
581 case 36: /* cyan (light cyan) foreground */
582 case 37: /* white (bright white) foreground */
583 tem->tvs_fg_color = param - 30;
584 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
585 break;
586
587 case 39:
588 /*
589 * Reset the foreground colour and brightness.
590 */
591 tem->tvs_fg_color = tems.ts_init_color.fg_color;
592 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
593 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
594 else
595 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
596 break;
597
598 case 40: /* black (grey) background */
599 case 41: /* red (light red) background */
600 case 42: /* green (light green) background */
601 case 43: /* brown (yellow) background */
602 case 44: /* blue (light blue) background */
603 case 45: /* magenta (light magenta) background */
604 case 46: /* cyan (light cyan) background */
605 case 47: /* white (bright white) background */
606 tem->tvs_bg_color = param - 40;
607 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
608 break;
609
610 case 49:
611 /*
612 * Reset the background colour and brightness.
613 */
614 tem->tvs_bg_color = tems.ts_init_color.bg_color;
615 if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
616 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
617 else
618 tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
619 break;
620
621 case 90: /* black (grey) foreground */
622 case 91: /* red (light red) foreground */
623 case 92: /* green (light green) foreground */
624 case 93: /* brown (yellow) foreground */
625 case 94: /* blue (light blue) foreground */
626 case 95: /* magenta (light magenta) foreground */
627 case 96: /* cyan (light cyan) foreground */
628 case 97: /* white (bright white) foreground */
629 tem->tvs_fg_color = param - 90;
630 tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
631 break;
632
633 case 100: /* black (grey) background */
634 case 101: /* red (light red) background */
635 case 102: /* green (light green) background */
636 case 103: /* brown (yellow) background */
637 case 104: /* blue (light blue) background */
638 case 105: /* magenta (light magenta) background */
639 case 106: /* cyan (light cyan) background */
640 case 107: /* white (bright white) background */
641 tem->tvs_bg_color = param - 100;
642 tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
643 break;
644
645 default:
646 break;
647 }
648 count++;
649 curparam--;
650
651 } while (curparam > 0);
652 }
653
654 /*
655 * perform the appropriate action for the escape sequence
656 *
657 * General rule: This code does not validate the arguments passed.
658 * It assumes that the next lower level will do so.
659 */
660 static void
661 tem_safe_chkparam(struct tem_vt_state *tem, uchar_t ch, cred_t *credp,
662 enum called_from called_from)
663 {
664 int i;
665 int row;
666 int col;
667
668 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
669 MUTEX_HELD(&tem->tvs_lock));
670
671 row = tem->tvs_c_cursor.row;
672 col = tem->tvs_c_cursor.col;
673
674 switch (ch) {
675
676 case 'm': /* select terminal graphics mode */
677 tem_safe_send_data(tem, credp, called_from);
678 tem_safe_selgraph(tem);
679 break;
680
681 case '@': /* insert char */
682 tem_safe_setparam(tem, 1, 1);
683 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
684 credp, called_from);
685 break;
686
687 case 'A': /* cursor up */
688 tem_safe_setparam(tem, 1, 1);
689 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
690 credp, called_from);
691 break;
692
693 case 'd': /* VPA - vertical position absolute */
694 tem_safe_setparam(tem, 1, 1);
695 tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
696 credp, called_from);
697 break;
698
699 case 'e': /* VPR - vertical position relative */
700 case 'B': /* cursor down */
701 tem_safe_setparam(tem, 1, 1);
702 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
703 credp, called_from);
704 break;
705
706 case 'a': /* HPR - horizontal position relative */
707 case 'C': /* cursor right */
708 tem_safe_setparam(tem, 1, 1);
709 tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
710 credp, called_from);
711 break;
712
713 case '`': /* HPA - horizontal position absolute */
714 tem_safe_setparam(tem, 1, 1);
715 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
716 credp, called_from);
717 break;
718
719 case 'D': /* cursor left */
720 tem_safe_setparam(tem, 1, 1);
721 tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
722 credp, called_from);
723 break;
724
725 case 'E': /* CNL cursor next line */
726 tem_safe_setparam(tem, 1, 1);
727 tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
728 credp, called_from);
729 break;
730
731 case 'F': /* CPL cursor previous line */
732 tem_safe_setparam(tem, 1, 1);
733 tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
734 credp, called_from);
735 break;
736
737 case 'G': /* cursor horizontal position */
738 tem_safe_setparam(tem, 1, 1);
739 tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
740 credp, called_from);
741 break;
742
743 case 'g': /* clear tabs */
744 tem_safe_setparam(tem, 1, 0);
745 tem_safe_clear_tabs(tem, tem->tvs_params[0]);
746 break;
747
748 case 'f': /* HVP Horizontal and Vertical Position */
749 case 'H': /* CUP position cursor */
750 tem_safe_setparam(tem, 2, 1);
751 tem_safe_mv_cursor(tem,
752 tem->tvs_params[0] - 1,
753 tem->tvs_params[1] - 1,
754 credp, called_from);
755 break;
756
757 case 'I': /* CHT - Cursor Horizontal Tab */
758 /* Not implemented */
759 break;
760
761 case 'J': /* ED - Erase in Display */
762 tem_safe_send_data(tem, credp, called_from);
763 tem_safe_setparam(tem, 1, 0);
764 switch (tem->tvs_params[0]) {
765 case 0:
766 /* erase cursor to end of screen */
767 /* FIRST erase cursor to end of line */
768 tem_safe_clear_chars(tem,
769 tems.ts_c_dimension.width -
770 tem->tvs_c_cursor.col,
771 tem->tvs_c_cursor.row,
772 tem->tvs_c_cursor.col, credp, called_from);
773
774 /* THEN erase lines below the cursor */
775 for (row = tem->tvs_c_cursor.row + 1;
776 row < tems.ts_c_dimension.height;
777 row++) {
778 tem_safe_clear_chars(tem,
779 tems.ts_c_dimension.width,
780 row, 0, credp, called_from);
781 }
782 break;
783
784 case 1:
785 /* erase beginning of screen to cursor */
786 /* FIRST erase lines above the cursor */
787 for (row = 0;
788 row < tem->tvs_c_cursor.row;
789 row++) {
790 tem_safe_clear_chars(tem,
791 tems.ts_c_dimension.width,
792 row, 0, credp, called_from);
793 }
794 /* THEN erase beginning of line to cursor */
795 tem_safe_clear_chars(tem,
796 tem->tvs_c_cursor.col + 1,
797 tem->tvs_c_cursor.row,
798 0, credp, called_from);
799 break;
800
801 case 2:
802 /* erase whole screen */
803 for (row = 0;
804 row < tems.ts_c_dimension.height;
805 row++) {
806 tem_safe_clear_chars(tem,
807 tems.ts_c_dimension.width,
808 row, 0, credp, called_from);
809 }
810 break;
811 }
812 break;
813
814 case 'K': /* EL - Erase in Line */
815 tem_safe_send_data(tem, credp, called_from);
816 tem_safe_setparam(tem, 1, 0);
817 switch (tem->tvs_params[0]) {
818 case 0:
819 /* erase cursor to end of line */
820 tem_safe_clear_chars(tem,
821 (tems.ts_c_dimension.width -
822 tem->tvs_c_cursor.col),
823 tem->tvs_c_cursor.row,
824 tem->tvs_c_cursor.col,
825 credp, called_from);
826 break;
827
828 case 1:
829 /* erase beginning of line to cursor */
830 tem_safe_clear_chars(tem,
831 tem->tvs_c_cursor.col + 1,
832 tem->tvs_c_cursor.row,
833 0, credp, called_from);
834 break;
835
836 case 2:
837 /* erase whole line */
838 tem_safe_clear_chars(tem,
839 tems.ts_c_dimension.width,
840 tem->tvs_c_cursor.row,
841 0, credp, called_from);
842 break;
843 }
844 break;
845
846 case 'L': /* insert line */
847 tem_safe_send_data(tem, credp, called_from);
848 tem_safe_setparam(tem, 1, 1);
849 tem_safe_scroll(tem,
850 tem->tvs_c_cursor.row,
851 tems.ts_c_dimension.height - 1,
852 tem->tvs_params[0], TEM_SCROLL_DOWN,
853 credp, called_from);
854 break;
855
856 case 'M': /* delete line */
857 tem_safe_send_data(tem, credp, called_from);
858 tem_safe_setparam(tem, 1, 1);
859 tem_safe_scroll(tem,
860 tem->tvs_c_cursor.row,
861 tems.ts_c_dimension.height - 1,
862 tem->tvs_params[0], TEM_SCROLL_UP,
863 credp, called_from);
864 break;
865
866 case 'P': /* DCH - delete char */
867 tem_safe_setparam(tem, 1, 1);
868 tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
869 credp, called_from);
870 break;
871
872 case 'S': /* scroll up */
873 tem_safe_send_data(tem, credp, called_from);
874 tem_safe_setparam(tem, 1, 1);
875 tem_safe_scroll(tem, 0,
876 tems.ts_c_dimension.height - 1,
877 tem->tvs_params[0], TEM_SCROLL_UP,
878 credp, called_from);
879 break;
880
881 case 'T': /* scroll down */
882 tem_safe_send_data(tem, credp, called_from);
883 tem_safe_setparam(tem, 1, 1);
884 tem_safe_scroll(tem, 0,
885 tems.ts_c_dimension.height - 1,
886 tem->tvs_params[0], TEM_SCROLL_DOWN,
887 credp, called_from);
888 break;
889
890 case 'X': /* erase char */
891 tem_safe_setparam(tem, 1, 1);
892 tem_safe_clear_chars(tem,
893 tem->tvs_params[0],
894 tem->tvs_c_cursor.row,
895 tem->tvs_c_cursor.col,
896 credp, called_from);
897 break;
898
899 case 'Z': /* cursor backward tabulation */
900 tem_safe_setparam(tem, 1, 1);
901
902 /*
903 * Rule exception - We do sanity checking here.
904 *
905 * Restrict the count to a sane value to keep from
906 * looping for a long time. There can't be more than one
907 * tab stop per column, so use that as a limit.
908 */
909 if (tem->tvs_params[0] > tems.ts_c_dimension.width)
910 tem->tvs_params[0] = tems.ts_c_dimension.width;
911
912 for (i = 0; i < tem->tvs_params[0]; i++)
913 tem_safe_back_tab(tem, credp, called_from);
914 break;
915 }
916 tem->tvs_state = A_STATE_START;
917 }
918
919
920 /*
921 * Gather the parameters of an ANSI escape sequence
922 */
923 static void
924 tem_safe_getparams(struct tem_vt_state *tem, uchar_t ch,
925 cred_t *credp, enum called_from called_from)
926 {
927 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
928 MUTEX_HELD(&tem->tvs_lock));
929
930 if (ch >= '0' && ch <= '9') {
931 tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
932 tem->tvs_gotparam = B_TRUE; /* Remember got parameter */
933 return; /* Return immediately */
934 } else if (tem->tvs_state == A_STATE_CSI_EQUAL ||
935 tem->tvs_state == A_STATE_CSI_QMARK) {
936 tem->tvs_state = A_STATE_START;
937 } else {
938 if (tem->tvs_curparam < TEM_MAXPARAMS) {
939 if (tem->tvs_gotparam) {
940 /* get the parameter value */
941 tem->tvs_params[tem->tvs_curparam] =
942 tem->tvs_paramval;
943 }
944 tem->tvs_curparam++;
945 }
946
947 if (ch == ';') {
948 /* Restart parameter search */
949 tem->tvs_gotparam = B_FALSE;
950 tem->tvs_paramval = 0; /* No parame value yet */
951 } else {
952 /* Handle escape sequence */
953 tem_safe_chkparam(tem, ch, credp, called_from);
954 }
955 }
956 }
957
958 /*
959 * Add character to internal buffer.
960 * When its full, send it to the next layer.
961 */
962
963 static void
964 tem_safe_outch(struct tem_vt_state *tem, uchar_t ch,
965 cred_t *credp, enum called_from called_from)
966 {
967
968 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
969 called_from == CALLED_FROM_STANDALONE);
970
971 /* buffer up the character until later */
972
973 tem->tvs_outbuf[tem->tvs_outindex++] = ch;
974 tem->tvs_c_cursor.col++;
975 if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
976 tem_safe_send_data(tem, credp, called_from);
977 tem_safe_new_line(tem, credp, called_from);
978 }
979 }
980
981 static void
982 tem_safe_new_line(struct tem_vt_state *tem,
983 cred_t *credp, enum called_from called_from)
984 {
985 tem_safe_cr(tem);
986 tem_safe_lf(tem, credp, called_from);
987 }
988
989 static void
990 tem_safe_cr(struct tem_vt_state *tem)
991 {
992 tem->tvs_c_cursor.col = 0;
993 tem_safe_align_cursor(tem);
994 }
995
996 static void
997 tem_safe_lf(struct tem_vt_state *tem,
998 cred_t *credp, enum called_from called_from)
999 {
1000 int row;
1001
1002 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1003 MUTEX_HELD(&tem->tvs_lock));
1004
1005 /*
1006 * Sanity checking notes:
1007 * . a_nscroll was validated when it was set.
1008 * . Regardless of that, tem_safe_scroll and tem_safe_mv_cursor
1009 * will prevent anything bad from happening.
1010 */
1011 row = tem->tvs_c_cursor.row + 1;
1012
1013 if (row >= tems.ts_c_dimension.height) {
1014 if (tem->tvs_nscroll != 0) {
1015 tem_safe_scroll(tem, 0,
1016 tems.ts_c_dimension.height - 1,
1017 tem->tvs_nscroll, TEM_SCROLL_UP,
1018 credp, called_from);
1019 row = tems.ts_c_dimension.height -
1020 tem->tvs_nscroll;
1021 } else { /* no scroll */
1022 /*
1023 * implement Esc[#r when # is zero. This means no
1024 * scroll but just return cursor to top of screen,
1025 * do not clear screen.
1026 */
1027 row = 0;
1028 }
1029 }
1030
1031 tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
1032 credp, called_from);
1033
1034 if (tem->tvs_nscroll == 0) {
1035 /* erase rest of cursor line */
1036 tem_safe_clear_chars(tem,
1037 tems.ts_c_dimension.width -
1038 tem->tvs_c_cursor.col,
1039 tem->tvs_c_cursor.row,
1040 tem->tvs_c_cursor.col,
1041 credp, called_from);
1042
1043 }
1044
1045 tem_safe_align_cursor(tem);
1046 }
1047
1048 static void
1049 tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
1050 enum called_from called_from)
1051 {
1052 text_color_t fg_color;
1053 text_color_t bg_color;
1054
1055 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1056 MUTEX_HELD(&tem->tvs_lock));
1057
1058 if (tem->tvs_outindex == 0) {
1059 tem_safe_align_cursor(tem);
1060 return;
1061 }
1062
1063 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_REVERSE);
1064 tem_safe_virtual_display(tem,
1065 tem->tvs_outbuf, tem->tvs_outindex,
1066 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1067 fg_color, bg_color);
1068
1069 if (tem->tvs_isactive) {
1070 /*
1071 * Call the primitive to render this data.
1072 */
1073 tem_safe_callback_display(tem,
1074 tem->tvs_outbuf, tem->tvs_outindex,
1075 tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
1076 fg_color, bg_color,
1077 credp, called_from);
1078 }
1079
1080 tem->tvs_outindex = 0;
1081
1082 tem_safe_align_cursor(tem);
1083 }
1084
1085
1086 /*
1087 * We have just done something to the current output point. Reset the start
1088 * point for the buffered data in a_outbuf. There shouldn't be any data
1089 * buffered yet.
1090 */
1091 static void
1092 tem_safe_align_cursor(struct tem_vt_state *tem)
1093 {
1094 tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
1095 tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
1096 }
1097
1098 /*
1099 * State machine parser based on the current state and character input
1100 * major terminations are to control character or normal character
1101 */
1102
1103 static void
1104 tem_safe_parse(struct tem_vt_state *tem, uchar_t ch,
1105 cred_t *credp, enum called_from called_from)
1106 {
1107 int i;
1108
1109 ASSERT((called_from == CALLED_FROM_STANDALONE) ||
1110 MUTEX_HELD(&tem->tvs_lock));
1111
1112 if (tem->tvs_state == A_STATE_START) { /* Normal state? */
1113 if (ch == A_CSI || ch == A_ESC || ch < ' ') {
1114 /* Control */
1115 tem_safe_control(tem, ch, credp, called_from);
1116 } else {
1117 /* Display */
1118 tem_safe_outch(tem, ch, credp, called_from);
1119 }
1120 return;
1121 }
1122
1123 /* In <ESC> sequence */
1124 if (tem->tvs_state != A_STATE_ESC) { /* Need to get parameters? */
1125 if (tem->tvs_state != A_STATE_CSI) {
1126 tem_safe_getparams(tem, ch, credp, called_from);
1127 return;
1128 }
1129
1130 switch (ch) {
1131 case '?':
1132 tem->tvs_state = A_STATE_CSI_QMARK;
1133 return;
1134 case '=':
1135 tem->tvs_state = A_STATE_CSI_EQUAL;
1136 return;
1137 case 's':
1138 /*
1139 * As defined below, this sequence
1140 * saves the cursor. However, Sun
1141 * defines ESC[s as reset. We resolved
1142 * the conflict by selecting reset as it
1143 * is exported in the termcap file for
1144 * sun-mon, while the "save cursor"
1145 * definition does not exist anywhere in
1146 * /etc/termcap.
1147 * However, having no coherent
1148 * definition of reset, we have not
1149 * implemented it.
1150 */
1151
1152 /*
1153 * Original code
1154 * tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1155 * tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1156 * tem->tvs_state = A_STATE_START;
1157 */
1158
1159 tem->tvs_state = A_STATE_START;
1160 return;
1161 case 'u':
1162 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1163 tem->tvs_r_cursor.col, credp, called_from);
1164 tem->tvs_state = A_STATE_START;
1165 return;
1166 case 'p': /* sunbow */
1167 tem_safe_send_data(tem, credp, called_from);
1168 /*
1169 * Don't set anything if we are
1170 * already as we want to be.
1171 */
1172 if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
1173 tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
1174 /*
1175 * If we have switched the characters to be the
1176 * inverse from the screen, then switch them as
1177 * well to keep them the inverse of the screen.
1178 */
1179 if (tem->tvs_flags & TEM_ATTR_REVERSE)
1180 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1181 else
1182 tem->tvs_flags |= TEM_ATTR_REVERSE;
1183 }
1184 tem_safe_cls(tem, credp, called_from);
1185 tem->tvs_state = A_STATE_START;
1186 return;
1187 case 'q': /* sunwob */
1188 tem_safe_send_data(tem, credp, called_from);
1189 /*
1190 * Don't set anything if we are
1191 * already where as we want to be.
1192 */
1193 if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
1194 tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
1195 /*
1196 * If we have switched the characters to be the
1197 * inverse from the screen, then switch them as
1198 * well to keep them the inverse of the screen.
1199 */
1200 if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
1201 tem->tvs_flags |= TEM_ATTR_REVERSE;
1202 else
1203 tem->tvs_flags &= ~TEM_ATTR_REVERSE;
1204 }
1205
1206 tem_safe_cls(tem, credp, called_from);
1207 tem->tvs_state = A_STATE_START;
1208 return;
1209 case 'r': /* sunscrl */
1210 /*
1211 * Rule exception: check for validity here.
1212 */
1213 tem->tvs_nscroll = tem->tvs_paramval;
1214 if (tem->tvs_nscroll > tems.ts_c_dimension.height)
1215 tem->tvs_nscroll = tems.ts_c_dimension.height;
1216 if (tem->tvs_nscroll < 0)
1217 tem->tvs_nscroll = 1;
1218 tem->tvs_state = A_STATE_START;
1219 return;
1220 default:
1221 tem_safe_getparams(tem, ch, credp, called_from);
1222 return;
1223 }
1224 }
1225
1226 /* Previous char was <ESC> */
1227 if (ch == '[') {
1228 tem->tvs_curparam = 0;
1229 tem->tvs_paramval = 0;
1230 tem->tvs_gotparam = B_FALSE;
1231 /* clear the parameters */
1232 for (i = 0; i < TEM_MAXPARAMS; i++)
1233 tem->tvs_params[i] = -1;
1234 tem->tvs_state = A_STATE_CSI;
1235 } else if (ch == 'Q') { /* <ESC>Q ? */
1236 tem->tvs_state = A_STATE_START;
1237 } else if (ch == 'C') { /* <ESC>C ? */
1238 tem->tvs_state = A_STATE_START;
1239 } else {
1240 tem->tvs_state = A_STATE_START;
1241 if (ch == 'c') {
1242 /* ESC c resets display */
1243 tem_safe_reset_display(tem, credp, called_from,
1244 B_TRUE, B_TRUE);
1245 } else if (ch == 'H') {
1246 /* ESC H sets a tab */
1247 tem_safe_set_tab(tem);
1248 } else if (ch == '7') {
1249 /* ESC 7 Save Cursor position */
1250 tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
1251 tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
1252 } else if (ch == '8') {
1253 /* ESC 8 Restore Cursor position */
1254 tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
1255 tem->tvs_r_cursor.col, credp, called_from);
1256 /* check for control chars */
1257 } else if (ch < ' ') {
1258 tem_safe_control(tem, ch, credp, called_from);
1259 } else {
1260 tem_safe_outch(tem, ch, credp, called_from);
1261 }
1262 }
1263 }
1264
1265 /* ARGSUSED */
1266 static void
1267 tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
1268 {
1269 if (called_from == CALLED_FROM_STANDALONE)
1270 (void) beep_polled(BEEP_CONSOLE);
1271 else
1272 (void) beep(BEEP_CONSOLE);
1273 }
1274
1275
1276 static void
1277 tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
1278 int direction, cred_t *credp, enum called_from called_from)
1279 {
1280 int row;
1281 int lines_affected;
1282
1283 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1284 called_from == CALLED_FROM_STANDALONE);
1285
1286 lines_affected = end - start + 1;
1287 if (count > lines_affected)
1288 count = lines_affected;
1289 if (count <= 0)
1290 return;
1291
1292 switch (direction) {
1293 case TEM_SCROLL_UP:
1294 if (count < lines_affected) {
1295 tem_safe_copy_area(tem, 0, start + count,
1296 tems.ts_c_dimension.width - 1, end,
1297 0, start, credp, called_from);
1298 }
1299 for (row = (end - count) + 1; row <= end; row++) {
1300 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1301 row, 0, credp, called_from);
1302 }
1303 break;
1304
1305 case TEM_SCROLL_DOWN:
1306 if (count < lines_affected) {
1307 tem_safe_copy_area(tem, 0, start,
1308 tems.ts_c_dimension.width - 1,
1309 end - count, 0, start + count,
1310 credp, called_from);
1311 }
1312 for (row = start; row < start + count; row++) {
1313 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1314 row, 0, credp, called_from);
1315 }
1316 break;
1317 }
1318 }
1319
1320 static void
1321 tem_safe_copy_area(struct tem_vt_state *tem,
1322 screen_pos_t s_col, screen_pos_t s_row,
1323 screen_pos_t e_col, screen_pos_t e_row,
1324 screen_pos_t t_col, screen_pos_t t_row,
1325 cred_t *credp, enum called_from called_from)
1326 {
1327 int rows;
1328 int cols;
1329
1330 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1331 called_from == CALLED_FROM_STANDALONE);
1332
1333 if (s_col < 0 || s_row < 0 ||
1334 e_col < 0 || e_row < 0 ||
1335 t_col < 0 || t_row < 0 ||
1336 s_col >= tems.ts_c_dimension.width ||
1337 e_col >= tems.ts_c_dimension.width ||
1338 t_col >= tems.ts_c_dimension.width ||
1339 s_row >= tems.ts_c_dimension.height ||
1340 e_row >= tems.ts_c_dimension.height ||
1341 t_row >= tems.ts_c_dimension.height)
1342 return;
1343
1344 if (s_row > e_row || s_col > e_col)
1345 return;
1346
1347 rows = e_row - s_row + 1;
1348 cols = e_col - s_col + 1;
1349 if (t_row + rows > tems.ts_c_dimension.height ||
1350 t_col + cols > tems.ts_c_dimension.width)
1351 return;
1352
1353 tem_safe_virtual_copy(tem,
1354 s_col, s_row,
1355 e_col, e_row,
1356 t_col, t_row);
1357
1358 if (!tem->tvs_isactive)
1359 return;
1360
1361 tem_safe_callback_copy(tem, s_col, s_row,
1362 e_col, e_row, t_col, t_row, credp, called_from);
1363 }
1364
1365 static void
1366 tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
1367 screen_pos_t col, cred_t *credp, enum called_from called_from)
1368 {
1369 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1370 called_from == CALLED_FROM_STANDALONE);
1371
1372 if (row < 0 || row >= tems.ts_c_dimension.height ||
1373 col < 0 || col >= tems.ts_c_dimension.width ||
1374 count < 0)
1375 return;
1376
1377 /*
1378 * Note that very large values of "count" could cause col+count
1379 * to overflow, so we check "count" independently.
1380 */
1381 if (count > tems.ts_c_dimension.width ||
1382 col + count > tems.ts_c_dimension.width)
1383 count = tems.ts_c_dimension.width - col;
1384
1385 tem_safe_virtual_cls(tem, count, row, col);
1386
1387 if (!tem->tvs_isactive)
1388 return;
1389
1390 tem_safe_callback_cls(tem, count, row, col, credp, called_from);
1391 }
1392
1393 /*ARGSUSED*/
1394 void
1395 tem_safe_text_display(struct tem_vt_state *tem, uchar_t *string,
1396 int count, screen_pos_t row, screen_pos_t col,
1397 text_color_t fg_color, text_color_t bg_color,
1398 cred_t *credp, enum called_from called_from)
1399 {
1400 struct vis_consdisplay da;
1401
1402 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1403 called_from == CALLED_FROM_STANDALONE);
1404
1405 da.data = string;
1406 da.width = (screen_size_t)count;
1407 da.row = row;
1408 da.col = col;
1409
1410 da.fg_color = fg_color;
1411 da.bg_color = bg_color;
1412
1413 tems_safe_display(&da, credp, called_from);
1414 }
1415
1416 /*
1417 * This function is used to blit a rectangular color image,
1418 * unperturbed on the underlying framebuffer, to render
1419 * icons and pictures. The data is a pixel pattern that
1420 * fills a rectangle bounded to the width and height parameters.
1421 * The color pixel data must to be pre-adjusted by the caller
1422 * for the current video depth.
1423 *
1424 * This function is unused now.
1425 */
1426 /*ARGSUSED*/
1427 static void
1428 tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
1429 int height, int width, screen_pos_t row, screen_pos_t col,
1430 cred_t *credp, enum called_from called_from)
1431 {
1432 struct vis_consdisplay da;
1433
1434 mutex_enter(&tems.ts_lock);
1435 mutex_enter(&tem->tvs_lock);
1436
1437 da.data = image;
1438 da.width = (screen_size_t)width;
1439 da.height = (screen_size_t)height;
1440 da.row = row;
1441 da.col = col;
1442
1443 tems_safe_display(&da, credp, called_from);
1444
1445 mutex_exit(&tem->tvs_lock);
1446 mutex_exit(&tems.ts_lock);
1447 }
1448
1449
1450 /*ARGSUSED*/
1451 void
1452 tem_safe_text_copy(struct tem_vt_state *tem,
1453 screen_pos_t s_col, screen_pos_t s_row,
1454 screen_pos_t e_col, screen_pos_t e_row,
1455 screen_pos_t t_col, screen_pos_t t_row,
1456 cred_t *credp, enum called_from called_from)
1457 {
1458 struct vis_conscopy da;
1459
1460 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1461 called_from == CALLED_FROM_STANDALONE);
1462
1463 da.s_row = s_row;
1464 da.s_col = s_col;
1465 da.e_row = e_row;
1466 da.e_col = e_col;
1467 da.t_row = t_row;
1468 da.t_col = t_col;
1469
1470 tems_safe_copy(&da, credp, called_from);
1471 }
1472
1473 void
1474 tem_safe_text_cls(struct tem_vt_state *tem,
1475 int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
1476 enum called_from called_from)
1477 {
1478 struct vis_consdisplay da;
1479
1480 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1481 called_from == CALLED_FROM_STANDALONE);
1482
1483 da.data = tems.ts_blank_line;
1484 da.width = (screen_size_t)count;
1485 da.row = row;
1486 da.col = col;
1487
1488 tem_safe_get_color(tem, &da.fg_color, &da.bg_color,
1489 TEM_ATTR_SCREEN_REVERSE);
1490 tems_safe_display(&da, credp, called_from);
1491 }
1492
1493 void
1494 tem_safe_pix_display(struct tem_vt_state *tem,
1495 uchar_t *string, int count,
1496 screen_pos_t row, screen_pos_t col,
1497 text_color_t fg_color, text_color_t bg_color,
1498 cred_t *credp, enum called_from called_from)
1499 {
1500 struct vis_consdisplay da;
1501 int i;
1502
1503 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1504 called_from == CALLED_FROM_STANDALONE);
1505
1506 da.data = (uchar_t *)tem->tvs_pix_data;
1507 da.width = tems.ts_font.width;
1508 da.height = tems.ts_font.height;
1509 da.row = (row * da.height) + tems.ts_p_offset.y;
1510 da.col = (col * da.width) + tems.ts_p_offset.x;
1511
1512 for (i = 0; i < count; i++) {
1513 tem_safe_callback_bit2pix(tem, string[i], fg_color, bg_color);
1514 tems_safe_display(&da, credp, called_from);
1515 da.col += da.width;
1516 }
1517 }
1518
1519 void
1520 tem_safe_pix_copy(struct tem_vt_state *tem,
1521 screen_pos_t s_col, screen_pos_t s_row,
1522 screen_pos_t e_col, screen_pos_t e_row,
1523 screen_pos_t t_col, screen_pos_t t_row,
1524 cred_t *credp,
1525 enum called_from called_from)
1526 {
1527 struct vis_conscopy ma;
1528 static boolean_t need_clear = B_TRUE;
1529
1530 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1531 called_from == CALLED_FROM_STANDALONE);
1532
1533 if (need_clear && tem->tvs_first_line > 0) {
1534 /*
1535 * Clear OBP output above our kernel console term
1536 * when our kernel console term begins to scroll up,
1537 * we hope it is user friendly.
1538 * (Also see comments on tem_safe_pix_clear_prom_output)
1539 *
1540 * This is only one time call.
1541 */
1542 tem_safe_pix_clear_prom_output(tem, credp, called_from);
1543 }
1544 need_clear = B_FALSE;
1545
1546 ma.s_row = s_row * tems.ts_font.height + tems.ts_p_offset.y;
1547 ma.e_row = (e_row + 1) * tems.ts_font.height + tems.ts_p_offset.y - 1;
1548 ma.t_row = t_row * tems.ts_font.height + tems.ts_p_offset.y;
1549
1550 /*
1551 * Check if we're in process of clearing OBP's columns area,
1552 * which only happens when term scrolls up a whole line.
1553 */
1554 if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
1555 e_col == tems.ts_c_dimension.width - 1) {
1556 /*
1557 * We need to clear OBP's columns area outside our kernel
1558 * console term. So that we set ma.e_col to entire row here.
1559 */
1560 ma.s_col = s_col * tems.ts_font.width;
1561 ma.e_col = tems.ts_p_dimension.width - 1;
1562
1563 ma.t_col = t_col * tems.ts_font.width;
1564 } else {
1565 ma.s_col = s_col * tems.ts_font.width + tems.ts_p_offset.x;
1566 ma.e_col = (e_col + 1) * tems.ts_font.width +
1567 tems.ts_p_offset.x - 1;
1568 ma.t_col = t_col * tems.ts_font.width + tems.ts_p_offset.x;
1569 }
1570
1571 tems_safe_copy(&ma, credp, called_from);
1572
1573 if (tem->tvs_first_line > 0 && t_row < s_row) {
1574 /* We have scrolled up (s_row - t_row) rows. */
1575 tem->tvs_first_line -= (s_row - t_row);
1576 if (tem->tvs_first_line <= 0) {
1577 /* All OBP rows have been cleared. */
1578 tem->tvs_first_line = 0;
1579 }
1580 }
1581
1582 }
1583
1584 void
1585 tem_safe_pix_bit2pix(struct tem_vt_state *tem, unsigned char c,
1586 unsigned char fg, unsigned char bg)
1587 {
1588 void (*fp)(struct tem_vt_state *, unsigned char,
1589 unsigned char, unsigned char);
1590
1591 switch (tems.ts_pdepth) {
1592 case 4:
1593 fp = bit_to_pix4;
1594 break;
1595 case 8:
1596 fp = bit_to_pix8;
1597 break;
1598 case 24:
1599 case 32:
1600 fp = bit_to_pix24;
1601 }
1602
1603 fp(tem, c, fg, bg);
1604 }
1605
1606
1607 /*
1608 * This function only clears count of columns in one row
1609 */
1610 void
1611 tem_safe_pix_cls(struct tem_vt_state *tem, int count,
1612 screen_pos_t row, screen_pos_t col, cred_t *credp,
1613 enum called_from called_from)
1614 {
1615 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1616 called_from == CALLED_FROM_STANDALONE);
1617
1618 tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
1619 col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
1620 }
1621
1622 /*
1623 * This function clears OBP output above our kernel console term area
1624 * because OBP's term may have a bigger terminal window than that of
1625 * our kernel console term. So we need to clear OBP output garbage outside
1626 * of our kernel console term at a proper time, which is when the first
1627 * row output of our kernel console term scrolls at the first screen line.
1628 *
1629 * _________________________________
1630 * | _____________________ | ---> OBP's bigger term window
1631 * | | | |
1632 * |___| | |
1633 * | | | | |
1634 * | | | | |
1635 * |_|_|___________________|_______|
1636 * | | | ---> first line
1637 * | |___________________|---> our kernel console term window
1638 * |
1639 * |---> columns area to be cleared
1640 *
1641 * This function only takes care of the output above our kernel console term,
1642 * and tem_prom_scroll_up takes care of columns area outside of our kernel
1643 * console term.
1644 */
1645 static void
1646 tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
1647 enum called_from called_from)
1648 {
1649 int nrows, ncols, width, height;
1650
1651 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1652 called_from == CALLED_FROM_STANDALONE);
1653
1654 width = tems.ts_font.width;
1655 height = tems.ts_font.height;
1656
1657 nrows = (tems.ts_p_offset.y + (height - 1))/ height;
1658 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1659
1660 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1661 B_FALSE, credp, called_from);
1662 }
1663
1664 /*
1665 * clear the whole screen for pixel mode, just clear the
1666 * physical screen.
1667 */
1668 void
1669 tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
1670 enum called_from called_from)
1671 {
1672 int nrows, ncols, width, height;
1673
1674 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1675 called_from == CALLED_FROM_STANDALONE);
1676
1677 width = tems.ts_font.width;
1678 height = tems.ts_font.height;
1679
1680 nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
1681 ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
1682
1683 tem_safe_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0,
1684 B_FALSE, credp, called_from);
1685
1686 /*
1687 * Since the whole screen is cleared, we don't need
1688 * to clear OBP output later.
1689 */
1690 if (tem->tvs_first_line > 0)
1691 tem->tvs_first_line = 0;
1692 }
1693
1694 /*
1695 * clear the whole screen, including the virtual screen buffer,
1696 * and reset the cursor to start point.
1697 */
1698 static void
1699 tem_safe_cls(struct tem_vt_state *tem,
1700 cred_t *credp, enum called_from called_from)
1701 {
1702 int row;
1703
1704 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1705 called_from == CALLED_FROM_STANDALONE);
1706
1707 if (tems.ts_display_mode == VIS_TEXT) {
1708 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1709 tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
1710 row, 0, credp, called_from);
1711 }
1712 tem->tvs_c_cursor.row = 0;
1713 tem->tvs_c_cursor.col = 0;
1714 tem_safe_align_cursor(tem);
1715 return;
1716 }
1717
1718 ASSERT(tems.ts_display_mode == VIS_PIXEL);
1719
1720 for (row = 0; row < tems.ts_c_dimension.height; row++) {
1721 tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
1722 }
1723 tem->tvs_c_cursor.row = 0;
1724 tem->tvs_c_cursor.col = 0;
1725 tem_safe_align_cursor(tem);
1726
1727 if (!tem->tvs_isactive)
1728 return;
1729
1730 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
1731 }
1732
1733 static void
1734 tem_safe_back_tab(struct tem_vt_state *tem,
1735 cred_t *credp, enum called_from called_from)
1736 {
1737 int i;
1738 screen_pos_t tabstop;
1739
1740 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1741 called_from == CALLED_FROM_STANDALONE);
1742
1743 tabstop = 0;
1744
1745 for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
1746 if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
1747 tabstop = tem->tvs_tabs[i];
1748 break;
1749 }
1750 }
1751
1752 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1753 tabstop, credp, called_from);
1754 }
1755
1756 static void
1757 tem_safe_tab(struct tem_vt_state *tem,
1758 cred_t *credp, enum called_from called_from)
1759 {
1760 int i;
1761 screen_pos_t tabstop;
1762
1763 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1764 called_from == CALLED_FROM_STANDALONE);
1765
1766 tabstop = tems.ts_c_dimension.width - 1;
1767
1768 for (i = 0; i < tem->tvs_ntabs; i++) {
1769 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1770 tabstop = tem->tvs_tabs[i];
1771 break;
1772 }
1773 }
1774
1775 tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
1776 tabstop, credp, called_from);
1777 }
1778
1779 static void
1780 tem_safe_set_tab(struct tem_vt_state *tem)
1781 {
1782 int i;
1783 int j;
1784
1785 if (tem->tvs_ntabs == TEM_MAXTAB)
1786 return;
1787 if (tem->tvs_ntabs == 0 ||
1788 tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
1789 tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
1790 return;
1791 }
1792 for (i = 0; i < tem->tvs_ntabs; i++) {
1793 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
1794 return;
1795 if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
1796 for (j = tem->tvs_ntabs - 1; j >= i; j--)
1797 tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
1798 tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
1799 tem->tvs_ntabs++;
1800 return;
1801 }
1802 }
1803 }
1804
1805 static void
1806 tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
1807 {
1808 int i;
1809 int j;
1810
1811 switch (action) {
1812 case 3: /* clear all tabs */
1813 tem->tvs_ntabs = 0;
1814 break;
1815 case 0: /* clr tab at cursor */
1816
1817 for (i = 0; i < tem->tvs_ntabs; i++) {
1818 if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
1819 tem->tvs_ntabs--;
1820 for (j = i; j < tem->tvs_ntabs; j++)
1821 tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
1822 return;
1823 }
1824 }
1825 break;
1826 }
1827 }
1828
1829 static void
1830 tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
1831 cred_t *credp, enum called_from called_from)
1832 {
1833 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1834 called_from == CALLED_FROM_STANDALONE);
1835
1836 /*
1837 * Sanity check and bounds enforcement. Out of bounds requests are
1838 * clipped to the screen boundaries. This seems to be what SPARC
1839 * does.
1840 */
1841 if (row < 0)
1842 row = 0;
1843 if (row >= tems.ts_c_dimension.height)
1844 row = tems.ts_c_dimension.height - 1;
1845 if (col < 0)
1846 col = 0;
1847 if (col >= tems.ts_c_dimension.width)
1848 col = tems.ts_c_dimension.width - 1;
1849
1850 tem_safe_send_data(tem, credp, called_from);
1851 tem->tvs_c_cursor.row = (screen_pos_t)row;
1852 tem->tvs_c_cursor.col = (screen_pos_t)col;
1853 tem_safe_align_cursor(tem);
1854 }
1855
1856 /* ARGSUSED */
1857 void
1858 tem_safe_reset_emulator(struct tem_vt_state *tem,
1859 cred_t *credp, enum called_from called_from,
1860 boolean_t init_color)
1861 {
1862 int j;
1863
1864 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1865 called_from == CALLED_FROM_STANDALONE);
1866
1867 tem->tvs_c_cursor.row = 0;
1868 tem->tvs_c_cursor.col = 0;
1869 tem->tvs_r_cursor.row = 0;
1870 tem->tvs_r_cursor.col = 0;
1871 tem->tvs_s_cursor.row = 0;
1872 tem->tvs_s_cursor.col = 0;
1873 tem->tvs_outindex = 0;
1874 tem->tvs_state = A_STATE_START;
1875 tem->tvs_gotparam = B_FALSE;
1876 tem->tvs_curparam = 0;
1877 tem->tvs_paramval = 0;
1878 tem->tvs_nscroll = 1;
1879
1880 if (init_color) {
1881 /* use initial settings */
1882 tem->tvs_fg_color = tems.ts_init_color.fg_color;
1883 tem->tvs_bg_color = tems.ts_init_color.bg_color;
1884 tem->tvs_flags = tems.ts_init_color.a_flags;
1885 }
1886
1887 /*
1888 * set up the initial tab stops
1889 */
1890 tem->tvs_ntabs = 0;
1891 for (j = 8; j < tems.ts_c_dimension.width; j += 8)
1892 tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
1893
1894 for (j = 0; j < TEM_MAXPARAMS; j++)
1895 tem->tvs_params[j] = 0;
1896 }
1897
1898 void
1899 tem_safe_reset_display(struct tem_vt_state *tem,
1900 cred_t *credp, enum called_from called_from,
1901 boolean_t clear_txt, boolean_t init_color)
1902 {
1903 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1904 called_from == CALLED_FROM_STANDALONE);
1905
1906 tem_safe_reset_emulator(tem, credp, called_from, init_color);
1907
1908 if (clear_txt) {
1909 if (tem->tvs_isactive)
1910 tem_safe_callback_cursor(tem,
1911 VIS_HIDE_CURSOR, credp, called_from);
1912
1913 tem_safe_cls(tem, credp, called_from);
1914
1915 if (tem->tvs_isactive)
1916 tem_safe_callback_cursor(tem,
1917 VIS_DISPLAY_CURSOR, credp, called_from);
1918 }
1919 }
1920
1921 static void
1922 tem_safe_shift(
1923 struct tem_vt_state *tem,
1924 int count,
1925 int direction,
1926 cred_t *credp,
1927 enum called_from called_from)
1928 {
1929 int rest_of_line;
1930
1931 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1932 called_from == CALLED_FROM_STANDALONE);
1933
1934 rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
1935 if (count > rest_of_line)
1936 count = rest_of_line;
1937
1938 if (count <= 0)
1939 return;
1940
1941 switch (direction) {
1942 case TEM_SHIFT_LEFT:
1943 if (count < rest_of_line) {
1944 tem_safe_copy_area(tem,
1945 tem->tvs_c_cursor.col + count,
1946 tem->tvs_c_cursor.row,
1947 tems.ts_c_dimension.width - 1,
1948 tem->tvs_c_cursor.row,
1949 tem->tvs_c_cursor.col,
1950 tem->tvs_c_cursor.row,
1951 credp, called_from);
1952 }
1953
1954 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1955 (tems.ts_c_dimension.width - count), credp,
1956 called_from);
1957 break;
1958 case TEM_SHIFT_RIGHT:
1959 if (count < rest_of_line) {
1960 tem_safe_copy_area(tem,
1961 tem->tvs_c_cursor.col,
1962 tem->tvs_c_cursor.row,
1963 tems.ts_c_dimension.width - count - 1,
1964 tem->tvs_c_cursor.row,
1965 tem->tvs_c_cursor.col + count,
1966 tem->tvs_c_cursor.row,
1967 credp, called_from);
1968 }
1969
1970 tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
1971 tem->tvs_c_cursor.col, credp, called_from);
1972 break;
1973 }
1974 }
1975
1976 void
1977 tem_safe_text_cursor(struct tem_vt_state *tem, short action,
1978 cred_t *credp, enum called_from called_from)
1979 {
1980 struct vis_conscursor ca;
1981
1982 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
1983 called_from == CALLED_FROM_STANDALONE);
1984
1985 ca.row = tem->tvs_c_cursor.row;
1986 ca.col = tem->tvs_c_cursor.col;
1987 ca.action = action;
1988
1989 tems_safe_cursor(&ca, credp, called_from);
1990
1991 if (action == VIS_GET_CURSOR) {
1992 tem->tvs_c_cursor.row = ca.row;
1993 tem->tvs_c_cursor.col = ca.col;
1994 }
1995 }
1996
1997 void
1998 tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
1999 cred_t *credp, enum called_from called_from)
2000 {
2001 struct vis_conscursor ca;
2002
2003 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2004 called_from == CALLED_FROM_STANDALONE);
2005
2006 ca.row = tem->tvs_c_cursor.row * tems.ts_font.height +
2007 tems.ts_p_offset.y;
2008 ca.col = tem->tvs_c_cursor.col * tems.ts_font.width +
2009 tems.ts_p_offset.x;
2010 ca.width = tems.ts_font.width;
2011 ca.height = tems.ts_font.height;
2012 if (tems.ts_pdepth == 8 || tems.ts_pdepth == 4) {
2013 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2014 ca.fg_color.mono = TEM_TEXT_WHITE;
2015 ca.bg_color.mono = TEM_TEXT_BLACK;
2016 } else {
2017 ca.fg_color.mono = TEM_TEXT_BLACK;
2018 ca.bg_color.mono = TEM_TEXT_WHITE;
2019 }
2020 } else if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32) {
2021 if (tem->tvs_flags & TEM_ATTR_REVERSE) {
2022 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2023 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2024 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2025
2026 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2027 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2028 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2029 } else {
2030 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED;
2031 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN;
2032 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE;
2033
2034 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED;
2035 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN;
2036 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE;
2037 }
2038 }
2039
2040 ca.action = action;
2041
2042 tems_safe_cursor(&ca, credp, called_from);
2043 }
2044
2045 static void
2046 bit_to_pix4(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2047 text_color_t bg_color)
2048 {
2049 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2050 font_bit_to_pix4(&tems.ts_font, dest, c, fg_color, bg_color);
2051 }
2052
2053 static void
2054 bit_to_pix8(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color,
2055 text_color_t bg_color)
2056 {
2057 uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
2058 font_bit_to_pix8(&tems.ts_font, dest, c, fg_color, bg_color);
2059 }
2060
2061 static void
2062 bit_to_pix24(struct tem_vt_state *tem, uchar_t c, text_color_t fg_color4,
2063 text_color_t bg_color4)
2064 {
2065 uint32_t fg_color32, bg_color32, *dest;
2066
2067 ASSERT(fg_color4 < 16 && bg_color4 < 16);
2068
2069 fg_color32 = PIX4TO32(fg_color4);
2070 bg_color32 = PIX4TO32(bg_color4);
2071
2072 dest = (uint32_t *)tem->tvs_pix_data;
2073 font_bit_to_pix24(&tems.ts_font, dest, c, fg_color32, bg_color32);
2074 }
2075
2076 static text_color_t
2077 ansi_bg_to_solaris(struct tem_vt_state *tem, int ansi)
2078 {
2079 if (tem->tvs_flags & TEM_ATTR_BRIGHT_BG)
2080 return (brt_xlate[ansi]);
2081 else
2082 return (dim_xlate[ansi]);
2083 }
2084
2085 static text_color_t
2086 ansi_fg_to_solaris(struct tem_vt_state *tem, int ansi)
2087 {
2088 if (tem->tvs_flags & TEM_ATTR_BRIGHT_FG ||
2089 tem->tvs_flags & TEM_ATTR_BOLD) {
2090 return (brt_xlate[ansi]);
2091 } else {
2092 return (dim_xlate[ansi]);
2093 }
2094 }
2095
2096 /*
2097 * flag: TEM_ATTR_SCREEN_REVERSE or TEM_ATTR_REVERSE
2098 */
2099 void
2100 tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
2101 text_color_t *bg, uint8_t flag)
2102 {
2103 if (tem->tvs_flags & flag) {
2104 *fg = ansi_fg_to_solaris(tem,
2105 tem->tvs_bg_color);
2106 *bg = ansi_bg_to_solaris(tem,
2107 tem->tvs_fg_color);
2108 } else {
2109 *fg = ansi_fg_to_solaris(tem,
2110 tem->tvs_fg_color);
2111 *bg = ansi_bg_to_solaris(tem,
2112 tem->tvs_bg_color);
2113 }
2114 }
2115
2116 /*
2117 * Clear a rectangle of screen for pixel mode.
2118 *
2119 * arguments:
2120 * row: start row#
2121 * nrows: the number of rows to clear
2122 * offset_y: the offset of height in pixels to begin clear
2123 * col: start col#
2124 * ncols: the number of cols to clear
2125 * offset_x: the offset of width in pixels to begin clear
2126 * scroll_up: whether this function is called during sroll up,
2127 * which is called only once.
2128 */
2129 void
2130 tem_safe_pix_cls_range(struct tem_vt_state *tem,
2131 screen_pos_t row, int nrows, int offset_y,
2132 screen_pos_t col, int ncols, int offset_x,
2133 boolean_t sroll_up, cred_t *credp,
2134 enum called_from called_from)
2135 {
2136 struct vis_consdisplay da;
2137 int i, j;
2138 int row_add = 0;
2139 text_color_t fg_color;
2140 text_color_t bg_color;
2141
2142 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2143 called_from == CALLED_FROM_STANDALONE);
2144
2145 if (sroll_up)
2146 row_add = tems.ts_c_dimension.height - 1;
2147
2148 da.width = tems.ts_font.width;
2149 da.height = tems.ts_font.height;
2150
2151 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2152
2153 tem_safe_callback_bit2pix(tem, ' ', fg_color, bg_color);
2154 da.data = (uchar_t *)tem->tvs_pix_data;
2155
2156 for (i = 0; i < nrows; i++, row++) {
2157 da.row = (row + row_add) * da.height + offset_y;
2158 da.col = col * da.width + offset_x;
2159 for (j = 0; j < ncols; j++) {
2160 tems_safe_display(&da, credp, called_from);
2161 da.col += da.width;
2162 }
2163 }
2164 }
2165
2166 /*
2167 * virtual screen operations
2168 */
2169 static void
2170 tem_safe_virtual_display(struct tem_vt_state *tem, unsigned char *string,
2171 int count, screen_pos_t row, screen_pos_t col,
2172 text_color_t fg_color, text_color_t bg_color)
2173 {
2174 int i, width;
2175 unsigned char *addr;
2176 text_color_t *pfgcolor;
2177 text_color_t *pbgcolor;
2178
2179 if (row < 0 || row >= tems.ts_c_dimension.height ||
2180 col < 0 || col >= tems.ts_c_dimension.width ||
2181 col + count > tems.ts_c_dimension.width)
2182 return;
2183
2184 width = tems.ts_c_dimension.width;
2185 addr = tem->tvs_screen_buf + (row * width + col);
2186 pfgcolor = tem->tvs_fg_buf + (row * width + col);
2187 pbgcolor = tem->tvs_bg_buf + (row * width + col);
2188 for (i = 0; i < count; i++) {
2189 *addr++ = string[i];
2190 *pfgcolor++ = fg_color;
2191 *pbgcolor++ = bg_color;
2192 }
2193 }
2194
2195 static void
2196 i_virtual_copy(unsigned char *base,
2197 screen_pos_t s_col, screen_pos_t s_row,
2198 screen_pos_t e_col, screen_pos_t e_row,
2199 screen_pos_t t_col, screen_pos_t t_row)
2200 {
2201 unsigned char *from;
2202 unsigned char *to;
2203 int cnt;
2204 screen_size_t chars_per_row;
2205 unsigned char *to_row_start;
2206 unsigned char *from_row_start;
2207 screen_size_t rows_to_move;
2208 int cols = tems.ts_c_dimension.width;
2209
2210 chars_per_row = e_col - s_col + 1;
2211 rows_to_move = e_row - s_row + 1;
2212
2213 to_row_start = base + ((t_row * cols) + t_col);
2214 from_row_start = base + ((s_row * cols) + s_col);
2215
2216 if (to_row_start < from_row_start) {
2217 while (rows_to_move-- > 0) {
2218 to = to_row_start;
2219 from = from_row_start;
2220 to_row_start += cols;
2221 from_row_start += cols;
2222 for (cnt = chars_per_row; cnt-- > 0; )
2223 *to++ = *from++;
2224 }
2225 } else {
2226 /*
2227 * Offset to the end of the region and copy backwards.
2228 */
2229 cnt = rows_to_move * cols + chars_per_row;
2230 to_row_start += cnt;
2231 from_row_start += cnt;
2232
2233 while (rows_to_move-- > 0) {
2234 to_row_start -= cols;
2235 from_row_start -= cols;
2236 to = to_row_start;
2237 from = from_row_start;
2238 for (cnt = chars_per_row; cnt-- > 0; )
2239 *--to = *--from;
2240 }
2241 }
2242 }
2243
2244 static void
2245 tem_safe_virtual_copy(struct tem_vt_state *tem,
2246 screen_pos_t s_col, screen_pos_t s_row,
2247 screen_pos_t e_col, screen_pos_t e_row,
2248 screen_pos_t t_col, screen_pos_t t_row)
2249 {
2250 screen_size_t chars_per_row;
2251 screen_size_t rows_to_move;
2252 int rows = tems.ts_c_dimension.height;
2253 int cols = tems.ts_c_dimension.width;
2254
2255 if (s_col < 0 || s_col >= cols ||
2256 s_row < 0 || s_row >= rows ||
2257 e_col < 0 || e_col >= cols ||
2258 e_row < 0 || e_row >= rows ||
2259 t_col < 0 || t_col >= cols ||
2260 t_row < 0 || t_row >= rows ||
2261 s_col > e_col ||
2262 s_row > e_row)
2263 return;
2264
2265 chars_per_row = e_col - s_col + 1;
2266 rows_to_move = e_row - s_row + 1;
2267
2268 /* More sanity checks. */
2269 if (t_row + rows_to_move > rows ||
2270 t_col + chars_per_row > cols)
2271 return;
2272
2273 i_virtual_copy(tem->tvs_screen_buf, s_col, s_row,
2274 e_col, e_row, t_col, t_row);
2275
2276 /* text_color_t is the same size as char */
2277 i_virtual_copy((unsigned char *)tem->tvs_fg_buf,
2278 s_col, s_row, e_col, e_row, t_col, t_row);
2279 i_virtual_copy((unsigned char *)tem->tvs_bg_buf,
2280 s_col, s_row, e_col, e_row, t_col, t_row);
2281
2282 }
2283
2284 static void
2285 tem_safe_virtual_cls(struct tem_vt_state *tem,
2286 int count, screen_pos_t row, screen_pos_t col)
2287 {
2288 text_color_t fg_color;
2289 text_color_t bg_color;
2290
2291 tem_safe_get_color(tem, &fg_color, &bg_color, TEM_ATTR_SCREEN_REVERSE);
2292 tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col,
2293 fg_color, bg_color);
2294 }
2295
2296 /*
2297 * only blank screen, not clear our screen buffer
2298 */
2299 void
2300 tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
2301 enum called_from called_from)
2302 {
2303 int row;
2304
2305 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2306 called_from == CALLED_FROM_STANDALONE);
2307
2308 if (tems.ts_display_mode == VIS_PIXEL) {
2309 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2310 return;
2311 }
2312
2313 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2314 tem_safe_callback_cls(tem,
2315 tems.ts_c_dimension.width,
2316 row, 0, credp, called_from);
2317 }
2318 }
2319
2320 /*
2321 * unblank screen with associated tem from its screen buffer
2322 */
2323 void
2324 tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
2325 enum called_from called_from)
2326 {
2327 text_color_t fg_color, fg_last;
2328 text_color_t bg_color, bg_last;
2329 size_t tc_size = sizeof (text_color_t);
2330 int row, col, count, col_start;
2331 int width;
2332 unsigned char *buf;
2333
2334 ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
2335 called_from == CALLED_FROM_STANDALONE);
2336
2337 if (tems.ts_display_mode == VIS_PIXEL)
2338 tem_safe_pix_clear_entire_screen(tem, credp, called_from);
2339
2340 tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
2341
2342 width = tems.ts_c_dimension.width;
2343
2344 /*
2345 * Display data in tvs_screen_buf to the actual framebuffer in a
2346 * row by row way.
2347 * When dealing with one row, output data with the same foreground
2348 * and background color all together.
2349 */
2350 for (row = 0; row < tems.ts_c_dimension.height; row++) {
2351 buf = tem->tvs_screen_buf + (row * width);
2352 count = col_start = 0;
2353 for (col = 0; col < width; col++) {
2354 fg_color =
2355 tem->tvs_fg_buf[(row * width + col) * tc_size];
2356 bg_color =
2357 tem->tvs_bg_buf[(row * width + col) * tc_size];
2358 if (col == 0) {
2359 fg_last = fg_color;
2360 bg_last = bg_color;
2361 }
2362
2363 if ((fg_color != fg_last) || (bg_color != bg_last)) {
2364 /*
2365 * Call the primitive to render this data.
2366 */
2367 tem_safe_callback_display(tem,
2368 buf, count, row, col_start,
2369 fg_last, bg_last, credp, called_from);
2370 buf += count;
2371 count = 1;
2372 col_start = col;
2373 fg_last = fg_color;
2374 bg_last = bg_color;
2375 } else {
2376 count++;
2377 }
2378 }
2379
2380 if (col_start == (width - 1))
2381 continue;
2382
2383 /*
2384 * Call the primitive to render this data.
2385 */
2386 tem_safe_callback_display(tem,
2387 buf, count, row, col_start,
2388 fg_last, bg_last, credp, called_from);
2389 }
2390
2391 tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
2392 }