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