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