11253Slq150181 /* 21253Slq150181 * CDDL HEADER START 31253Slq150181 * 41253Slq150181 * The contents of this file are subject to the terms of the 51253Slq150181 * Common Development and Distribution License (the "License"). 61253Slq150181 * You may not use this file except in compliance with the License. 71253Slq150181 * 81253Slq150181 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91253Slq150181 * or http://www.opensolaris.org/os/licensing. 101253Slq150181 * See the License for the specific language governing permissions 111253Slq150181 * and limitations under the License. 121253Slq150181 * 131253Slq150181 * When distributing Covered Code, include this CDDL HEADER in each 141253Slq150181 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151253Slq150181 * If applicable, add the following below this CDDL HEADER, with the 161253Slq150181 * fields enclosed by brackets "[]" replaced with your own identifying 171253Slq150181 * information: Portions Copyright [yyyy] [name of copyright owner] 181253Slq150181 * 191253Slq150181 * CDDL HEADER END 201253Slq150181 */ 211253Slq150181 221253Slq150181 /* 23*3994Slq150181 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 241253Slq150181 * Use is subject to license terms. 251253Slq150181 */ 261253Slq150181 271253Slq150181 #pragma ident "%Z%%M% %I% %E% SMI" 281253Slq150181 291253Slq150181 /* 301253Slq150181 * Polled I/O safe ANSI terminal emulator module; 311253Slq150181 * Supporting TERM types 'sun' and 'sun-color, parsing 321253Slq150181 * ANSI x3.64 escape sequences, and the like. (See wscons(7d) 331253Slq150181 * for more information). 341253Slq150181 * 351253Slq150181 * IMPORTANT: 361253Slq150181 * 371253Slq150181 * The functions in this file *must* be able to function in 381253Slq150181 * standalone mode, ie. on a quiesced system. In that state, 391253Slq150181 * access is single threaded, only one CPU is running. 401253Slq150181 * System services are NOT available. 411253Slq150181 * 421253Slq150181 * The following restrictions pertain to every function 431253Slq150181 * in this file: 441253Slq150181 * 451253Slq150181 * - CANNOT use the DDI or LDI interfaces 461253Slq150181 * - CANNOT call system services 471253Slq150181 * - CANNOT use mutexes 481253Slq150181 * - CANNOT wait for interrupts 491253Slq150181 * - CANNOT allocate memory 501253Slq150181 * 511253Slq150181 */ 521253Slq150181 531253Slq150181 #include <sys/types.h> 541253Slq150181 #include <sys/ascii.h> 551253Slq150181 #include <sys/visual_io.h> 561253Slq150181 #include <sys/font.h> 571253Slq150181 #include <sys/tem.h> 581253Slq150181 #include <sys/tem_impl.h> 591253Slq150181 #include <sys/ksynch.h> 601253Slq150181 #include <sys/sysmacros.h> 611253Slq150181 #include <sys/mutex.h> 621253Slq150181 631253Slq150181 static void tem_display(struct tem *, 641253Slq150181 struct vis_consdisplay *, 651253Slq150181 cred_t *, enum called_from); 661253Slq150181 static void tem_cursor(struct tem *, 671253Slq150181 struct vis_conscursor *, 681253Slq150181 cred_t *, enum called_from); 691253Slq150181 static void tem_control(struct tem *, uchar_t, 701253Slq150181 cred_t *, enum called_from); 711253Slq150181 static void tem_setparam(struct tem *, int, int); 721253Slq150181 static void tem_selgraph(struct tem *); 731253Slq150181 static void tem_chkparam(struct tem *, uchar_t, 741253Slq150181 cred_t *, enum called_from); 751253Slq150181 static void tem_getparams(struct tem *, uchar_t, 761253Slq150181 cred_t *, enum called_from); 771253Slq150181 static void tem_outch(struct tem *, uchar_t, 781253Slq150181 cred_t *, enum called_from); 791253Slq150181 static void tem_parse(struct tem *, uchar_t, 801253Slq150181 cred_t *, enum called_from); 811253Slq150181 821253Slq150181 static void tem_new_line(struct tem *, 831253Slq150181 cred_t *, enum called_from); 841253Slq150181 static void tem_cr(struct tem *); 851253Slq150181 static void tem_lf(struct tem *, 861253Slq150181 cred_t *, enum called_from); 871253Slq150181 static void tem_send_data(struct tem *, cred_t *, 881253Slq150181 enum called_from); 891253Slq150181 static void tem_cls(struct tem *, 901253Slq150181 cred_t *, enum called_from); 911253Slq150181 static void tem_tab(struct tem *, 921253Slq150181 cred_t *, enum called_from); 931253Slq150181 static void tem_back_tab(struct tem *, 941253Slq150181 cred_t *, enum called_from); 951253Slq150181 static void tem_clear_tabs(struct tem *, int); 961253Slq150181 static void tem_set_tab(struct tem *); 971253Slq150181 static void tem_mv_cursor(struct tem *, int, int, 981253Slq150181 cred_t *, enum called_from); 991253Slq150181 static void tem_shift(struct tem *, int, int, 1001253Slq150181 cred_t *, enum called_from); 1011253Slq150181 static void tem_scroll(struct tem *, int, int, 1021253Slq150181 int, int, cred_t *, enum called_from); 1031253Slq150181 static void tem_clear_chars(struct tem *tem, 1041253Slq150181 int count, screen_pos_t row, screen_pos_t col, 1051253Slq150181 cred_t *credp, enum called_from called_from); 1061253Slq150181 static void tem_copy_area(struct tem *tem, 1071253Slq150181 screen_pos_t s_col, screen_pos_t s_row, 1081253Slq150181 screen_pos_t e_col, screen_pos_t e_row, 1091253Slq150181 screen_pos_t t_col, screen_pos_t t_row, 1101253Slq150181 cred_t *credp, enum called_from called_from); 1111253Slq150181 static void tem_image_display(struct tem *, uchar_t *, 1121253Slq150181 int, int, screen_pos_t, screen_pos_t, 1131253Slq150181 cred_t *, enum called_from); 1141253Slq150181 static void tem_bell(struct tem *tem, 1151253Slq150181 enum called_from called_from); 1161253Slq150181 static void tem_get_color(struct tem *tem, 1171253Slq150181 text_color_t *fg, text_color_t *bg); 1181253Slq150181 static void tem_pix_clear_prom_output(struct tem *tem, 1191253Slq150181 cred_t *credp, enum called_from called_from); 1201253Slq150181 1211253Slq150181 /* BEGIN CSTYLED */ 1221253Slq150181 /* Bk Rd Gr Br Bl Mg Cy Wh */ 1231253Slq150181 static text_color_t fg_dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 }; 1241253Slq150181 static text_color_t fg_brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 }; 1251253Slq150181 static text_color_t bg_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 0 }; 1261253Slq150181 /* END CSTYLED */ 1271253Slq150181 1281253Slq150181 1291253Slq150181 text_cmap_t cmap4_to_24 = { 1301253Slq150181 /* BEGIN CSTYLED */ 1311253Slq150181 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1321253Slq150181 Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ 1331253Slq150181 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff, 1341253Slq150181 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff, 1351253Slq150181 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00 1361253Slq150181 /* END CSTYLED */ 1371253Slq150181 }; 1381253Slq150181 1391253Slq150181 #define PIX4TO32(pix4) (pixel32_t)( \ 1401253Slq150181 cmap4_to_24.red[pix4] << 16 | \ 1411253Slq150181 cmap4_to_24.green[pix4] << 8 | \ 1421253Slq150181 cmap4_to_24.blue[pix4]) 1431253Slq150181 1441253Slq150181 /* 1451253Slq150181 * Fonts are statically linked with this module. At some point an 1461253Slq150181 * RFE might be desireable to allow dynamic font loading. The 1471253Slq150181 * original intention to facilitate dynamic fonts can be seen 1481253Slq150181 * by examining the data structures and set_font(). As much of 1491253Slq150181 * the original code is retained but modified to be suited to 1501253Slq150181 * traversing a list of static fonts. 1511253Slq150181 */ 1521253Slq150181 extern struct fontlist fonts[]; 1531253Slq150181 1541253Slq150181 #define DEFAULT_FONT_DATA font_data_12x22 1551253Slq150181 1561253Slq150181 extern bitmap_data_t font_data_12x22; 1571253Slq150181 extern bitmap_data_t font_data_7x14; 1581253Slq150181 extern bitmap_data_t font_data_6x10; 1591253Slq150181 /* 1601253Slq150181 * Must be sorted by font size in descending order 1611253Slq150181 */ 1621253Slq150181 struct fontlist fonts[] = { 1631253Slq150181 { &font_data_12x22, NULL }, 1641253Slq150181 { &font_data_7x14, NULL }, 1651253Slq150181 { &font_data_6x10, NULL }, 1661253Slq150181 { NULL, NULL } 1671253Slq150181 }; 1681253Slq150181 1691253Slq150181 #define INVERSE(ch) (ch ^ 0xff) 1701253Slq150181 1711253Slq150181 #define BIT_TO_PIX(tem, c, fg, bg) { \ 1721253Slq150181 ASSERT((tem)->state->in_fp.f_bit2pix != NULL); \ 1731253Slq150181 (void) (*(tem)->state->in_fp.f_bit2pix)((tem), (c), (fg), (bg));\ 1741253Slq150181 } 1751253Slq150181 1761253Slq150181 void 1771253Slq150181 tem_check_first_time( 1781253Slq150181 struct tem *tem, 1791253Slq150181 cred_t *credp, 1801253Slq150181 enum called_from called_from) 1811253Slq150181 { 1821253Slq150181 static int first_time = 1; 1831253Slq150181 1841253Slq150181 /* 1851253Slq150181 * Realign the console cursor. We did this in tem_init(). 1861253Slq150181 * However, drivers in the console stream may emit additional 1871253Slq150181 * messages before we are ready. This causes text overwrite 1881253Slq150181 * on the screen. This is a workaround. 1891253Slq150181 */ 1901253Slq150181 if (first_time && tem->state->display_mode == VIS_TEXT) { 1911253Slq150181 tem_text_cursor(tem, VIS_GET_CURSOR, credp, called_from); 1921253Slq150181 tem_align_cursor(tem); 1931253Slq150181 } 1941253Slq150181 first_time = 0; 1951253Slq150181 1961253Slq150181 } 1971253Slq150181 1981253Slq150181 /* 1991253Slq150181 * This entry point handles output requests from restricted contexts like 2001253Slq150181 * kmdb, where services like mutexes are not available. This function 2011253Slq150181 * is entered when OBP or when a kernel debugger (such as kmdb) 2021253Slq150181 * are generating console output. In those cases, power management 2031253Slq150181 * concerns are handled by the abort sequence initiation (ie. when 2041253Slq150181 * the user hits L1+A or the equivalent to enter OBP or the debugger.). 2051253Slq150181 * It is also entered when the kernel is panicing. 2061253Slq150181 */ 2071253Slq150181 void 2081253Slq150181 tem_polled_write( 2091253Slq150181 struct tem *tem, 2101253Slq150181 uchar_t *buf, 2111253Slq150181 int len) 2121253Slq150181 { 2131253Slq150181 2141253Slq150181 ASSERT(tem->hdl != NULL); 2151253Slq150181 2161253Slq150181 tem_check_first_time(tem, kcred, CALLED_FROM_STANDALONE); 2171253Slq150181 tem_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE); 2181253Slq150181 } 2191253Slq150181 2201253Slq150181 2211253Slq150181 /* 2221253Slq150181 * This is the main entry point into the terminal emulator. 2231253Slq150181 * 2241253Slq150181 * For each data message coming downstream, ANSI assumes that it is composed 2251253Slq150181 * of ASCII characters, which are treated as a byte-stream input to the 2261253Slq150181 * parsing state machine. All data is parsed immediately -- there is 2271253Slq150181 * no enqueing. 2281253Slq150181 */ 2291253Slq150181 void 2301253Slq150181 tem_terminal_emulate( 2311253Slq150181 struct tem *tem, 2321253Slq150181 uchar_t *buf, 2331253Slq150181 int len, 2341253Slq150181 cred_t *credp, 2351253Slq150181 enum called_from called_from) 2361253Slq150181 { 2371253Slq150181 struct tem_state *tems = tem->state; 2381253Slq150181 2391253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 2401253Slq150181 MUTEX_HELD(&tem->lock)); 2411253Slq150181 2421253Slq150181 (*tems->in_fp.f_cursor) 2431253Slq150181 (tem, VIS_HIDE_CURSOR, credp, called_from); 2441253Slq150181 2451253Slq150181 for (; len > 0; len--, buf++) { 2461253Slq150181 tem_parse(tem, *buf, credp, called_from); 2471253Slq150181 } 2481253Slq150181 2491253Slq150181 /* 2501253Slq150181 * Send the data we just got to the framebuffer. 2511253Slq150181 */ 2521253Slq150181 tem_send_data(tem, credp, called_from); 2531253Slq150181 2541253Slq150181 (*tems->in_fp.f_cursor) 2551253Slq150181 (tem, VIS_DISPLAY_CURSOR, credp, called_from); 2561253Slq150181 } 2571253Slq150181 2581253Slq150181 /* 2591253Slq150181 * Display an rectangular image on the frame buffer using the 2601253Slq150181 * mechanism appropriate for the system state being called 2611253Slq150181 * from quiesced or normal (ie. use polled I/O vs. layered ioctls) 2621253Slq150181 */ 2631253Slq150181 static void 2641253Slq150181 tem_display( 2651253Slq150181 struct tem *tem, 2661253Slq150181 struct vis_consdisplay *pda, 2671253Slq150181 cred_t *credp, 2681253Slq150181 enum called_from called_from) 2691253Slq150181 { 2701253Slq150181 if (called_from == CALLED_FROM_STANDALONE) 2711253Slq150181 tem->fb_polledio->display(tem->fb_polledio->arg, pda); 2721253Slq150181 else 2731253Slq150181 tem_display_layered(tem, pda, credp); 2741253Slq150181 } 2751253Slq150181 2761253Slq150181 /* 2771253Slq150181 * Copy a rectangle from one location to another on the frame buffer 2781253Slq150181 * using the mechanism appropriate for the system state being called 2791253Slq150181 * from, quiesced or normal (ie. use polled I/O vs. layered ioctls) 2801253Slq150181 */ 2811253Slq150181 void 2821253Slq150181 tem_copy( 2831253Slq150181 struct tem *tem, 2841253Slq150181 struct vis_conscopy *pca, 2851253Slq150181 cred_t *credp, 2861253Slq150181 enum called_from called_from) 2871253Slq150181 { 2881253Slq150181 if (called_from == CALLED_FROM_STANDALONE) 2891253Slq150181 tem->fb_polledio->copy(tem->fb_polledio->arg, pca); 2901253Slq150181 else 2911253Slq150181 tem_copy_layered(tem, pca, credp); 2921253Slq150181 } 2931253Slq150181 2941253Slq150181 /* 2951253Slq150181 * Display or hide a rectangular block text cursor of a specificsize 2961253Slq150181 * at a specific location on frame buffer* using the mechanism 2971253Slq150181 * appropriate for the system state being called from, quisced or 2981253Slq150181 * normal (ie. use polled I/O vs. layered ioctls). 2991253Slq150181 */ 3001253Slq150181 static void 3011253Slq150181 tem_cursor( 3021253Slq150181 struct tem *tem, 3031253Slq150181 struct vis_conscursor *pca, 3041253Slq150181 cred_t *credp, 3051253Slq150181 enum called_from called_from) 3061253Slq150181 { 3071253Slq150181 if (called_from == CALLED_FROM_STANDALONE) 3081253Slq150181 tem->fb_polledio->cursor(tem->fb_polledio->arg, pca); 3091253Slq150181 else 3101253Slq150181 tem_cursor_layered(tem, pca, credp); 3111253Slq150181 } 3121253Slq150181 3131253Slq150181 /* 3141253Slq150181 * send the appropriate control message or set state based on the 3151253Slq150181 * value of the control character ch 3161253Slq150181 */ 3171253Slq150181 3181253Slq150181 static void 3191253Slq150181 tem_control( 3201253Slq150181 struct tem *tem, 3211253Slq150181 uchar_t ch, 3221253Slq150181 cred_t *credp, 3231253Slq150181 enum called_from called_from) 3241253Slq150181 { 3251253Slq150181 struct tem_state *tems = tem->state; 3261253Slq150181 3271253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 3281253Slq150181 MUTEX_HELD(&tem->lock)); 3291253Slq150181 3301253Slq150181 tems->a_state = A_STATE_START; 3311253Slq150181 switch (ch) { 3321253Slq150181 case A_BEL: 3331253Slq150181 tem_bell(tem, called_from); 3341253Slq150181 break; 3351253Slq150181 3361253Slq150181 case A_BS: 3371253Slq150181 tem_mv_cursor(tem, 3381253Slq150181 tems->a_c_cursor.row, 3391253Slq150181 tems->a_c_cursor.col - 1, 3401253Slq150181 credp, called_from); 3411253Slq150181 break; 3421253Slq150181 3431253Slq150181 case A_HT: 3441253Slq150181 tem_tab(tem, credp, called_from); 3451253Slq150181 break; 3461253Slq150181 3471253Slq150181 case A_NL: 3481253Slq150181 /* 3491253Slq150181 * tem_send_data(tem, credp, called_from); 3501253Slq150181 * tem_new_line(tem, credp, called_from); 3511253Slq150181 * break; 3521253Slq150181 */ 3531253Slq150181 3541253Slq150181 case A_VT: 3551253Slq150181 tem_send_data(tem, credp, called_from); 3561253Slq150181 tem_lf(tem, credp, called_from); 3571253Slq150181 break; 3581253Slq150181 3591253Slq150181 case A_FF: 3601253Slq150181 tem_send_data(tem, credp, called_from); 3611253Slq150181 tem_cls(tem, credp, called_from); 3621253Slq150181 break; 3631253Slq150181 3641253Slq150181 case A_CR: 3651253Slq150181 tem_send_data(tem, credp, called_from); 3661253Slq150181 tem_cr(tem); 3671253Slq150181 break; 3681253Slq150181 3691253Slq150181 case A_ESC: 3701253Slq150181 tems->a_state = A_STATE_ESC; 3711253Slq150181 break; 3721253Slq150181 3731253Slq150181 case A_CSI: 3741253Slq150181 { 3751253Slq150181 int i; 3761253Slq150181 tems->a_curparam = 0; 3771253Slq150181 tems->a_paramval = 0; 3781253Slq150181 tems->a_gotparam = B_FALSE; 3791253Slq150181 /* clear the parameters */ 3801253Slq150181 for (i = 0; i < TEM_MAXPARAMS; i++) 3811253Slq150181 tems->a_params[i] = -1; 3821253Slq150181 tems->a_state = A_STATE_CSI; 3831253Slq150181 } 3841253Slq150181 break; 3851253Slq150181 3861253Slq150181 case A_GS: 3871253Slq150181 tem_back_tab(tem, credp, called_from); 3881253Slq150181 break; 3891253Slq150181 3901253Slq150181 default: 3911253Slq150181 break; 3921253Slq150181 } 3931253Slq150181 } 3941253Slq150181 3951253Slq150181 3961253Slq150181 /* 3971253Slq150181 * if parameters [0..count - 1] are not set, set them to the value 3981253Slq150181 * of newparam. 3991253Slq150181 */ 4001253Slq150181 4011253Slq150181 static void 4021253Slq150181 tem_setparam(struct tem *tem, int count, int newparam) 4031253Slq150181 { 4041253Slq150181 int i; 4051253Slq150181 4061253Slq150181 for (i = 0; i < count; i++) { 4071253Slq150181 if (tem->state->a_params[i] == -1) 4081253Slq150181 tem->state->a_params[i] = newparam; 4091253Slq150181 } 4101253Slq150181 } 4111253Slq150181 4121253Slq150181 4131253Slq150181 /* 4141253Slq150181 * select graphics mode based on the param vals stored in a_params 4151253Slq150181 */ 4161253Slq150181 static void 4171253Slq150181 tem_selgraph(struct tem *tem) 4181253Slq150181 { 4191253Slq150181 struct tem_state *tems = tem->state; 4201253Slq150181 int curparam; 4211253Slq150181 int count = 0; 4221253Slq150181 int param; 4231253Slq150181 4241253Slq150181 curparam = tems->a_curparam; 4251253Slq150181 do { 4261253Slq150181 param = tems->a_params[count]; 4271253Slq150181 4281253Slq150181 switch (param) { 4291253Slq150181 case -1: 4301253Slq150181 case 0: 4311253Slq150181 if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) { 4321253Slq150181 tems->a_flags |= TEM_ATTR_REVERSE; 4331253Slq150181 } else { 4341253Slq150181 tems->a_flags &= ~TEM_ATTR_REVERSE; 4351253Slq150181 } 436*3994Slq150181 tems->a_flags = tem->init_color.a_flags; 437*3994Slq150181 tems->fg_color = tem->init_color.fg_color; 438*3994Slq150181 tems->bg_color = tem->init_color.bg_color; 4391253Slq150181 break; 4401253Slq150181 4411253Slq150181 case 1: /* Bold Intense */ 4421253Slq150181 tems->a_flags |= TEM_ATTR_BOLD; 4431253Slq150181 break; 4441253Slq150181 445*3994Slq150181 case 2: /* Faint Intense */ 446*3994Slq150181 tems->a_flags &= ~TEM_ATTR_BOLD; 447*3994Slq150181 break; 448*3994Slq150181 4491253Slq150181 case 5: /* Blink */ 4501253Slq150181 tems->a_flags |= TEM_ATTR_BLINK; 4511253Slq150181 break; 4521253Slq150181 4531253Slq150181 case 7: /* Reverse video */ 4541253Slq150181 if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) { 4551253Slq150181 tems->a_flags &= ~TEM_ATTR_REVERSE; 4561253Slq150181 } else { 4571253Slq150181 tems->a_flags |= TEM_ATTR_REVERSE; 4581253Slq150181 } 4591253Slq150181 break; 4601253Slq150181 4611253Slq150181 case 30: /* black (grey) foreground */ 4621253Slq150181 case 31: /* red (light red) foreground */ 4631253Slq150181 case 32: /* green (light green) foreground */ 4641253Slq150181 case 33: /* brown (yellow) foreground */ 4651253Slq150181 case 34: /* blue (light blue) foreground */ 4661253Slq150181 case 35: /* magenta (light magenta) foreground */ 4671253Slq150181 case 36: /* cyan (light cyan) foreground */ 4681253Slq150181 case 37: /* white (bright white) foreground */ 4691253Slq150181 tems->fg_color = param - 30; 4701253Slq150181 break; 4711253Slq150181 4721253Slq150181 case 40: /* black (grey) background */ 4731253Slq150181 case 41: /* red (light red) background */ 4741253Slq150181 case 42: /* green (light green) background */ 4751253Slq150181 case 43: /* brown (yellow) background */ 4761253Slq150181 case 44: /* blue (light blue) background */ 4771253Slq150181 case 45: /* magenta (light magenta) background */ 4781253Slq150181 case 46: /* cyan (light cyan) background */ 4791253Slq150181 case 47: /* white (bright white) background */ 4801253Slq150181 tems->bg_color = param - 40; 4811253Slq150181 break; 4821253Slq150181 4831253Slq150181 default: 4841253Slq150181 break; 4851253Slq150181 } 4861253Slq150181 count++; 4871253Slq150181 curparam--; 4881253Slq150181 4891253Slq150181 } while (curparam > 0); 4901253Slq150181 4911253Slq150181 4921253Slq150181 tems->a_state = A_STATE_START; 4931253Slq150181 } 4941253Slq150181 4951253Slq150181 /* 4961253Slq150181 * perform the appropriate action for the escape sequence 4971253Slq150181 * 4981253Slq150181 * General rule: This code does not validate the arguments passed. 4991253Slq150181 * It assumes that the next lower level will do so. 5001253Slq150181 */ 5011253Slq150181 static void 5021253Slq150181 tem_chkparam( 5031253Slq150181 struct tem *tem, 5041253Slq150181 uchar_t ch, 5051253Slq150181 cred_t *credp, 5061253Slq150181 enum called_from called_from) 5071253Slq150181 { 5081253Slq150181 struct tem_state *tems = tem->state; 5091253Slq150181 int i; 5101253Slq150181 int row; 5111253Slq150181 int col; 5121253Slq150181 5131253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 5141253Slq150181 MUTEX_HELD(&tem->lock)); 5151253Slq150181 5161253Slq150181 row = tems->a_c_cursor.row; 5171253Slq150181 col = tems->a_c_cursor.col; 5181253Slq150181 5191253Slq150181 switch (ch) { 5201253Slq150181 5211253Slq150181 case 'm': /* select terminal graphics mode */ 5221253Slq150181 tem_send_data(tem, credp, called_from); 5231253Slq150181 tem_selgraph(tem); 5241253Slq150181 break; 5251253Slq150181 5261253Slq150181 case '@': /* insert char */ 5271253Slq150181 tem_setparam(tem, 1, 1); 5281253Slq150181 tem_shift(tem, tems->a_params[0], TEM_SHIFT_RIGHT, 5291253Slq150181 credp, called_from); 5301253Slq150181 break; 5311253Slq150181 5321253Slq150181 case 'A': /* cursor up */ 5331253Slq150181 tem_setparam(tem, 1, 1); 5341253Slq150181 tem_mv_cursor(tem, row - tems->a_params[0], col, 5351253Slq150181 credp, called_from); 5361253Slq150181 break; 5371253Slq150181 5381253Slq150181 case 'd': /* VPA - vertical position absolute */ 5391253Slq150181 tem_setparam(tem, 1, 1); 5401253Slq150181 tem_mv_cursor(tem, tems->a_params[0] - 1, col, 5411253Slq150181 credp, called_from); 5421253Slq150181 break; 5431253Slq150181 5441253Slq150181 case 'e': /* VPR - vertical position relative */ 5451253Slq150181 case 'B': /* cursor down */ 5461253Slq150181 tem_setparam(tem, 1, 1); 5471253Slq150181 tem_mv_cursor(tem, row + tems->a_params[0], col, 5481253Slq150181 credp, called_from); 5491253Slq150181 break; 5501253Slq150181 5511253Slq150181 case 'a': /* HPR - horizontal position relative */ 5521253Slq150181 case 'C': /* cursor right */ 5531253Slq150181 tem_setparam(tem, 1, 1); 5541253Slq150181 tem_mv_cursor(tem, row, col + tems->a_params[0], 5551253Slq150181 credp, called_from); 5561253Slq150181 break; 5571253Slq150181 5581253Slq150181 case '`': /* HPA - horizontal position absolute */ 5591253Slq150181 tem_setparam(tem, 1, 1); 5601253Slq150181 tem_mv_cursor(tem, row, tems->a_params[0] - 1, 5611253Slq150181 credp, called_from); 5621253Slq150181 break; 5631253Slq150181 5641253Slq150181 case 'D': /* cursor left */ 5651253Slq150181 tem_setparam(tem, 1, 1); 5661253Slq150181 tem_mv_cursor(tem, row, col - tems->a_params[0], 5671253Slq150181 credp, called_from); 5681253Slq150181 break; 5691253Slq150181 5701253Slq150181 case 'E': /* CNL cursor next line */ 5711253Slq150181 tem_setparam(tem, 1, 1); 5721253Slq150181 tem_mv_cursor(tem, row + tems->a_params[0], 0, 5731253Slq150181 credp, called_from); 5741253Slq150181 break; 5751253Slq150181 5761253Slq150181 case 'F': /* CPL cursor previous line */ 5771253Slq150181 tem_setparam(tem, 1, 1); 5781253Slq150181 tem_mv_cursor(tem, row - tems->a_params[0], 0, 5791253Slq150181 credp, called_from); 5801253Slq150181 break; 5811253Slq150181 5821253Slq150181 case 'G': /* cursor horizontal position */ 5831253Slq150181 tem_setparam(tem, 1, 1); 5841253Slq150181 tem_mv_cursor(tem, row, tems->a_params[0] - 1, 5851253Slq150181 credp, called_from); 5861253Slq150181 break; 5871253Slq150181 5881253Slq150181 case 'g': /* clear tabs */ 5891253Slq150181 tem_setparam(tem, 1, 0); 5901253Slq150181 tem_clear_tabs(tem, tems->a_params[0]); 5911253Slq150181 break; 5921253Slq150181 5931253Slq150181 case 'f': /* HVP Horizontal and Vertical Position */ 5941253Slq150181 case 'H': /* CUP position cursor */ 5951253Slq150181 tem_setparam(tem, 2, 1); 5961253Slq150181 tem_mv_cursor(tem, 5971253Slq150181 tems->a_params[0] - 1, 5981253Slq150181 tems->a_params[1] - 1, 5991253Slq150181 credp, called_from); 6001253Slq150181 break; 6011253Slq150181 6021253Slq150181 case 'I': /* CHT - Cursor Horizontal Tab */ 6031253Slq150181 /* Not implemented */ 6041253Slq150181 break; 6051253Slq150181 6061253Slq150181 case 'J': /* ED - Erase in Display */ 6071253Slq150181 tem_send_data(tem, credp, called_from); 6081253Slq150181 tem_setparam(tem, 1, 0); 6091253Slq150181 switch (tems->a_params[0]) { 6101253Slq150181 case 0: 6111253Slq150181 /* erase cursor to end of screen */ 6121253Slq150181 /* FIRST erase cursor to end of line */ 6131253Slq150181 tem_clear_chars(tem, 6141253Slq150181 tems->a_c_dimension.width - 6151253Slq150181 tems->a_c_cursor.col, 6161253Slq150181 tems->a_c_cursor.row, 6171253Slq150181 tems->a_c_cursor.col, credp, called_from); 6181253Slq150181 6191253Slq150181 /* THEN erase lines below the cursor */ 6201253Slq150181 for (row = tems->a_c_cursor.row + 1; 6211253Slq150181 row < tems->a_c_dimension.height; 6221253Slq150181 row++) { 6231253Slq150181 tem_clear_chars(tem, 6241253Slq150181 tems->a_c_dimension.width, 6251253Slq150181 row, 0, credp, called_from); 6261253Slq150181 } 6271253Slq150181 break; 6281253Slq150181 6291253Slq150181 case 1: 6301253Slq150181 /* erase beginning of screen to cursor */ 6311253Slq150181 /* FIRST erase lines above the cursor */ 6321253Slq150181 for (row = 0; 6331253Slq150181 row < tems->a_c_cursor.row; 6341253Slq150181 row++) { 6351253Slq150181 tem_clear_chars(tem, 6361253Slq150181 tems->a_c_dimension.width, 6371253Slq150181 row, 0, credp, called_from); 6381253Slq150181 } 6391253Slq150181 /* THEN erase beginning of line to cursor */ 6401253Slq150181 tem_clear_chars(tem, 6411253Slq150181 tems->a_c_cursor.col + 1, 6421253Slq150181 tems->a_c_cursor.row, 6431253Slq150181 0, credp, called_from); 6441253Slq150181 break; 6451253Slq150181 6461253Slq150181 case 2: 6471253Slq150181 /* erase whole screen */ 6481253Slq150181 for (row = 0; 6491253Slq150181 row < tems->a_c_dimension.height; 6501253Slq150181 row++) { 6511253Slq150181 tem_clear_chars(tem, 6521253Slq150181 tems->a_c_dimension.width, 6531253Slq150181 row, 0, credp, called_from); 6541253Slq150181 } 6551253Slq150181 break; 6561253Slq150181 } 6571253Slq150181 break; 6581253Slq150181 6591253Slq150181 case 'K': /* EL - Erase in Line */ 6601253Slq150181 tem_send_data(tem, credp, called_from); 6611253Slq150181 tem_setparam(tem, 1, 0); 6621253Slq150181 switch (tems->a_params[0]) { 6631253Slq150181 case 0: 6641253Slq150181 /* erase cursor to end of line */ 6651253Slq150181 tem_clear_chars(tem, 6661253Slq150181 (tems->a_c_dimension.width - 6671253Slq150181 tems->a_c_cursor.col), 6681253Slq150181 tems->a_c_cursor.row, 6691253Slq150181 tems->a_c_cursor.col, 6701253Slq150181 credp, called_from); 6711253Slq150181 break; 6721253Slq150181 6731253Slq150181 case 1: 6741253Slq150181 /* erase beginning of line to cursor */ 6751253Slq150181 tem_clear_chars(tem, 6761253Slq150181 tems->a_c_cursor.col + 1, 6771253Slq150181 tems->a_c_cursor.row, 6781253Slq150181 0, credp, called_from); 6791253Slq150181 break; 6801253Slq150181 6811253Slq150181 case 2: 6821253Slq150181 /* erase whole line */ 6831253Slq150181 tem_clear_chars(tem, 6841253Slq150181 tems->a_c_dimension.width, 6851253Slq150181 tems->a_c_cursor.row, 6861253Slq150181 0, credp, called_from); 6871253Slq150181 break; 6881253Slq150181 } 6891253Slq150181 break; 6901253Slq150181 6911253Slq150181 case 'L': /* insert line */ 6921253Slq150181 tem_send_data(tem, credp, called_from); 6931253Slq150181 tem_setparam(tem, 1, 1); 6941253Slq150181 tem_scroll(tem, 6951253Slq150181 tems->a_c_cursor.row, 6961253Slq150181 tems->a_c_dimension.height - 1, 6971253Slq150181 tems->a_params[0], TEM_SCROLL_DOWN, 6981253Slq150181 credp, called_from); 6991253Slq150181 break; 7001253Slq150181 7011253Slq150181 case 'M': /* delete line */ 7021253Slq150181 tem_send_data(tem, credp, called_from); 7031253Slq150181 tem_setparam(tem, 1, 1); 7041253Slq150181 tem_scroll(tem, 7051253Slq150181 tems->a_c_cursor.row, 7061253Slq150181 tems->a_c_dimension.height - 1, 7071253Slq150181 tems->a_params[0], TEM_SCROLL_UP, 7081253Slq150181 credp, called_from); 7091253Slq150181 break; 7101253Slq150181 7111253Slq150181 case 'P': /* DCH - delete char */ 7121253Slq150181 tem_setparam(tem, 1, 1); 7131253Slq150181 tem_shift(tem, tems->a_params[0], TEM_SHIFT_LEFT, 7141253Slq150181 credp, called_from); 7151253Slq150181 break; 7161253Slq150181 7171253Slq150181 case 'S': /* scroll up */ 7181253Slq150181 tem_send_data(tem, credp, called_from); 7191253Slq150181 tem_setparam(tem, 1, 1); 7201253Slq150181 tem_scroll(tem, 0, 7211253Slq150181 tems->a_c_dimension.height - 1, 7221253Slq150181 tems->a_params[0], TEM_SCROLL_UP, 7231253Slq150181 credp, called_from); 7241253Slq150181 break; 7251253Slq150181 7261253Slq150181 case 'T': /* scroll down */ 7271253Slq150181 tem_send_data(tem, credp, called_from); 7281253Slq150181 tem_setparam(tem, 1, 1); 7291253Slq150181 tem_scroll(tem, 0, 7301253Slq150181 tems->a_c_dimension.height - 1, 7311253Slq150181 tems->a_params[0], TEM_SCROLL_DOWN, 7321253Slq150181 credp, called_from); 7331253Slq150181 break; 7341253Slq150181 7351253Slq150181 case 'X': /* erase char */ 7361253Slq150181 tem_setparam(tem, 1, 1); 7371253Slq150181 tem_clear_chars(tem, 7381253Slq150181 tems->a_params[0], 7391253Slq150181 tems->a_c_cursor.row, 7401253Slq150181 tems->a_c_cursor.col, 7411253Slq150181 credp, called_from); 7421253Slq150181 break; 7431253Slq150181 7441253Slq150181 case 'Z': /* cursor backward tabulation */ 7451253Slq150181 tem_setparam(tem, 1, 1); 7461253Slq150181 7471253Slq150181 /* 7481253Slq150181 * Rule exception - We do sanity checking here. 7491253Slq150181 * 7501253Slq150181 * Restrict the count to a sane value to keep from 7511253Slq150181 * looping for a long time. There can't be more than one 7521253Slq150181 * tab stop per column, so use that as a limit. 7531253Slq150181 */ 7541253Slq150181 if (tems->a_params[0] > tems->a_c_dimension.width) 7551253Slq150181 tems->a_params[0] = tems->a_c_dimension.width; 7561253Slq150181 7571253Slq150181 for (i = 0; i < tems->a_params[0]; i++) 7581253Slq150181 tem_back_tab(tem, credp, called_from); 7591253Slq150181 break; 7601253Slq150181 } 7611253Slq150181 tems->a_state = A_STATE_START; 7621253Slq150181 } 7631253Slq150181 7641253Slq150181 7651253Slq150181 /* 7661253Slq150181 * Gather the parameters of an ANSI escape sequence 7671253Slq150181 */ 7681253Slq150181 static void 7691253Slq150181 tem_getparams(struct tem *tem, uchar_t ch, 7701253Slq150181 cred_t *credp, enum called_from called_from) 7711253Slq150181 { 7721253Slq150181 struct tem_state *tems = tem->state; 7731253Slq150181 7741253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 7751253Slq150181 MUTEX_HELD(&tem->lock)); 7761253Slq150181 7772216Slt200341 if (ch >= '0' && ch <= '9') { 7782216Slt200341 tems->a_paramval = ((tems->a_paramval * 10) + (ch - '0')); 7791253Slq150181 tems->a_gotparam = B_TRUE; /* Remember got parameter */ 7801253Slq150181 return; /* Return immediately */ 7812216Slt200341 } else if (tems->a_state == A_STATE_CSI_EQUAL || 7822216Slt200341 tems->a_state == A_STATE_CSI_QMARK) { 7832216Slt200341 tems->a_state = A_STATE_START; 7842216Slt200341 } else { 7852216Slt200341 if (tems->a_curparam < TEM_MAXPARAMS) { 7862216Slt200341 if (tems->a_gotparam) { 7872216Slt200341 /* get the parameter value */ 7882216Slt200341 tems->a_params[tems->a_curparam] = 7892216Slt200341 tems->a_paramval; 7901253Slq150181 } 7911253Slq150181 tems->a_curparam++; 7921253Slq150181 } 7931253Slq150181 7941253Slq150181 if (ch == ';') { 7951253Slq150181 /* Restart parameter search */ 7961253Slq150181 tems->a_gotparam = B_FALSE; 7971253Slq150181 tems->a_paramval = 0; /* No parame value yet */ 7982216Slt200341 } else { 7991253Slq150181 /* Handle escape sequence */ 8001253Slq150181 tem_chkparam(tem, ch, credp, called_from); 8012216Slt200341 } 8021253Slq150181 } 8031253Slq150181 } 8041253Slq150181 8051253Slq150181 /* 8061253Slq150181 * Add character to internal buffer. 8071253Slq150181 * When its full, send it to the next layer. 8081253Slq150181 */ 8091253Slq150181 8101253Slq150181 static void 8111253Slq150181 tem_outch(struct tem *tem, uchar_t ch, 8121253Slq150181 cred_t *credp, enum called_from called_from) 8131253Slq150181 { 8141253Slq150181 8151253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 8161253Slq150181 MUTEX_HELD(&tem->lock)); 8171253Slq150181 8181253Slq150181 /* buffer up the character until later */ 8191253Slq150181 8201253Slq150181 tem->state->a_outbuf[tem->state->a_outindex++] = ch; 8211253Slq150181 tem->state->a_c_cursor.col++; 8221253Slq150181 if (tem->state->a_c_cursor.col >= tem->state->a_c_dimension.width) { 8231253Slq150181 tem_send_data(tem, credp, called_from); 8241253Slq150181 tem_new_line(tem, credp, called_from); 8251253Slq150181 } 8261253Slq150181 } 8271253Slq150181 8281253Slq150181 static void 8291253Slq150181 tem_new_line(struct tem *tem, 8301253Slq150181 cred_t *credp, enum called_from called_from) 8311253Slq150181 { 8321253Slq150181 tem_cr(tem); 8331253Slq150181 tem_lf(tem, credp, called_from); 8341253Slq150181 } 8351253Slq150181 8361253Slq150181 static void 8371253Slq150181 tem_cr(struct tem *tem) 8381253Slq150181 { 8391253Slq150181 tem->state->a_c_cursor.col = 0; 8401253Slq150181 tem_align_cursor(tem); 8411253Slq150181 } 8421253Slq150181 8431253Slq150181 static void 8441253Slq150181 tem_lf(struct tem *tem, 8451253Slq150181 cred_t *credp, enum called_from called_from) 8461253Slq150181 { 8471253Slq150181 struct tem_state *tems = tem->state; 8481253Slq150181 int row; 8491253Slq150181 8501253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 8511253Slq150181 MUTEX_HELD(&tem->lock)); 8521253Slq150181 8531253Slq150181 /* 8541253Slq150181 * Sanity checking notes: 8551253Slq150181 * . a_nscroll was validated when it was set. 8561253Slq150181 * . Regardless of that, tem_scroll and tem_mv_cursor will prevent 8571253Slq150181 * anything bad from happening. 8581253Slq150181 */ 8591253Slq150181 row = tems->a_c_cursor.row + 1; 8601253Slq150181 8611253Slq150181 if (row >= tems->a_c_dimension.height) { 8621253Slq150181 if (tems->a_nscroll != 0) { 8631253Slq150181 tem_scroll(tem, 0, 8641253Slq150181 tems->a_c_dimension.height - 1, 8651253Slq150181 tems->a_nscroll, TEM_SCROLL_UP, 8661253Slq150181 credp, called_from); 8671253Slq150181 row = tems->a_c_dimension.height - 8681253Slq150181 tems->a_nscroll; 8691253Slq150181 } else { /* no scroll */ 8701253Slq150181 /* 8711253Slq150181 * implement Esc[#r when # is zero. This means no 8721253Slq150181 * scroll but just return cursor to top of screen, 8731253Slq150181 * do not clear screen. 8741253Slq150181 */ 8751253Slq150181 row = 0; 8761253Slq150181 } 8771253Slq150181 } 8781253Slq150181 8791253Slq150181 tem_mv_cursor(tem, row, tems->a_c_cursor.col, 8801253Slq150181 credp, called_from); 8811253Slq150181 8821253Slq150181 if (tems->a_nscroll == 0) { 8831253Slq150181 /* erase rest of cursor line */ 8841253Slq150181 tem_clear_chars(tem, 8851253Slq150181 tems->a_c_dimension.width - 8861253Slq150181 tems->a_c_cursor.col, 8871253Slq150181 tems->a_c_cursor.row, 8881253Slq150181 tems->a_c_cursor.col, 8891253Slq150181 credp, called_from); 8901253Slq150181 8911253Slq150181 } 8921253Slq150181 8931253Slq150181 tem_align_cursor(tem); 8941253Slq150181 } 8951253Slq150181 8961253Slq150181 static void 8971253Slq150181 tem_send_data(struct tem *tem, cred_t *credp, 8981253Slq150181 enum called_from called_from) 8991253Slq150181 { 9001253Slq150181 struct tem_state *tems = tem->state; 9011253Slq150181 text_color_t fg_color; 9021253Slq150181 text_color_t bg_color; 9031253Slq150181 9041253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 9051253Slq150181 MUTEX_HELD(&tem->lock)); 9061253Slq150181 9071253Slq150181 if (tems->a_outindex != 0) { 9081253Slq150181 9091253Slq150181 if (tems->a_flags & TEM_ATTR_REVERSE) { 9101253Slq150181 fg_color = ansi_fg_to_solaris(tem, 9111253Slq150181 tems->bg_color); 9121253Slq150181 bg_color = ansi_bg_to_solaris(tem, 9131253Slq150181 tems->fg_color); 9141253Slq150181 } else { 9151253Slq150181 fg_color = ansi_fg_to_solaris(tem, 9161253Slq150181 tems->fg_color); 9171253Slq150181 bg_color = ansi_bg_to_solaris(tem, 9181253Slq150181 tems->bg_color); 9191253Slq150181 } 9201253Slq150181 9211253Slq150181 /* 9221253Slq150181 * Call the primitive to render this data. 9231253Slq150181 */ 9241253Slq150181 (*tems->in_fp.f_display)(tem, 9251253Slq150181 tems->a_outbuf, 9261253Slq150181 tems->a_outindex, 9271253Slq150181 tems->a_s_cursor.row, 9281253Slq150181 tems->a_s_cursor.col, 9291253Slq150181 fg_color, bg_color, 9301253Slq150181 credp, called_from); 9311253Slq150181 tems->a_outindex = 0; 9321253Slq150181 } 9331253Slq150181 tem_align_cursor(tem); 9341253Slq150181 } 9351253Slq150181 9361253Slq150181 9371253Slq150181 /* 9381253Slq150181 * We have just done something to the current output point. Reset the start 9391253Slq150181 * point for the buffered data in a_outbuf. There shouldn't be any data 9401253Slq150181 * buffered yet. 9411253Slq150181 */ 9421253Slq150181 void 9431253Slq150181 tem_align_cursor(struct tem *tem) 9441253Slq150181 { 9451253Slq150181 tem->state->a_s_cursor.row = tem->state->a_c_cursor.row; 9461253Slq150181 tem->state->a_s_cursor.col = tem->state->a_c_cursor.col; 9471253Slq150181 } 9481253Slq150181 9491253Slq150181 9501253Slq150181 9511253Slq150181 /* 9521253Slq150181 * State machine parser based on the current state and character input 9531253Slq150181 * major terminations are to control character or normal character 9541253Slq150181 */ 9551253Slq150181 9561253Slq150181 static void 9571253Slq150181 tem_parse(struct tem *tem, uchar_t ch, 9581253Slq150181 cred_t *credp, enum called_from called_from) 9591253Slq150181 { 9601253Slq150181 struct tem_state *tems = tem->state; 9611253Slq150181 int i; 9621253Slq150181 9631253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 9641253Slq150181 MUTEX_HELD(&tem->lock)); 9651253Slq150181 9661253Slq150181 if (tems->a_state == A_STATE_START) { /* Normal state? */ 9671253Slq150181 if (ch == A_CSI || ch == A_ESC || ch < ' ') /* Control? */ 9681253Slq150181 tem_control(tem, ch, credp, called_from); 9691253Slq150181 else 9701253Slq150181 /* Display */ 9711253Slq150181 tem_outch(tem, ch, credp, called_from); 9721253Slq150181 return; 9731253Slq150181 } 9741253Slq150181 9751253Slq150181 /* In <ESC> sequence */ 9761253Slq150181 if (tems->a_state != A_STATE_ESC) { /* Need to get parameters? */ 9771253Slq150181 if (tems->a_state != A_STATE_CSI) { 9781253Slq150181 tem_getparams(tem, ch, credp, called_from); 9791253Slq150181 return; 9801253Slq150181 } 9811253Slq150181 9821253Slq150181 switch (ch) { 9831253Slq150181 case '?': 9841253Slq150181 tems->a_state = A_STATE_CSI_QMARK; 9851253Slq150181 return; 9861253Slq150181 case '=': 9871253Slq150181 tems->a_state = A_STATE_CSI_EQUAL; 9881253Slq150181 return; 9891253Slq150181 case 's': 9901253Slq150181 /* 9911253Slq150181 * As defined below, this sequence 9921253Slq150181 * saves the cursor. However, Sun 9931253Slq150181 * defines ESC[s as reset. We resolved 9941253Slq150181 * the conflict by selecting reset as it 9951253Slq150181 * is exported in the termcap file for 9961253Slq150181 * sun-mon, while the "save cursor" 9971253Slq150181 * definition does not exist anywhere in 9981253Slq150181 * /etc/termcap. 9991253Slq150181 * However, having no coherent 10001253Slq150181 * definition of reset, we have not 10011253Slq150181 * implemented it. 10021253Slq150181 */ 10031253Slq150181 10041253Slq150181 /* 10051253Slq150181 * Original code 10061253Slq150181 * tems->a_r_cursor.row = tems->a_c_cursor.row; 10071253Slq150181 * tems->a_r_cursor.col = tems->a_c_cursor.col; 10081253Slq150181 * tems->a_state = A_STATE_START; 10091253Slq150181 */ 10101253Slq150181 10111253Slq150181 tems->a_state = A_STATE_START; 10121253Slq150181 return; 10131253Slq150181 case 'u': 10141253Slq150181 tem_mv_cursor(tem, tems->a_r_cursor.row, 10151253Slq150181 tems->a_r_cursor.col, credp, called_from); 10161253Slq150181 tems->a_state = A_STATE_START; 10171253Slq150181 return; 10181253Slq150181 case 'p': /* sunbow */ 10191253Slq150181 tem_send_data(tem, credp, called_from); 10201253Slq150181 /* 10211253Slq150181 * Don't set anything if we are 10221253Slq150181 * already as we want to be. 10231253Slq150181 */ 10241253Slq150181 if (tems->a_flags & TEM_ATTR_SCREEN_REVERSE) { 10251253Slq150181 tems->a_flags &= ~TEM_ATTR_SCREEN_REVERSE; 10261253Slq150181 /* 10271253Slq150181 * If we have switched the characters to be the 10281253Slq150181 * inverse from the screen, then switch them as 10291253Slq150181 * well to keep them the inverse of the screen. 10301253Slq150181 */ 10311253Slq150181 if (tems->a_flags & TEM_ATTR_REVERSE) { 10321253Slq150181 tems->a_flags &= ~TEM_ATTR_REVERSE; 10331253Slq150181 } else { 10341253Slq150181 tems->a_flags |= TEM_ATTR_REVERSE; 10351253Slq150181 } 10361253Slq150181 } 10371253Slq150181 tem_cls(tem, credp, called_from); 10381253Slq150181 tems->a_state = A_STATE_START; 10391253Slq150181 return; 10401253Slq150181 case 'q': /* sunwob */ 10411253Slq150181 tem_send_data(tem, credp, called_from); 10421253Slq150181 /* 10431253Slq150181 * Don't set anything if we are 10441253Slq150181 * already where as we want to be. 10451253Slq150181 */ 10461253Slq150181 if (!(tems->a_flags & TEM_ATTR_SCREEN_REVERSE)) { 10471253Slq150181 tems->a_flags |= TEM_ATTR_SCREEN_REVERSE; 10481253Slq150181 /* 10491253Slq150181 * If we have switched the characters to be the 10501253Slq150181 * inverse from the screen, then switch them as 10511253Slq150181 * well to keep them the inverse of the screen. 10521253Slq150181 */ 10531253Slq150181 if (!(tems->a_flags & TEM_ATTR_REVERSE)) { 10541253Slq150181 tems->a_flags |= TEM_ATTR_REVERSE; 10551253Slq150181 } else { 10561253Slq150181 tems->a_flags &= ~TEM_ATTR_REVERSE; 10571253Slq150181 } 10581253Slq150181 } 10591253Slq150181 10601253Slq150181 tem_cls(tem, credp, called_from); 10611253Slq150181 tems->a_state = A_STATE_START; 10621253Slq150181 return; 10631253Slq150181 case 'r': /* sunscrl */ 10641253Slq150181 /* 10651253Slq150181 * Rule exception: check for validity here. 10661253Slq150181 */ 10671253Slq150181 tems->a_nscroll = tems->a_paramval; 10681253Slq150181 if (tems->a_nscroll > tems->a_c_dimension.height) 10691253Slq150181 tems->a_nscroll = tems->a_c_dimension.height; 10701253Slq150181 if (tems->a_nscroll < 0) 10711253Slq150181 tems->a_nscroll = 1; 10721253Slq150181 tems->a_state = A_STATE_START; 10731253Slq150181 return; 10741253Slq150181 default: 10751253Slq150181 tem_getparams(tem, ch, credp, called_from); 10761253Slq150181 return; 10771253Slq150181 } 10781253Slq150181 } 10791253Slq150181 10801253Slq150181 /* Previous char was <ESC> */ 10811253Slq150181 if (ch == '[') { 10821253Slq150181 tems->a_curparam = 0; 10831253Slq150181 tems->a_paramval = 0; 10841253Slq150181 tems->a_gotparam = B_FALSE; 10851253Slq150181 /* clear the parameters */ 10861253Slq150181 for (i = 0; i < TEM_MAXPARAMS; i++) 10871253Slq150181 tems->a_params[i] = -1; 10881253Slq150181 tems->a_state = A_STATE_CSI; 10891253Slq150181 } else if (ch == 'Q') { /* <ESC>Q ? */ 10902216Slt200341 tems->a_state = A_STATE_START; 10911253Slq150181 } else if (ch == 'C') { /* <ESC>C ? */ 10922216Slt200341 tems->a_state = A_STATE_START; 10931253Slq150181 } else { 10941253Slq150181 tems->a_state = A_STATE_START; 10951253Slq150181 if (ch == 'c') 10961253Slq150181 /* ESC c resets display */ 1097*3994Slq150181 tem_reset_display(tem, credp, called_from, 1, NULL); 10981253Slq150181 else if (ch == 'H') 10991253Slq150181 /* ESC H sets a tab */ 11001253Slq150181 tem_set_tab(tem); 11011253Slq150181 else if (ch == '7') { 11021253Slq150181 /* ESC 7 Save Cursor position */ 11031253Slq150181 tems->a_r_cursor.row = tems->a_c_cursor.row; 11041253Slq150181 tems->a_r_cursor.col = tems->a_c_cursor.col; 11051253Slq150181 } else if (ch == '8') 11061253Slq150181 /* ESC 8 Restore Cursor position */ 11071253Slq150181 tem_mv_cursor(tem, tems->a_r_cursor.row, 11081253Slq150181 tems->a_r_cursor.col, credp, called_from); 11091253Slq150181 /* check for control chars */ 11101253Slq150181 else if (ch < ' ') 11111253Slq150181 tem_control(tem, ch, credp, called_from); 11121253Slq150181 else 11131253Slq150181 tem_outch(tem, ch, credp, called_from); 11141253Slq150181 } 11151253Slq150181 } 11161253Slq150181 11171253Slq150181 /* ARGSUSED */ 11181253Slq150181 static void 11191253Slq150181 tem_bell(struct tem *tem, enum called_from called_from) 11201253Slq150181 { 11211253Slq150181 if (called_from == CALLED_FROM_STANDALONE) 11221253Slq150181 beep_polled(BEEP_CONSOLE); 11231253Slq150181 else 11241253Slq150181 beep(BEEP_CONSOLE); 11251253Slq150181 } 11261253Slq150181 11271253Slq150181 11281253Slq150181 static void 11291253Slq150181 tem_scroll(tem_t *tem, int start, int end, int count, int direction, 11301253Slq150181 cred_t *credp, enum called_from called_from) 11311253Slq150181 { 11321253Slq150181 struct tem_state *tems = tem->state; 11331253Slq150181 int row; 11341253Slq150181 int lines_affected; 11351253Slq150181 11361253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 11371253Slq150181 MUTEX_HELD(&tem->lock)); 11381253Slq150181 11391253Slq150181 lines_affected = end - start + 1; 11401253Slq150181 if (count > lines_affected) 11411253Slq150181 count = lines_affected; 11421253Slq150181 if (count <= 0) 11431253Slq150181 return; 11441253Slq150181 11451253Slq150181 switch (direction) { 11461253Slq150181 case TEM_SCROLL_UP: 11471253Slq150181 if (count < lines_affected) { 11481253Slq150181 tem_copy_area(tem, 0, start + count, 11491253Slq150181 tems->a_c_dimension.width - 1, end, 11501253Slq150181 0, start, credp, called_from); 11511253Slq150181 } 11521253Slq150181 for (row = (end - count) + 1; row <= end; row++) { 11531253Slq150181 tem_clear_chars(tem, tems->a_c_dimension.width, 11541253Slq150181 row, 0, credp, called_from); 11551253Slq150181 } 11561253Slq150181 break; 11571253Slq150181 11581253Slq150181 case TEM_SCROLL_DOWN: 11591253Slq150181 if (count < lines_affected) { 11601253Slq150181 tem_copy_area(tem, 0, start, 11611253Slq150181 tems->a_c_dimension.width - 1, 11621253Slq150181 end - count, 0, start + count, 11631253Slq150181 credp, called_from); 11641253Slq150181 } 11651253Slq150181 for (row = start; row < start + count; row++) { 11661253Slq150181 tem_clear_chars(tem, tems->a_c_dimension.width, 11671253Slq150181 row, 0, credp, called_from); 11681253Slq150181 } 11691253Slq150181 break; 11701253Slq150181 } 11711253Slq150181 } 11721253Slq150181 11731253Slq150181 static void 11741253Slq150181 tem_copy_area(struct tem *tem, 11751253Slq150181 screen_pos_t s_col, screen_pos_t s_row, 11761253Slq150181 screen_pos_t e_col, screen_pos_t e_row, 11771253Slq150181 screen_pos_t t_col, screen_pos_t t_row, 11781253Slq150181 cred_t *credp, enum called_from called_from) 11791253Slq150181 { 11801253Slq150181 struct tem_state *tems = tem->state; 11811253Slq150181 int rows; 11821253Slq150181 int cols; 11831253Slq150181 11841253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 11851253Slq150181 MUTEX_HELD(&tem->lock)); 11861253Slq150181 11871253Slq150181 if (s_col < 0 || s_row < 0 || 11881253Slq150181 e_col < 0 || e_row < 0 || 11891253Slq150181 t_col < 0 || t_row < 0 || 11901253Slq150181 s_col >= tems->a_c_dimension.width || 11911253Slq150181 e_col >= tems->a_c_dimension.width || 11921253Slq150181 t_col >= tems->a_c_dimension.width || 11931253Slq150181 s_row >= tems->a_c_dimension.height || 11941253Slq150181 e_row >= tems->a_c_dimension.height || 11951253Slq150181 t_row >= tems->a_c_dimension.height) 11961253Slq150181 return; 11971253Slq150181 11981253Slq150181 if (s_row > e_row || s_col > e_col) 11991253Slq150181 return; 12001253Slq150181 12011253Slq150181 rows = e_row - s_row + 1; 12021253Slq150181 cols = e_col - s_col + 1; 12031253Slq150181 if (t_row + rows > tems->a_c_dimension.height || 12041253Slq150181 t_col + cols > tems->a_c_dimension.width) 12051253Slq150181 return; 12061253Slq150181 12071253Slq150181 (*tems->in_fp.f_copy)(tem, s_col, s_row, 12081253Slq150181 e_col, e_row, t_col, t_row, credp, called_from); 12091253Slq150181 } 12101253Slq150181 12111253Slq150181 static void 12121253Slq150181 tem_clear_chars(struct tem *tem, int count, screen_pos_t row, 12131253Slq150181 screen_pos_t col, cred_t *credp, enum called_from called_from) 12141253Slq150181 { 12151253Slq150181 struct tem_state *tems = tem->state; 12161253Slq150181 12171253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 12181253Slq150181 MUTEX_HELD(&tem->lock)); 12191253Slq150181 12201253Slq150181 if (row < 0 || row >= tems->a_c_dimension.height || 12211253Slq150181 col < 0 || col >= tems->a_c_dimension.width || 12221253Slq150181 count < 0) 12231253Slq150181 return; 12241253Slq150181 12251253Slq150181 /* 12261253Slq150181 * Note that very large values of "count" could cause col+count 12271253Slq150181 * to overflow, so we check "count" independently. 12281253Slq150181 */ 12291253Slq150181 if (count > tems->a_c_dimension.width || 12301253Slq150181 col + count > tems->a_c_dimension.width) 12311253Slq150181 count = tems->a_c_dimension.width - col; 12321253Slq150181 12331253Slq150181 (*tems->in_fp.f_cls)(tem, count, row, col, credp, called_from); 12341253Slq150181 } 12351253Slq150181 12361253Slq150181 void 12371253Slq150181 tem_text_display(struct tem *tem, uchar_t *string, 12381253Slq150181 int count, screen_pos_t row, screen_pos_t col, 12391253Slq150181 text_color_t fg_color, text_color_t bg_color, 12401253Slq150181 cred_t *credp, enum called_from called_from) 12411253Slq150181 { 12421253Slq150181 struct vis_consdisplay da; 12431253Slq150181 12441253Slq150181 da.data = string; 12451253Slq150181 da.width = count; 12461253Slq150181 da.row = row; 12471253Slq150181 da.col = col; 12481253Slq150181 12491253Slq150181 da.fg_color = fg_color; 12501253Slq150181 da.bg_color = bg_color; 12511253Slq150181 12521253Slq150181 tem_display(tem, &da, credp, called_from); 12531253Slq150181 } 12541253Slq150181 12551253Slq150181 /* 12561253Slq150181 * This function is used to blit a rectangular color image, 12571253Slq150181 * unperturbed on the underlying framebuffer, to render 12581253Slq150181 * icons and pictures. The data is a pixel pattern that 12591253Slq150181 * fills a rectangle bounded to the width and height parameters. 12601253Slq150181 * The color pixel data must to be pre-adjusted by the caller 12611253Slq150181 * for the current video depth. 12621253Slq150181 * 12631253Slq150181 * This function is unused now. 12641253Slq150181 */ 12651253Slq150181 void 12661253Slq150181 tem_image_display(struct tem *tem, uchar_t *image, 12671253Slq150181 int height, int width, screen_pos_t row, screen_pos_t col, 12681253Slq150181 cred_t *credp, enum called_from called_from) 12691253Slq150181 { 12701253Slq150181 struct vis_consdisplay da; 12711253Slq150181 12721253Slq150181 da.data = image; 12731253Slq150181 da.width = width; 12741253Slq150181 da.height = height; 12751253Slq150181 da.row = row; 12761253Slq150181 da.col = col; 12771253Slq150181 12781253Slq150181 tem_display(tem, &da, credp, called_from); 12791253Slq150181 } 12801253Slq150181 12811253Slq150181 12821253Slq150181 void 12831253Slq150181 tem_text_copy(struct tem *tem, 12841253Slq150181 screen_pos_t s_col, screen_pos_t s_row, 12851253Slq150181 screen_pos_t e_col, screen_pos_t e_row, 12861253Slq150181 screen_pos_t t_col, screen_pos_t t_row, 12871253Slq150181 cred_t *credp, enum called_from called_from) 12881253Slq150181 { 12891253Slq150181 struct vis_conscopy da; 12901253Slq150181 12911253Slq150181 da.s_row = s_row; 12921253Slq150181 da.s_col = s_col; 12931253Slq150181 da.e_row = e_row; 12941253Slq150181 da.e_col = e_col; 12951253Slq150181 da.t_row = t_row; 12961253Slq150181 da.t_col = t_col; 12971253Slq150181 12981253Slq150181 tem_copy(tem, &da, credp, called_from); 12991253Slq150181 } 13001253Slq150181 13011253Slq150181 void 13021253Slq150181 tem_text_cls(struct tem *tem, 13031253Slq150181 int count, screen_pos_t row, screen_pos_t col, cred_t *credp, 13041253Slq150181 enum called_from called_from) 13051253Slq150181 { 13061253Slq150181 struct vis_consdisplay da; 13071253Slq150181 13081253Slq150181 da.data = tem->state->a_blank_line; 13091253Slq150181 da.width = count; 13101253Slq150181 da.row = row; 13111253Slq150181 da.col = col; 13121253Slq150181 13131253Slq150181 tem_get_color(tem, &da.fg_color, &da.bg_color); 13141253Slq150181 tem_display(tem, &da, credp, called_from); 13151253Slq150181 } 13161253Slq150181 13171253Slq150181 13181253Slq150181 13191253Slq150181 void 13201253Slq150181 tem_pix_display(struct tem *tem, 13211253Slq150181 uchar_t *string, int count, 13221253Slq150181 screen_pos_t row, screen_pos_t col, 13231253Slq150181 text_color_t fg_color, text_color_t bg_color, 13241253Slq150181 cred_t *credp, enum called_from called_from) 13251253Slq150181 { 13261253Slq150181 struct tem_state *tems = tem->state; 13271253Slq150181 struct vis_consdisplay da; 13281253Slq150181 int i; 13291253Slq150181 da.data = (uchar_t *)tems->a_pix_data; 13301253Slq150181 da.width = tems->a_font.width; 13311253Slq150181 da.height = tems->a_font.height; 13321253Slq150181 da.row = (row * da.height) + tems->a_p_offset.y; 13331253Slq150181 da.col = (col * da.width) + tems->a_p_offset.x; 13341253Slq150181 13351253Slq150181 for (i = 0; i < count; i++) { 13361253Slq150181 BIT_TO_PIX(tem, string[i], fg_color, bg_color); 13371253Slq150181 tem_display(tem, &da, credp, called_from); 13381253Slq150181 da.col += da.width; 13391253Slq150181 } 13401253Slq150181 } 13411253Slq150181 13421253Slq150181 void 13431253Slq150181 tem_pix_copy(struct tem *tem, 13441253Slq150181 screen_pos_t s_col, screen_pos_t s_row, 13451253Slq150181 screen_pos_t e_col, screen_pos_t e_row, 13461253Slq150181 screen_pos_t t_col, screen_pos_t t_row, 13471253Slq150181 cred_t *credp, 13481253Slq150181 enum called_from called_from) 13491253Slq150181 { 13501253Slq150181 struct tem_state *tems = tem->state; 13511253Slq150181 struct vis_conscopy ma; 13521253Slq150181 static boolean_t need_clear = B_TRUE; 13531253Slq150181 13541253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 13551253Slq150181 MUTEX_HELD(&tem->lock)); 13561253Slq150181 13571253Slq150181 if (need_clear && tems->first_line > 0) { 13581253Slq150181 /* 13591253Slq150181 * Clear OBP output above our kernel console term 13601253Slq150181 * when our kernel console term begins to scroll up, 13611253Slq150181 * we hope it is user friendly. 13621253Slq150181 * (Also see comments on tem_pix_clear_prom_output) 13631253Slq150181 * 13641253Slq150181 * This is only one time call. 13651253Slq150181 */ 13661253Slq150181 tem_pix_clear_prom_output(tem, credp, called_from); 13671253Slq150181 } 13681253Slq150181 need_clear = B_FALSE; 13691253Slq150181 13701253Slq150181 ma.s_row = s_row * tems->a_font.height + tems->a_p_offset.y; 13711253Slq150181 ma.e_row = (e_row + 1) * tems->a_font.height + tems->a_p_offset.y - 1; 13721253Slq150181 ma.t_row = t_row * tems->a_font.height + tems->a_p_offset.y; 13731253Slq150181 13741253Slq150181 /* 13751253Slq150181 * Check if we're in process of clearing OBP's columns area, 13761253Slq150181 * which only happens when term scrolls up a whole line. 13771253Slq150181 */ 13781253Slq150181 if (tems->first_line > 0 && t_row < s_row && t_col == 0 && 13791253Slq150181 e_col == tems->a_c_dimension.width - 1) { 13801253Slq150181 /* 13811253Slq150181 * We need to clear OBP's columns area outside our kernel 13821253Slq150181 * console term. So that we set ma.e_col to entire row here. 13831253Slq150181 */ 13841253Slq150181 ma.s_col = s_col * tems->a_font.width; 13851253Slq150181 ma.e_col = tems->a_p_dimension.width - 1; 13861253Slq150181 13871253Slq150181 ma.t_col = t_col * tems->a_font.width; 13881253Slq150181 } else { 13891253Slq150181 ma.s_col = s_col * tems->a_font.width + tems->a_p_offset.x; 13901253Slq150181 ma.e_col = (e_col + 1) * tems->a_font.width + 13911253Slq150181 tems->a_p_offset.x - 1; 13921253Slq150181 ma.t_col = t_col * tems->a_font.width + tems->a_p_offset.x; 13931253Slq150181 } 13941253Slq150181 13951253Slq150181 tem_copy(tem, &ma, credp, called_from); 13961253Slq150181 13971253Slq150181 if (tems->first_line > 0 && t_row < s_row) { 13981253Slq150181 /* We have scrolled up (s_row - t_row) rows. */ 13991253Slq150181 tems->first_line -= (s_row - t_row); 14001253Slq150181 if (tems->first_line <= 0) { 14011253Slq150181 /* All OBP rows have been cleared. */ 14021253Slq150181 tems->first_line = 0; 14031253Slq150181 } 14041253Slq150181 } 14051253Slq150181 14061253Slq150181 } 14071253Slq150181 14081253Slq150181 /* 14091253Slq150181 * This function only clears count of columns in one row 14101253Slq150181 */ 14111253Slq150181 void 14121253Slq150181 tem_pix_cls(struct tem *tem, int count, 14131253Slq150181 screen_pos_t row, screen_pos_t col, cred_t *credp, 14141253Slq150181 enum called_from called_from) 14151253Slq150181 { 14161253Slq150181 struct tem_state *tems = tem->state; 14171253Slq150181 14181253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 14191253Slq150181 MUTEX_HELD(&tem->lock)); 14201253Slq150181 14211253Slq150181 tem_pix_cls_range(tem, row, 1, tems->a_p_offset.y, 14221253Slq150181 col, count, tems->a_p_offset.x, B_FALSE, credp, called_from); 14231253Slq150181 } 14241253Slq150181 14251253Slq150181 /* 14261253Slq150181 * This function clears OBP output above our kernel console term area 14271253Slq150181 * because OBP's term may have a bigger terminal window than that of 14281253Slq150181 * our kernel console term. So we need to clear OBP output garbage outside 14291253Slq150181 * of our kernel console term at a proper time, which is when the first 14301253Slq150181 * row output of our kernel console term scrolls at the first screen line. 14311253Slq150181 * 14321253Slq150181 * _________________________________ 14331253Slq150181 * | _____________________ | ---> OBP's bigger term window 14341253Slq150181 * | | | | 14351253Slq150181 * |___| | | 14361253Slq150181 * | | | | | 14371253Slq150181 * | | | | | 14381253Slq150181 * |_|_|___________________|_______| 14391253Slq150181 * | | | ---> first line 14401253Slq150181 * | |___________________|---> our kernel console term window 14411253Slq150181 * | 14421253Slq150181 * |---> columns area to be cleared 14431253Slq150181 * 14441253Slq150181 * This function only takes care of the output above our kernel console term, 14451253Slq150181 * and tem_prom_scroll_up takes care of columns area outside of our kernel 14461253Slq150181 * console term. 14471253Slq150181 */ 14481253Slq150181 static void 14491253Slq150181 tem_pix_clear_prom_output(struct tem *tem, cred_t *credp, 14501253Slq150181 enum called_from called_from) 14511253Slq150181 { 14521253Slq150181 struct tem_state *tems = tem->state; 14531253Slq150181 int nrows, ncols, width, height; 14541253Slq150181 14551253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 14561253Slq150181 MUTEX_HELD(&tem->lock)); 14571253Slq150181 14581253Slq150181 width = tems->a_font.width; 14591253Slq150181 height = tems->a_font.height; 14601253Slq150181 14611253Slq150181 nrows = (tems->a_p_offset.y + (height - 1))/ height; 14621253Slq150181 ncols = (tems->a_p_dimension.width + (width - 1))/ width; 14631253Slq150181 14641253Slq150181 tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0, 14651253Slq150181 B_FALSE, credp, called_from); 14661253Slq150181 } 14671253Slq150181 14681253Slq150181 /* 14691253Slq150181 * clear the whole screen for pixel mode 14701253Slq150181 */ 14711253Slq150181 static void 14721253Slq150181 tem_pix_clear_entire_screen(struct tem *tem, cred_t *credp, 14731253Slq150181 enum called_from called_from) 14741253Slq150181 { 14751253Slq150181 struct tem_state *tems = tem->state; 14761253Slq150181 int nrows, ncols, width, height; 14771253Slq150181 14781253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 14791253Slq150181 MUTEX_HELD(&tem->lock)); 14801253Slq150181 14811253Slq150181 width = tems->a_font.width; 14821253Slq150181 height = tems->a_font.height; 14831253Slq150181 14841253Slq150181 nrows = (tems->a_p_dimension.height + (height - 1))/ height; 14851253Slq150181 ncols = (tems->a_p_dimension.width + (width - 1))/ width; 14861253Slq150181 14871253Slq150181 tem_pix_cls_range(tem, 0, nrows, 0, 0, ncols, 0, 14881253Slq150181 B_FALSE, credp, called_from); 14891253Slq150181 14901253Slq150181 tems->a_c_cursor.row = 0; 14911253Slq150181 tems->a_c_cursor.col = 0; 14921253Slq150181 tem_align_cursor(tem); 14931253Slq150181 14941253Slq150181 /* 14951253Slq150181 * Since the whole screen is cleared, we don't need 14961253Slq150181 * to clear OBP output later. 14971253Slq150181 */ 14981253Slq150181 if (tems->first_line > 0) { 14991253Slq150181 tems->first_line = 0; 15001253Slq150181 } 15011253Slq150181 } 15021253Slq150181 15031253Slq150181 /* 15041253Slq150181 * clear the whole screen 15051253Slq150181 */ 15061253Slq150181 static void 15071253Slq150181 tem_cls(struct tem *tem, 15081253Slq150181 cred_t *credp, enum called_from called_from) 15091253Slq150181 { 15101253Slq150181 struct tem_state *tems = tem->state; 15111253Slq150181 int row; 15121253Slq150181 15131253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 15141253Slq150181 MUTEX_HELD(&tem->lock)); 15151253Slq150181 15161253Slq150181 if (tems->display_mode == VIS_TEXT) { 15171253Slq150181 for (row = 0; row < tems->a_c_dimension.height; row++) { 15181253Slq150181 tem_clear_chars(tem, tems->a_c_dimension.width, 15191253Slq150181 row, 0, credp, called_from); 15201253Slq150181 } 15211253Slq150181 tems->a_c_cursor.row = 0; 15221253Slq150181 tems->a_c_cursor.col = 0; 15231253Slq150181 tem_align_cursor(tem); 15241253Slq150181 return; 15251253Slq150181 } 15261253Slq150181 15271253Slq150181 ASSERT(tems->display_mode == VIS_PIXEL); 15281253Slq150181 15291253Slq150181 tem_pix_clear_entire_screen(tem, credp, called_from); 15301253Slq150181 } 15311253Slq150181 15321253Slq150181 static void 15331253Slq150181 tem_back_tab(struct tem *tem, 15341253Slq150181 cred_t *credp, enum called_from called_from) 15351253Slq150181 { 15361253Slq150181 struct tem_state *tems = tem->state; 15371253Slq150181 int i; 15381253Slq150181 screen_pos_t tabstop; 15391253Slq150181 15401253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 15411253Slq150181 MUTEX_HELD(&tem->lock)); 15421253Slq150181 15431253Slq150181 tabstop = 0; 15441253Slq150181 15451253Slq150181 for (i = tems->a_ntabs - 1; i >= 0; i--) { 15461253Slq150181 if (tems->a_tabs[i] < tems->a_c_cursor.col) { 15471253Slq150181 tabstop = tems->a_tabs[i]; 15481253Slq150181 break; 15491253Slq150181 } 15501253Slq150181 } 15511253Slq150181 15521253Slq150181 tem_mv_cursor(tem, tems->a_c_cursor.row, 15531253Slq150181 tabstop, credp, called_from); 15541253Slq150181 } 15551253Slq150181 15561253Slq150181 static void 15571253Slq150181 tem_tab(struct tem *tem, 15581253Slq150181 cred_t *credp, enum called_from called_from) 15591253Slq150181 { 15601253Slq150181 struct tem_state *tems = tem->state; 15611253Slq150181 int i; 15621253Slq150181 screen_pos_t tabstop; 15631253Slq150181 15641253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 15651253Slq150181 MUTEX_HELD(&tem->lock)); 15661253Slq150181 15671253Slq150181 tabstop = tems->a_c_dimension.width - 1; 15681253Slq150181 15691253Slq150181 for (i = 0; i < tems->a_ntabs; i++) { 15701253Slq150181 if (tems->a_tabs[i] > tems->a_c_cursor.col) { 15711253Slq150181 tabstop = tems->a_tabs[i]; 15721253Slq150181 break; 15731253Slq150181 } 15741253Slq150181 } 15751253Slq150181 15761253Slq150181 tem_mv_cursor(tem, tems->a_c_cursor.row, 15771253Slq150181 tabstop, credp, called_from); 15781253Slq150181 } 15791253Slq150181 15801253Slq150181 static void 15811253Slq150181 tem_set_tab(struct tem *tem) 15821253Slq150181 { 15831253Slq150181 struct tem_state *tems = tem->state; 15841253Slq150181 int i; 15851253Slq150181 int j; 15861253Slq150181 15871253Slq150181 if (tems->a_ntabs == TEM_MAXTAB) 15881253Slq150181 return; 15891253Slq150181 if (tems->a_ntabs == 0 || 15901253Slq150181 tems->a_tabs[tems->a_ntabs] < tems->a_c_cursor.col) { 15911253Slq150181 tems->a_tabs[tems->a_ntabs++] = tems->a_c_cursor.col; 15921253Slq150181 return; 15931253Slq150181 } 15941253Slq150181 for (i = 0; i < tems->a_ntabs; i++) { 15951253Slq150181 if (tems->a_tabs[i] == tems->a_c_cursor.col) 15961253Slq150181 return; 15971253Slq150181 if (tems->a_tabs[i] > tems->a_c_cursor.col) { 15981253Slq150181 for (j = tems->a_ntabs - 1; j >= i; j--) 15991253Slq150181 tems->a_tabs[j+ 1] = tems->a_tabs[j]; 16001253Slq150181 tems->a_tabs[i] = tems->a_c_cursor.col; 16011253Slq150181 tems->a_ntabs++; 16021253Slq150181 return; 16031253Slq150181 } 16041253Slq150181 } 16051253Slq150181 } 16061253Slq150181 16071253Slq150181 static void 16081253Slq150181 tem_clear_tabs(struct tem *tem, int action) 16091253Slq150181 { 16101253Slq150181 struct tem_state *tems = tem->state; 16111253Slq150181 int i; 16121253Slq150181 int j; 16131253Slq150181 16141253Slq150181 switch (action) { 16151253Slq150181 case 3: /* clear all tabs */ 16161253Slq150181 tems->a_ntabs = 0; 16171253Slq150181 break; 16181253Slq150181 case 0: /* clr tab at cursor */ 16191253Slq150181 16201253Slq150181 for (i = 0; i < tems->a_ntabs; i++) { 16211253Slq150181 if (tems->a_tabs[i] == tems->a_c_cursor.col) { 16221253Slq150181 tems->a_ntabs--; 16231253Slq150181 for (j = i; j < tems->a_ntabs; j++) 16241253Slq150181 tems->a_tabs[j] = tems->a_tabs[j + 1]; 16251253Slq150181 return; 16261253Slq150181 } 16271253Slq150181 } 16281253Slq150181 break; 16291253Slq150181 } 16301253Slq150181 } 16311253Slq150181 16321253Slq150181 static void 16331253Slq150181 tem_mv_cursor(struct tem *tem, int row, int col, 16341253Slq150181 cred_t *credp, enum called_from called_from) 16351253Slq150181 { 16361253Slq150181 struct tem_state *tems = tem->state; 16371253Slq150181 16381253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 16391253Slq150181 MUTEX_HELD(&tem->lock)); 16401253Slq150181 16411253Slq150181 /* 16421253Slq150181 * Sanity check and bounds enforcement. Out of bounds requests are 16431253Slq150181 * clipped to the screen boundaries. This seems to be what SPARC 16441253Slq150181 * does. 16451253Slq150181 */ 16461253Slq150181 if (row < 0) 16471253Slq150181 row = 0; 16481253Slq150181 if (row >= tems->a_c_dimension.height) 16491253Slq150181 row = tems->a_c_dimension.height - 1; 16501253Slq150181 if (col < 0) 16511253Slq150181 col = 0; 16521253Slq150181 if (col >= tems->a_c_dimension.width) 16531253Slq150181 col = tems->a_c_dimension.width - 1; 16541253Slq150181 16551253Slq150181 tem_send_data(tem, credp, called_from); 16561253Slq150181 tems->a_c_cursor.row = row; 16571253Slq150181 tems->a_c_cursor.col = col; 16581253Slq150181 tem_align_cursor(tem); 16591253Slq150181 } 16601253Slq150181 16611253Slq150181 /* ARGSUSED */ 16621253Slq150181 void 16631253Slq150181 tem_reset_emulator(struct tem *tem, 1664*3994Slq150181 cred_t *credp, enum called_from called_from, 1665*3994Slq150181 tem_color_t *pcolor) 16661253Slq150181 { 16671253Slq150181 struct tem_state *tems = tem->state; 16681253Slq150181 int j; 16691253Slq150181 16701253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 16711253Slq150181 MUTEX_HELD(&tem->lock)); 16721253Slq150181 16731253Slq150181 tems->a_c_cursor.row = 0; 16741253Slq150181 tems->a_c_cursor.col = 0; 16751253Slq150181 tems->a_r_cursor.row = 0; 16761253Slq150181 tems->a_r_cursor.col = 0; 16771253Slq150181 tems->a_s_cursor.row = 0; 16781253Slq150181 tems->a_s_cursor.col = 0; 16791253Slq150181 tems->a_outindex = 0; 16801253Slq150181 tems->a_state = A_STATE_START; 16811253Slq150181 tems->a_gotparam = B_FALSE; 16821253Slq150181 tems->a_curparam = 0; 16831253Slq150181 tems->a_paramval = 0; 16841253Slq150181 tems->a_nscroll = 1; 1685*3994Slq150181 1686*3994Slq150181 if (pcolor != NULL) { 1687*3994Slq150181 /* use customized settings */ 1688*3994Slq150181 tems->fg_color = pcolor->fg_color; 1689*3994Slq150181 tems->bg_color = pcolor->bg_color; 1690*3994Slq150181 tems->a_flags = pcolor->a_flags; 1691*3994Slq150181 } else { 1692*3994Slq150181 /* use initial settings */ 1693*3994Slq150181 tems->fg_color = tem->init_color.fg_color; 1694*3994Slq150181 tems->bg_color = tem->init_color.bg_color; 1695*3994Slq150181 tems->a_flags = tem->init_color.a_flags; 1696*3994Slq150181 } 16971253Slq150181 16981253Slq150181 /* 16991253Slq150181 * set up the initial tab stops 17001253Slq150181 */ 17011253Slq150181 tems->a_ntabs = 0; 17021253Slq150181 for (j = 8; j < tems->a_c_dimension.width; j += 8) 17031253Slq150181 tems->a_tabs[tems->a_ntabs++] = (screen_pos_t)j; 17041253Slq150181 17051253Slq150181 for (j = 0; j < TEM_MAXPARAMS; j++) 17061253Slq150181 tems->a_params[j] = 0; 17071253Slq150181 } 17081253Slq150181 17091253Slq150181 void 17101253Slq150181 tem_reset_display(struct tem *tem, 1711*3994Slq150181 cred_t *credp, enum called_from called_from, int clear_txt, 1712*3994Slq150181 tem_color_t *pcolor) 17131253Slq150181 { 17141253Slq150181 struct tem_state *tems = tem->state; 17151253Slq150181 17161253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 17171253Slq150181 MUTEX_HELD(&tem->lock)); 17181253Slq150181 1719*3994Slq150181 tem_reset_emulator(tem, credp, called_from, pcolor); 17201253Slq150181 tem_reset_colormap(tem, credp, called_from); 17211253Slq150181 17221253Slq150181 if (clear_txt) { 17231253Slq150181 (*tems->in_fp.f_cursor)(tem, 17241253Slq150181 VIS_HIDE_CURSOR, credp, called_from); 17251253Slq150181 17261253Slq150181 tem_cls(tem, credp, called_from); 17271253Slq150181 17281253Slq150181 (*tems->in_fp.f_cursor)(tem, 17291253Slq150181 VIS_DISPLAY_CURSOR, credp, called_from); 17301253Slq150181 } 17311253Slq150181 17321253Slq150181 tems->a_initialized = 1; 17331253Slq150181 } 17341253Slq150181 17351253Slq150181 17361253Slq150181 static void 17371253Slq150181 tem_shift( 17381253Slq150181 struct tem *tem, 17391253Slq150181 int count, 17401253Slq150181 int direction, 17411253Slq150181 cred_t *credp, 17421253Slq150181 enum called_from called_from) 17431253Slq150181 { 17441253Slq150181 struct tem_state *tems = tem->state; 17451253Slq150181 int rest_of_line; 17461253Slq150181 17471253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 17481253Slq150181 MUTEX_HELD(&tem->lock)); 17491253Slq150181 17501253Slq150181 rest_of_line = tems->a_c_dimension.width - tems->a_c_cursor.col; 17511253Slq150181 if (count > rest_of_line) 17521253Slq150181 count = rest_of_line; 17531253Slq150181 17541253Slq150181 if (count <= 0) 17551253Slq150181 return; 17561253Slq150181 17571253Slq150181 switch (direction) { 17581253Slq150181 case TEM_SHIFT_LEFT: 17591253Slq150181 if (count < rest_of_line) { 17601253Slq150181 tem_copy_area(tem, 17611253Slq150181 tems->a_c_cursor.col + count, 17621253Slq150181 tems->a_c_cursor.row, 17631253Slq150181 tems->a_c_dimension.width - 1, 17641253Slq150181 tems->a_c_cursor.row, 17651253Slq150181 tems->a_c_cursor.col, 17661253Slq150181 tems->a_c_cursor.row, 17671253Slq150181 credp, called_from); 17681253Slq150181 } 17691253Slq150181 17701253Slq150181 tem_clear_chars(tem, count, tems->a_c_cursor.row, 17711253Slq150181 (tems->a_c_dimension.width - count), credp, 17721253Slq150181 called_from); 17731253Slq150181 break; 17741253Slq150181 case TEM_SHIFT_RIGHT: 17751253Slq150181 if (count < rest_of_line) { 17761253Slq150181 tem_copy_area(tem, 17771253Slq150181 tems->a_c_cursor.col, 17781253Slq150181 tems->a_c_cursor.row, 17791253Slq150181 tems->a_c_dimension.width - count - 1, 17801253Slq150181 tems->a_c_cursor.row, 17811253Slq150181 tems->a_c_cursor.col + count, 17821253Slq150181 tems->a_c_cursor.row, 17831253Slq150181 credp, called_from); 17841253Slq150181 } 17851253Slq150181 17861253Slq150181 tem_clear_chars(tem, count, tems->a_c_cursor.row, 17871253Slq150181 tems->a_c_cursor.col, credp, called_from); 17881253Slq150181 break; 17891253Slq150181 } 17901253Slq150181 } 17911253Slq150181 17921253Slq150181 void 17931253Slq150181 tem_text_cursor(struct tem *tem, short action, 17941253Slq150181 cred_t *credp, enum called_from called_from) 17951253Slq150181 { 17961253Slq150181 struct tem_state *tems = tem->state; 17971253Slq150181 struct vis_conscursor ca; 17981253Slq150181 17991253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 18001253Slq150181 MUTEX_HELD(&tem->lock)); 18011253Slq150181 18021253Slq150181 ca.row = tems->a_c_cursor.row; 18031253Slq150181 ca.col = tems->a_c_cursor.col; 18041253Slq150181 ca.action = action; 18051253Slq150181 18061253Slq150181 tem_cursor(tem, &ca, credp, called_from); 18071253Slq150181 18081253Slq150181 if (action == VIS_GET_CURSOR) { 18091253Slq150181 tems->a_c_cursor.row = ca.row; 18101253Slq150181 tems->a_c_cursor.col = ca.col; 18111253Slq150181 } 18121253Slq150181 } 18131253Slq150181 18141253Slq150181 18151253Slq150181 void 18161253Slq150181 tem_pix_cursor(struct tem *tem, short action, 18171253Slq150181 cred_t *credp, enum called_from called_from) 18181253Slq150181 { 18191253Slq150181 struct tem_state *tems = tem->state; 18201253Slq150181 struct vis_conscursor ca; 18211253Slq150181 18221253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 18231253Slq150181 MUTEX_HELD(&tem->lock)); 18241253Slq150181 18251253Slq150181 ca.row = tems->a_c_cursor.row * tems->a_font.height + 18261253Slq150181 tems->a_p_offset.y; 18271253Slq150181 ca.col = tems->a_c_cursor.col * tems->a_font.width + 18281253Slq150181 tems->a_p_offset.x; 18291253Slq150181 ca.width = tems->a_font.width; 18301253Slq150181 ca.height = tems->a_font.height; 18311253Slq150181 if (tems->a_pdepth == 8 || tems->a_pdepth == 4) { 18321253Slq150181 if (tems->a_flags & TEM_ATTR_REVERSE) { 18331253Slq150181 ca.fg_color.mono = TEM_TEXT_WHITE; 18341253Slq150181 ca.bg_color.mono = TEM_TEXT_BLACK; 18351253Slq150181 } else { 18361253Slq150181 ca.fg_color.mono = TEM_TEXT_BLACK; 18371253Slq150181 ca.bg_color.mono = TEM_TEXT_WHITE; 18381253Slq150181 } 18391253Slq150181 } else if (tems->a_pdepth == 24 || tems->a_pdepth == 32) { 18401253Slq150181 if (tems->a_flags & TEM_ATTR_REVERSE) { 18411253Slq150181 ca.fg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED; 18421253Slq150181 ca.fg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN; 18431253Slq150181 ca.fg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE; 18441253Slq150181 18451253Slq150181 ca.bg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED; 18461253Slq150181 ca.bg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN; 18471253Slq150181 ca.bg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE; 18481253Slq150181 } else { 18491253Slq150181 ca.fg_color.twentyfour[0] = TEM_TEXT_BLACK24_RED; 18501253Slq150181 ca.fg_color.twentyfour[1] = TEM_TEXT_BLACK24_GREEN; 18511253Slq150181 ca.fg_color.twentyfour[2] = TEM_TEXT_BLACK24_BLUE; 18521253Slq150181 18531253Slq150181 ca.bg_color.twentyfour[0] = TEM_TEXT_WHITE24_RED; 18541253Slq150181 ca.bg_color.twentyfour[1] = TEM_TEXT_WHITE24_GREEN; 18551253Slq150181 ca.bg_color.twentyfour[2] = TEM_TEXT_WHITE24_BLUE; 18561253Slq150181 } 18571253Slq150181 } 18581253Slq150181 18591253Slq150181 ca.action = action; 18601253Slq150181 18611253Slq150181 tem_cursor(tem, &ca, credp, called_from); 18621253Slq150181 } 18631253Slq150181 18641253Slq150181 #define BORDER_PIXELS 10 18651253Slq150181 void 18661253Slq150181 set_font(struct font *f, short *rows, short *cols, short height, short width) 18671253Slq150181 { 18681253Slq150181 bitmap_data_t *font_selected = NULL; 18691253Slq150181 struct fontlist *fl; 18701253Slq150181 18711253Slq150181 /* 18721253Slq150181 * Find best font for these dimensions, or use default 18731253Slq150181 * 18741253Slq150181 * A 1 pixel border is the absolute minimum we could have 18751253Slq150181 * as a border around the text window (BORDER_PIXELS = 2), 18761253Slq150181 * however a slightly larger border not only looks better 18771253Slq150181 * but for the fonts currently statically built into the 18781253Slq150181 * emulator causes much better font selection for the 18791253Slq150181 * normal range of screen resolutions. 18801253Slq150181 */ 18811253Slq150181 for (fl = fonts; fl->data; fl++) { 18821253Slq150181 if ((((*rows * fl->data->height) + BORDER_PIXELS) <= height) && 18831253Slq150181 (((*cols * fl->data->width) + BORDER_PIXELS) <= width)) { 18841253Slq150181 font_selected = fl->data; 18851253Slq150181 break; 18861253Slq150181 } 18871253Slq150181 } 18881253Slq150181 /* 18891253Slq150181 * The minus 2 is to make sure we have at least a 1 pixel 18901253Slq150181 * boarder around the entire screen. 18911253Slq150181 */ 18921253Slq150181 if (font_selected == NULL) { 18931253Slq150181 if (((*rows * DEFAULT_FONT_DATA.height) > height) || 18941253Slq150181 ((*cols * DEFAULT_FONT_DATA.width) > width)) { 18951253Slq150181 *rows = (height - 2) / DEFAULT_FONT_DATA.height; 18961253Slq150181 *cols = (width - 2) / DEFAULT_FONT_DATA.width; 18971253Slq150181 } 18981253Slq150181 font_selected = &DEFAULT_FONT_DATA; 18991253Slq150181 } 19001253Slq150181 19011253Slq150181 f->width = font_selected->width; 19021253Slq150181 f->height = font_selected->height; 19031253Slq150181 bcopy((caddr_t)font_selected->encoding, (caddr_t)f->char_ptr, 19041253Slq150181 sizeof (f->char_ptr)); 19051253Slq150181 f->image_data = font_selected->image; 19061253Slq150181 19071253Slq150181 } 19081253Slq150181 19091253Slq150181 /* 19101253Slq150181 * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte 19111253Slq150181 * for each 2 bits of input bitmap. It inverts the input bits before 19121253Slq150181 * doing the output translation, for reverse video. 19131253Slq150181 * 19141253Slq150181 * Assuming foreground is 0001 and background is 0000... 19151253Slq150181 * An input data byte of 0x53 will output the bit pattern 19161253Slq150181 * 00000001 00000001 00000000 00010001. 19171253Slq150181 */ 19181253Slq150181 19191253Slq150181 void 19201253Slq150181 bit_to_pix4( 19211253Slq150181 struct tem *tem, 19221253Slq150181 uchar_t c, 19231253Slq150181 text_color_t fg_color, 19241253Slq150181 text_color_t bg_color) 19251253Slq150181 { 19261253Slq150181 struct tem_state *tems = tem->state; 19271253Slq150181 int row; 19281253Slq150181 int byte; 19291253Slq150181 int i; 19301253Slq150181 uint8_t *cp; 19311253Slq150181 uint8_t data; 19321253Slq150181 uint8_t nibblett; 19331253Slq150181 int bytes_wide; 19341253Slq150181 uint8_t *dest; 19351253Slq150181 19361253Slq150181 dest = (uint8_t *)tems->a_pix_data; 19371253Slq150181 19381253Slq150181 cp = tems->a_font.char_ptr[c]; 19391253Slq150181 bytes_wide = (tems->a_font.width + 7) / 8; 19401253Slq150181 19411253Slq150181 for (row = 0; row < tems->a_font.height; row++) { 19421253Slq150181 for (byte = 0; byte < bytes_wide; byte++) { 19431253Slq150181 data = *cp++; 19441253Slq150181 for (i = 0; i < 4; i++) { 19451253Slq150181 nibblett = (data >> ((3-i) * 2)) & 0x3; 19461253Slq150181 switch (nibblett) { 19471253Slq150181 case 0x0: 19481253Slq150181 *dest++ = bg_color << 4 | bg_color; 19491253Slq150181 break; 19501253Slq150181 case 0x1: 19511253Slq150181 *dest++ = bg_color << 4 | fg_color; 19521253Slq150181 break; 19531253Slq150181 case 0x2: 19541253Slq150181 *dest++ = fg_color << 4 | bg_color; 19551253Slq150181 break; 19561253Slq150181 case 0x3: 19571253Slq150181 *dest++ = fg_color << 4 | fg_color; 19581253Slq150181 break; 19591253Slq150181 } 19601253Slq150181 } 19611253Slq150181 } 19621253Slq150181 } 19631253Slq150181 } 19641253Slq150181 19651253Slq150181 /* 19661253Slq150181 * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte 19671253Slq150181 * for each bit of input bitmap. It inverts the input bits before 19681253Slq150181 * doing the output translation, for reverse video. 19691253Slq150181 * 19701253Slq150181 * Assuming foreground is 00000001 and background is 00000000... 19711253Slq150181 * An input data byte of 0x53 will output the bit pattern 19721253Slq150181 * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001. 19731253Slq150181 */ 19741253Slq150181 19751253Slq150181 void 19761253Slq150181 bit_to_pix8( 19771253Slq150181 struct tem *tem, 19781253Slq150181 uchar_t c, 19791253Slq150181 text_color_t fg_color, 19801253Slq150181 text_color_t bg_color) 19811253Slq150181 { 19821253Slq150181 struct tem_state *tems = tem->state; 19831253Slq150181 int row; 19841253Slq150181 int byte; 19851253Slq150181 int i; 19861253Slq150181 uint8_t *cp; 19871253Slq150181 uint8_t data; 19881253Slq150181 int bytes_wide; 19891253Slq150181 uint8_t mask; 19901253Slq150181 int bitsleft, nbits; 19911253Slq150181 uint8_t *dest; 19921253Slq150181 19931253Slq150181 dest = (uint8_t *)tems->a_pix_data; 19941253Slq150181 19951253Slq150181 cp = tems->a_font.char_ptr[c]; 19961253Slq150181 bytes_wide = (tems->a_font.width + 7) / 8; 19971253Slq150181 19981253Slq150181 for (row = 0; row < tems->a_font.height; row++) { 19991253Slq150181 bitsleft = tems->a_font.width; 20001253Slq150181 for (byte = 0; byte < bytes_wide; byte++) { 20011253Slq150181 data = *cp++; 20021253Slq150181 mask = 0x80; 20031253Slq150181 nbits = MIN(8, bitsleft); 20041253Slq150181 bitsleft -= nbits; 20051253Slq150181 for (i = 0; i < nbits; i++) { 20061253Slq150181 *dest++ = (data & mask ? fg_color: bg_color); 20071253Slq150181 mask = mask >> 1; 20081253Slq150181 } 20091253Slq150181 } 20101253Slq150181 } 20111253Slq150181 } 20121253Slq150181 20131253Slq150181 /* 20141253Slq150181 * bit_to_pix24 is for 24-bit frame buffers. It will write four output bytes 20151253Slq150181 * for each bit of input bitmap. It inverts the input bits before 20161253Slq150181 * doing the output translation, for reverse video. Note that each 20171253Slq150181 * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the 20181253Slq150181 * high-order byte set to zero. 20191253Slq150181 * 20201253Slq150181 * Assuming foreground is 00000000 11111111 11111111 11111111 20211253Slq150181 * and background is 00000000 00000000 00000000 00000000 20221253Slq150181 * An input data byte of 0x53 will output the bit pattern 20231253Slq150181 * 20241253Slq150181 * 00000000 00000000 00000000 00000000 20251253Slq150181 * 00000000 11111111 11111111 11111111 20261253Slq150181 * 00000000 00000000 00000000 00000000 20271253Slq150181 * 00000000 11111111 11111111 11111111 20281253Slq150181 * 00000000 00000000 00000000 00000000 20291253Slq150181 * 00000000 00000000 00000000 00000000 20301253Slq150181 * 00000000 11111111 11111111 11111111 20311253Slq150181 * 00000000 11111111 11111111 11111111 20321253Slq150181 * 20331253Slq150181 */ 20341253Slq150181 typedef uint32_t pixel32_t; 20351253Slq150181 20361253Slq150181 void 20371253Slq150181 bit_to_pix24( 20381253Slq150181 struct tem *tem, 20391253Slq150181 uchar_t c, 20401253Slq150181 text_color_t fg_color4, 20411253Slq150181 text_color_t bg_color4) 20421253Slq150181 { 20431253Slq150181 struct tem_state *tems = tem->state; 20441253Slq150181 int row; 20451253Slq150181 int byte; 20461253Slq150181 int i; 20471253Slq150181 uint8_t *cp; 20481253Slq150181 uint8_t data; 20491253Slq150181 int bytes_wide; 20501253Slq150181 int bitsleft, nbits; 20511253Slq150181 20521253Slq150181 pixel32_t fg_color32, bg_color32, *destp; 20531253Slq150181 20541253Slq150181 ASSERT(fg_color4 < 16 && bg_color4 < 16); 20551253Slq150181 20561253Slq150181 fg_color32 = PIX4TO32(fg_color4); 20571253Slq150181 bg_color32 = PIX4TO32(bg_color4); 20581253Slq150181 20591253Slq150181 destp = (pixel32_t *)tems->a_pix_data; 20601253Slq150181 cp = tems->a_font.char_ptr[c]; 20611253Slq150181 bytes_wide = (tems->a_font.width + 7) / 8; 20621253Slq150181 20631253Slq150181 for (row = 0; row < tems->a_font.height; row++) { 20641253Slq150181 bitsleft = tems->a_font.width; 20651253Slq150181 for (byte = 0; byte < bytes_wide; byte++) { 20661253Slq150181 data = *cp++; 20671253Slq150181 nbits = MIN(8, bitsleft); 20681253Slq150181 bitsleft -= nbits; 20691253Slq150181 for (i = 0; i < nbits; i++) { 20701253Slq150181 *destp++ = ((data << i) & 0x80 ? 20711253Slq150181 fg_color32 : bg_color32); 20721253Slq150181 } 20731253Slq150181 } 20741253Slq150181 } 20751253Slq150181 } 20761253Slq150181 20771253Slq150181 /* ARGSUSED */ 20781253Slq150181 text_color_t 20791253Slq150181 ansi_bg_to_solaris(struct tem *tem, int ansi) 20801253Slq150181 { 20811253Slq150181 return (bg_xlate[ansi]); 20821253Slq150181 } 20831253Slq150181 20841253Slq150181 text_color_t 20851253Slq150181 ansi_fg_to_solaris(struct tem *tem, int ansi) 20861253Slq150181 { 20871253Slq150181 if (tem->state->a_flags & TEM_ATTR_BOLD) 20881253Slq150181 return (fg_brt_xlate[ansi]); 20891253Slq150181 else 20901253Slq150181 return (fg_dim_xlate[ansi]); 20911253Slq150181 } 20921253Slq150181 20931253Slq150181 static void 20941253Slq150181 tem_get_color(struct tem *tem, text_color_t *fg, text_color_t *bg) 20951253Slq150181 { 20961253Slq150181 if (tem->state->a_flags & TEM_ATTR_SCREEN_REVERSE) { 20971253Slq150181 *fg = ansi_fg_to_solaris(tem, 20981253Slq150181 DEFAULT_ANSI_BACKGROUND); 20991253Slq150181 *bg = ansi_bg_to_solaris(tem, 21001253Slq150181 DEFAULT_ANSI_FOREGROUND); 21011253Slq150181 } else { 21021253Slq150181 *fg = ansi_fg_to_solaris(tem, 21031253Slq150181 DEFAULT_ANSI_FOREGROUND); 21041253Slq150181 *bg = ansi_bg_to_solaris(tem, 21051253Slq150181 DEFAULT_ANSI_BACKGROUND); 21061253Slq150181 } 21071253Slq150181 } 21081253Slq150181 21091253Slq150181 /* 21101253Slq150181 * Clear a rectangle of screen for pixel mode. 21111253Slq150181 * 21121253Slq150181 * arguments: 21131253Slq150181 * row: start row# 21141253Slq150181 * nrows: the number of rows to clear 21151253Slq150181 * offset_y: the offset of height in pixels to begin clear 21161253Slq150181 * col: start col# 21171253Slq150181 * ncols: the number of cols to clear 21181253Slq150181 * offset_x: the offset of width in pixels to begin clear 21191253Slq150181 * scroll_up: whether this function is called during sroll up, 21201253Slq150181 * which is called only once. 21211253Slq150181 */ 21221253Slq150181 void 21231253Slq150181 tem_pix_cls_range(tem_t *tem, 21241253Slq150181 screen_pos_t row, int nrows, int offset_y, 21251253Slq150181 screen_pos_t col, int ncols, int offset_x, 21261253Slq150181 boolean_t sroll_up, cred_t *credp, 21271253Slq150181 enum called_from called_from) 21281253Slq150181 { 21291253Slq150181 struct tem_state *tems = tem->state; 21301253Slq150181 struct vis_consdisplay da; 21311253Slq150181 int i, j; 21321253Slq150181 int row_add = 0; 21331253Slq150181 text_color_t fg_color; 21341253Slq150181 text_color_t bg_color; 21351253Slq150181 21361253Slq150181 ASSERT((called_from == CALLED_FROM_STANDALONE) || 21371253Slq150181 MUTEX_HELD(&tem->lock)); 21381253Slq150181 21391253Slq150181 if (sroll_up) 21401253Slq150181 row_add = tems->a_c_dimension.height - 1; 21411253Slq150181 21421253Slq150181 da.width = tems->a_font.width; 21431253Slq150181 da.height = tems->a_font.height; 21441253Slq150181 21451253Slq150181 tem_get_color(tem, &fg_color, &bg_color); 21461253Slq150181 21471253Slq150181 BIT_TO_PIX(tem, ' ', fg_color, bg_color); 21481253Slq150181 da.data = (uchar_t *)tems->a_pix_data; 21491253Slq150181 21501253Slq150181 for (i = 0; i < nrows; i++, row++) { 21511253Slq150181 da.row = (row + row_add) * da.height + offset_y; 21521253Slq150181 da.col = col * da.width + offset_x; 21531253Slq150181 for (j = 0; j < ncols; j++) { 21541253Slq150181 tem_display(tem, &da, credp, called_from); 21551253Slq150181 da.col += da.width; 21561253Slq150181 } 21571253Slq150181 } 21581253Slq150181 } 2159