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