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