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