The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/tty/console.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* Code and data for the IBM console driver.
    2  *
    3  * The 6845 video controller used by the IBM PC shares its video memory with
    4  * the CPU somewhere in the 0xB0000 memory bank.  To the 6845 this memory
    5  * consists of 16-bit words.  Each word has a character code in the low byte
    6  * and a so-called attribute byte in the high byte.  The CPU directly modifies
    7  * video memory to display characters, and sets two registers on the 6845 that
    8  * specify the video origin and the cursor position.  The video origin is the
    9  * place in video memory where the first character (upper left corner) can
   10  * be found.  Moving the origin is a fast way to scroll the screen.  Some
   11  * video adapters wrap around the top of video memory, so the origin can
   12  * move without bounds.  For other adapters screen memory must sometimes be
   13  * moved to reset the origin.  All computations on video memory use character
   14  * (word) addresses for simplicity and assume there is no wrapping.  The
   15  * assembly support functions translate the word addresses to byte addresses
   16  * and the scrolling function worries about wrapping.
   17  */
   18 
   19 #include "../drivers.h"
   20 #include <termios.h>
   21 #include <minix/callnr.h>
   22 #include <minix/com.h>
   23 #include "tty.h"
   24 
   25 #include "../../kernel/const.h"
   26 #include "../../kernel/config.h"
   27 #include "../../kernel/type.h"
   28 
   29 /* Definitions used by the console driver. */
   30 #define MONO_BASE    0xB0000L   /* base of mono video memory */
   31 #define COLOR_BASE   0xB8000L   /* base of color video memory */
   32 #define MONO_SIZE     0x1000    /* 4K mono video memory */
   33 #define COLOR_SIZE    0x4000    /* 16K color video memory */
   34 #define EGA_SIZE      0x8000    /* EGA & VGA have at least 32K */
   35 #define BLANK_COLOR   0x0700    /* determines cursor color on blank screen */
   36 #define SCROLL_UP          0    /* scroll forward */
   37 #define SCROLL_DOWN        1    /* scroll backward */
   38 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
   39 #define CONS_RAM_WORDS    80    /* video ram buffer size */
   40 #define MAX_ESC_PARMS      4    /* number of escape sequence params allowed */
   41 
   42 /* Constants relating to the controller chips. */
   43 #define M_6845         0x3B4    /* port for 6845 mono */
   44 #define C_6845         0x3D4    /* port for 6845 color */
   45 #define INDEX              0    /* 6845's index register */
   46 #define DATA               1    /* 6845's data register */
   47 #define STATUS             6    /* 6845's status register */
   48 #define VID_ORG           12    /* 6845's origin register */
   49 #define CURSOR            14    /* 6845's cursor register */
   50 
   51 /* Beeper. */
   52 #define BEEP_FREQ     0x0533    /* value to put into timer to set beep freq */
   53 #define B_TIME             3    /* length of CTRL-G beep is ticks */
   54 
   55 /* definitions used for font management */
   56 #define GA_SEQUENCER_INDEX      0x3C4
   57 #define GA_SEQUENCER_DATA       0x3C5
   58 #define GA_GRAPHICS_INDEX       0x3CE
   59 #define GA_GRAPHICS_DATA        0x3CF
   60 #define GA_VIDEO_ADDRESS        0xA0000L
   61 #define GA_FONT_SIZE            8192
   62 
   63 /* Global variables used by the console driver and assembly support. */
   64 PUBLIC int vid_index;           /* index of video segment in remote mem map */
   65 PUBLIC u16_t vid_seg;
   66 PUBLIC vir_bytes vid_off;       /* video ram is found at vid_seg:vid_off */
   67 PUBLIC unsigned vid_size;       /* 0x2000 for color or 0x0800 for mono */
   68 PUBLIC unsigned vid_mask;       /* 0x1FFF for color or 0x07FF for mono */
   69 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
   70 
   71 /* Private variables used by the console driver. */
   72 PRIVATE int vid_port;           /* I/O port for accessing 6845 */
   73 PRIVATE int wrap;               /* hardware can wrap? */
   74 PRIVATE int softscroll;         /* 1 = software scrolling, 0 = hardware */
   75 PRIVATE int beeping;            /* speaker is beeping? */
   76 PRIVATE unsigned font_lines;    /* font lines per character */
   77 PRIVATE unsigned scr_width;     /* # characters on a line */
   78 PRIVATE unsigned scr_lines;     /* # lines on the screen */
   79 PRIVATE unsigned scr_size;      /* # characters on the screen */
   80 
   81 /* Per console data. */
   82 typedef struct console {
   83   tty_t *c_tty;                 /* associated TTY struct */
   84   int c_column;                 /* current column number (0-origin) */
   85   int c_row;                    /* current row (0 at top of screen) */
   86   int c_rwords;                 /* number of WORDS (not bytes) in outqueue */
   87   unsigned c_start;             /* start of video memory of this console */
   88   unsigned c_limit;             /* limit of this console's video memory */
   89   unsigned c_org;               /* location in RAM where 6845 base points */
   90   unsigned c_cur;               /* current position of cursor in video RAM */
   91   unsigned c_attr;              /* character attribute */
   92   unsigned c_blank;             /* blank attribute */
   93   char c_reverse;               /* reverse video */
   94   char c_esc_state;             /* 0=normal, 1=ESC, 2=ESC[ */
   95   char c_esc_intro;             /* Distinguishing character following ESC */
   96   int *c_esc_parmp;             /* pointer to current escape parameter */
   97   int c_esc_parmv[MAX_ESC_PARMS];       /* list of escape parameters */
   98   u16_t c_ramqueue[CONS_RAM_WORDS];     /* buffer for video RAM */
   99 } console_t;
  100 
  101 PRIVATE int nr_cons= 1;         /* actual number of consoles */
  102 PRIVATE console_t cons_table[NR_CONS];
  103 PRIVATE console_t *curcons;     /* currently visible */
  104 
  105 /* Color if using a color controller. */
  106 #define color   (vid_port == C_6845)
  107 
  108 /* Map from ANSI colors to the attributes used by the PC */
  109 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
  110 
  111 /* Structure used for font management */
  112 struct sequence {
  113         unsigned short index;
  114         unsigned char port;
  115         unsigned char value;
  116 };
  117 
  118 FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try)           );
  119 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c)                  );
  120 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c)             );
  121 FORWARD _PROTOTYPE( void cons_putk, (int c)                             );
  122 FORWARD _PROTOTYPE( void beep, (void)                                   );
  123 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c)            );
  124 FORWARD _PROTOTYPE( void flush, (console_t *cons)                       );
  125 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c)         );
  126 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir)      );
  127 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val)              );
  128 FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val)             );
  129 FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp)                     );
  130 FORWARD _PROTOTYPE( void cons_org0, (void)                              );
  131 FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq)              );
  132 FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int)                    );
  133 
  134 /*===========================================================================*
  135  *                              cons_write                                   *
  136  *===========================================================================*/
  137 PRIVATE int cons_write(tp, try)
  138 register struct tty *tp;        /* tells which terminal is to be used */
  139 int try;
  140 {
  141 /* Copy as much data as possible to the output queue, then start I/O.  On
  142  * memory-mapped terminals, such as the IBM console, the I/O will also be
  143  * finished, and the counts updated.  Keep repeating until all I/O done.
  144  */
  145 
  146   int count;
  147   int result;
  148   register char *tbuf;
  149   char buf[64];
  150   console_t *cons = tp->tty_priv;
  151 
  152   if (try) return 1;    /* we can always write to console */
  153 
  154   /* Check quickly for nothing to do, so this can be called often without
  155    * unmodular tests elsewhere.
  156    */
  157   if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
  158 
  159   /* Copy the user bytes to buf[] for decent addressing. Loop over the
  160    * copies, since the user buffer may be much larger than buf[].
  161    */
  162   do {
  163         if (count > sizeof(buf)) count = sizeof(buf);
  164         if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir, 
  165                         SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
  166                 break;
  167         tbuf = buf;
  168 
  169         /* Update terminal data structure. */
  170         tp->tty_out_vir += count;
  171         tp->tty_outcum += count;
  172         tp->tty_outleft -= count;
  173 
  174         /* Output each byte of the copy to the screen.  Avoid calling
  175          * out_char() for the "easy" characters, put them into the buffer
  176          * directly.
  177          */
  178         do {
  179                 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
  180                         || cons->c_column >= scr_width
  181                         || cons->c_rwords >= buflen(cons->c_ramqueue))
  182                 {
  183                         out_char(cons, *tbuf++);
  184                 } else {
  185                         cons->c_ramqueue[cons->c_rwords++] =
  186                                         cons->c_attr | (*tbuf++ & BYTE);
  187                         cons->c_column++;
  188                 }
  189         } while (--count != 0);
  190   } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
  191 
  192   flush(cons);                  /* transfer anything buffered to the screen */
  193 
  194   /* Reply to the writer if all output is finished or if an error occured. */
  195   if (tp->tty_outleft == 0 || result != OK) {
  196         /* REVIVE is not possible. I/O on memory mapped consoles finishes. */
  197         tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
  198                                                         tp->tty_outcum);
  199         tp->tty_outcum = 0;
  200   }
  201 }
  202 
  203 /*===========================================================================*
  204  *                              cons_echo                                    *
  205  *===========================================================================*/
  206 PRIVATE void cons_echo(tp, c)
  207 register tty_t *tp;             /* pointer to tty struct */
  208 int c;                          /* character to be echoed */
  209 {
  210 /* Echo keyboard input (print & flush). */
  211   console_t *cons = tp->tty_priv;
  212 
  213   out_char(cons, c);
  214   flush(cons);
  215 }
  216 
  217 /*===========================================================================*
  218  *                              out_char                                     *
  219  *===========================================================================*/
  220 PRIVATE void out_char(cons, c)
  221 register console_t *cons;       /* pointer to console struct */
  222 int c;                          /* character to be output */
  223 {
  224 /* Output a character on the console.  Check for escape sequences first. */
  225   if (cons->c_esc_state > 0) {
  226         parse_escape(cons, c);
  227         return;
  228   }
  229 
  230   switch(c) {
  231         case 000:               /* null is typically used for padding */
  232                 return;         /* better not do anything */
  233 
  234         case 007:               /* ring the bell */
  235                 flush(cons);    /* print any chars queued for output */
  236                 beep();
  237                 return;
  238 
  239         case '\b':              /* backspace */
  240                 if (--cons->c_column < 0) {
  241                         if (--cons->c_row >= 0) cons->c_column += scr_width;
  242                 }
  243                 flush(cons);
  244                 return;
  245 
  246         case '\n':              /* line feed */
  247                 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
  248                                                 == (OPOST|ONLCR)) {
  249                         cons->c_column = 0;
  250                 }
  251                 /*FALL THROUGH*/
  252         case 013:               /* CTRL-K */
  253         case 014:               /* CTRL-L */
  254                 if (cons->c_row == scr_lines-1) {
  255                         scroll_screen(cons, SCROLL_UP);
  256                 } else {
  257                         cons->c_row++;
  258                 }
  259                 flush(cons);
  260                 return;
  261 
  262         case '\r':              /* carriage return */
  263                 cons->c_column = 0;
  264                 flush(cons);
  265                 return;
  266 
  267         case '\t':              /* tab */
  268                 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
  269                 if (cons->c_column > scr_width) {
  270                         cons->c_column -= scr_width;
  271                         if (cons->c_row == scr_lines-1) {
  272                                 scroll_screen(cons, SCROLL_UP);
  273                         } else {
  274                                 cons->c_row++;
  275                         }
  276                 }
  277                 flush(cons);
  278                 return;
  279 
  280         case 033:               /* ESC - start of an escape sequence */
  281                 flush(cons);    /* print any chars queued for output */
  282                 cons->c_esc_state = 1;  /* mark ESC as seen */
  283                 return;
  284 
  285         default:                /* printable chars are stored in ramqueue */
  286                 if (cons->c_column >= scr_width) {
  287                         if (!LINEWRAP) return;
  288                         if (cons->c_row == scr_lines-1) {
  289                                 scroll_screen(cons, SCROLL_UP);
  290                         } else {
  291                                 cons->c_row++;
  292                         }
  293                         cons->c_column = 0;
  294                         flush(cons);
  295                 }
  296                 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
  297                 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
  298                 cons->c_column++;                       /* next column */
  299                 return;
  300   }
  301 }
  302 
  303 /*===========================================================================*
  304  *                              scroll_screen                                *
  305  *===========================================================================*/
  306 PRIVATE void scroll_screen(cons, dir)
  307 register console_t *cons;       /* pointer to console struct */
  308 int dir;                        /* SCROLL_UP or SCROLL_DOWN */
  309 {
  310   unsigned new_line, new_org, chars;
  311 
  312   flush(cons);
  313   chars = scr_size - scr_width;         /* one screen minus one line */
  314 
  315   /* Scrolling the screen is a real nuisance due to the various incompatible
  316    * video cards.  This driver supports software scrolling (Hercules?),
  317    * hardware scrolling (mono and CGA cards) and hardware scrolling without
  318    * wrapping (EGA cards).  In the latter case we must make sure that
  319    *            c_start <= c_org && c_org + scr_size <= c_limit
  320    * holds, because EGA doesn't wrap around the end of video memory.
  321    */
  322   if (dir == SCROLL_UP) {
  323         /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
  324         if (softscroll) {
  325                 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
  326         } else
  327         if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
  328                 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
  329                 cons->c_org = cons->c_start;
  330         } else {
  331                 cons->c_org = (cons->c_org + scr_width) & vid_mask;
  332         }
  333         new_line = (cons->c_org + chars) & vid_mask;
  334   } else {
  335         /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
  336         if (softscroll) {
  337                 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
  338         } else
  339         if (!wrap && cons->c_org < cons->c_start + scr_width) {
  340                 new_org = cons->c_limit - scr_size;
  341                 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
  342                 cons->c_org = new_org;
  343         } else {
  344                 cons->c_org = (cons->c_org - scr_width) & vid_mask;
  345         }
  346         new_line = cons->c_org;
  347   }
  348   /* Blank the new line at top or bottom. */
  349   blank_color = cons->c_blank;
  350   mem_vid_copy(BLANK_MEM, new_line, scr_width);
  351 
  352   /* Set the new video origin. */
  353   if (cons == curcons) set_6845(VID_ORG, cons->c_org);
  354   flush(cons);
  355 }
  356 
  357 /*===========================================================================*
  358  *                              flush                                        *
  359  *===========================================================================*/
  360 PRIVATE void flush(cons)
  361 register console_t *cons;       /* pointer to console struct */
  362 {
  363 /* Send characters buffered in 'ramqueue' to screen memory, check the new
  364  * cursor position, compute the new hardware cursor position and set it.
  365  */
  366   unsigned cur;
  367   tty_t *tp = cons->c_tty;
  368 
  369   /* Have the characters in 'ramqueue' transferred to the screen. */
  370   if (cons->c_rwords > 0) {
  371         mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
  372         cons->c_rwords = 0;
  373 
  374         /* TTY likes to know the current column and if echoing messed up. */
  375         tp->tty_position = cons->c_column;
  376         tp->tty_reprint = TRUE;
  377   }
  378 
  379   /* Check and update the cursor position. */
  380   if (cons->c_column < 0) cons->c_column = 0;
  381   if (cons->c_column > scr_width) cons->c_column = scr_width;
  382   if (cons->c_row < 0) cons->c_row = 0;
  383   if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
  384   cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
  385   if (cur != cons->c_cur) {
  386         if (cons == curcons) set_6845(CURSOR, cur);
  387         cons->c_cur = cur;
  388   }
  389 }
  390 
  391 /*===========================================================================*
  392  *                              parse_escape                                 *
  393  *===========================================================================*/
  394 PRIVATE void parse_escape(cons, c)
  395 register console_t *cons;       /* pointer to console struct */
  396 char c;                         /* next character in escape sequence */
  397 {
  398 /* The following ANSI escape sequences are currently supported.
  399  * If n and/or m are omitted, they default to 1.
  400  *   ESC [nA moves up n lines
  401  *   ESC [nB moves down n lines
  402  *   ESC [nC moves right n spaces
  403  *   ESC [nD moves left n spaces
  404  *   ESC [m;nH" moves cursor to (m,n)
  405  *   ESC [J clears screen from cursor
  406  *   ESC [K clears line from cursor
  407  *   ESC [nL inserts n lines ar cursor
  408  *   ESC [nM deletes n lines at cursor
  409  *   ESC [nP deletes n chars at cursor
  410  *   ESC [n@ inserts n chars at cursor
  411  *   ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
  412  *   ESC M scrolls the screen backwards if the cursor is on the top line
  413  */
  414 
  415   switch (cons->c_esc_state) {
  416     case 1:                     /* ESC seen */
  417         cons->c_esc_intro = '\0';
  418         cons->c_esc_parmp = bufend(cons->c_esc_parmv);
  419         do {
  420                 *--cons->c_esc_parmp = 0;
  421         } while (cons->c_esc_parmp > cons->c_esc_parmv);
  422         switch (c) {
  423             case '[':   /* Control Sequence Introducer */
  424                 cons->c_esc_intro = c;
  425                 cons->c_esc_state = 2;
  426                 break;
  427             case 'M':   /* Reverse Index */
  428                 do_escape(cons, c);
  429                 break;
  430             default:
  431                 cons->c_esc_state = 0;
  432         }
  433         break;
  434 
  435     case 2:                     /* ESC [ seen */
  436         if (c >= '' && c <= '9') {
  437                 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
  438                         *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'');
  439         } else
  440         if (c == ';') {
  441                 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
  442                         cons->c_esc_parmp++;
  443         } else {
  444                 do_escape(cons, c);
  445         }
  446         break;
  447   }
  448 }
  449 
  450 /*===========================================================================*
  451  *                              do_escape                                    *
  452  *===========================================================================*/
  453 PRIVATE void do_escape(cons, c)
  454 register console_t *cons;       /* pointer to console struct */
  455 char c;                         /* next character in escape sequence */
  456 {
  457   int value, n;
  458   unsigned src, dst, count;
  459   int *parmp;
  460 
  461   /* Some of these things hack on screen RAM, so it had better be up to date */
  462   flush(cons);
  463 
  464   if (cons->c_esc_intro == '\0') {
  465         /* Handle a sequence beginning with just ESC */
  466         switch (c) {
  467             case 'M':           /* Reverse Index */
  468                 if (cons->c_row == 0) {
  469                         scroll_screen(cons, SCROLL_DOWN);
  470                 } else {
  471                         cons->c_row--;
  472                 }
  473                 flush(cons);
  474                 break;
  475 
  476             default: break;
  477         }
  478   } else
  479   if (cons->c_esc_intro == '[') {
  480         /* Handle a sequence beginning with ESC [ and parameters */
  481         value = cons->c_esc_parmv[0];
  482         switch (c) {
  483             case 'A':           /* ESC [nA moves up n lines */
  484                 n = (value == 0 ? 1 : value);
  485                 cons->c_row -= n;
  486                 flush(cons);
  487                 break;
  488 
  489             case 'B':           /* ESC [nB moves down n lines */
  490                 n = (value == 0 ? 1 : value);
  491                 cons->c_row += n;
  492                 flush(cons);
  493                 break;
  494 
  495             case 'C':           /* ESC [nC moves right n spaces */
  496                 n = (value == 0 ? 1 : value);
  497                 cons->c_column += n;
  498                 flush(cons);
  499                 break;
  500 
  501             case 'D':           /* ESC [nD moves left n spaces */
  502                 n = (value == 0 ? 1 : value);
  503                 cons->c_column -= n;
  504                 flush(cons);
  505                 break;
  506 
  507             case 'H':           /* ESC [m;nH" moves cursor to (m,n) */
  508                 cons->c_row = cons->c_esc_parmv[0] - 1;
  509                 cons->c_column = cons->c_esc_parmv[1] - 1;
  510                 flush(cons);
  511                 break;
  512 
  513             case 'J':           /* ESC [sJ clears in display */
  514                 switch (value) {
  515                     case 0:     /* Clear from cursor to end of screen */
  516                         count = scr_size - (cons->c_cur - cons->c_org);
  517                         dst = cons->c_cur;
  518                         break;
  519                     case 1:     /* Clear from start of screen to cursor */
  520                         count = cons->c_cur - cons->c_org;
  521                         dst = cons->c_org;
  522                         break;
  523                     case 2:     /* Clear entire screen */
  524                         count = scr_size;
  525                         dst = cons->c_org;
  526                         break;
  527                     default:    /* Do nothing */
  528                         count = 0;
  529                         dst = cons->c_org;
  530                 }
  531                 blank_color = cons->c_blank;
  532                 mem_vid_copy(BLANK_MEM, dst, count);
  533                 break;
  534 
  535             case 'K':           /* ESC [sK clears line from cursor */
  536                 switch (value) {
  537                     case 0:     /* Clear from cursor to end of line */
  538                         count = scr_width - cons->c_column;
  539                         dst = cons->c_cur;
  540                         break;
  541                     case 1:     /* Clear from beginning of line to cursor */
  542                         count = cons->c_column;
  543                         dst = cons->c_cur - cons->c_column;
  544                         break;
  545                     case 2:     /* Clear entire line */
  546                         count = scr_width;
  547                         dst = cons->c_cur - cons->c_column;
  548                         break;
  549                     default:    /* Do nothing */
  550                         count = 0;
  551                         dst = cons->c_cur;
  552                 }
  553                 blank_color = cons->c_blank;
  554                 mem_vid_copy(BLANK_MEM, dst, count);
  555                 break;
  556 
  557             case 'L':           /* ESC [nL inserts n lines at cursor */
  558                 n = value;
  559                 if (n < 1) n = 1;
  560                 if (n > (scr_lines - cons->c_row))
  561                         n = scr_lines - cons->c_row;
  562 
  563                 src = cons->c_org + cons->c_row * scr_width;
  564                 dst = src + n * scr_width;
  565                 count = (scr_lines - cons->c_row - n) * scr_width;
  566                 vid_vid_copy(src, dst, count);
  567                 blank_color = cons->c_blank;
  568                 mem_vid_copy(BLANK_MEM, src, n * scr_width);
  569                 break;
  570 
  571             case 'M':           /* ESC [nM deletes n lines at cursor */
  572                 n = value;
  573                 if (n < 1) n = 1;
  574                 if (n > (scr_lines - cons->c_row))
  575                         n = scr_lines - cons->c_row;
  576 
  577                 dst = cons->c_org + cons->c_row * scr_width;
  578                 src = dst + n * scr_width;
  579                 count = (scr_lines - cons->c_row - n) * scr_width;
  580                 vid_vid_copy(src, dst, count);
  581                 blank_color = cons->c_blank;
  582                 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
  583                 break;
  584 
  585             case '@':           /* ESC [n@ inserts n chars at cursor */
  586                 n = value;
  587                 if (n < 1) n = 1;
  588                 if (n > (scr_width - cons->c_column))
  589                         n = scr_width - cons->c_column;
  590 
  591                 src = cons->c_cur;
  592                 dst = src + n;
  593                 count = scr_width - cons->c_column - n;
  594                 vid_vid_copy(src, dst, count);
  595                 blank_color = cons->c_blank;
  596                 mem_vid_copy(BLANK_MEM, src, n);
  597                 break;
  598 
  599             case 'P':           /* ESC [nP deletes n chars at cursor */
  600                 n = value;
  601                 if (n < 1) n = 1;
  602                 if (n > (scr_width - cons->c_column))
  603                         n = scr_width - cons->c_column;
  604 
  605                 dst = cons->c_cur;
  606                 src = dst + n;
  607                 count = scr_width - cons->c_column - n;
  608                 vid_vid_copy(src, dst, count);
  609                 blank_color = cons->c_blank;
  610                 mem_vid_copy(BLANK_MEM, dst + count, n);
  611                 break;
  612 
  613             case 'm':           /* ESC [nm enables rendition n */
  614                 for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
  615                                 && parmp < bufend(cons->c_esc_parmv); parmp++) {
  616                         if (cons->c_reverse) {
  617                                 /* Unswap fg and bg colors */
  618                                 cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
  619                                                 ((cons->c_attr & 0x0700) << 4) |
  620                                                 ((cons->c_attr & 0x8800));
  621                         }
  622                         switch (n = *parmp) {
  623                             case 0:     /* NORMAL */
  624                                 cons->c_attr = cons->c_blank = BLANK_COLOR;
  625                                 cons->c_reverse = FALSE;
  626                                 break;
  627 
  628                             case 1:     /* BOLD  */
  629                                 /* Set intensity bit */
  630                                 cons->c_attr |= 0x0800;
  631                                 break;
  632 
  633                             case 4:     /* UNDERLINE */
  634                                 if (color) {
  635                                         /* Change white to cyan, i.e. lose red
  636                                          */
  637                                         cons->c_attr = (cons->c_attr & 0xBBFF);
  638                                 } else {
  639                                         /* Set underline attribute */
  640                                         cons->c_attr = (cons->c_attr & 0x99FF);
  641                                 }
  642                                 break;
  643 
  644                             case 5:     /* BLINKING */
  645                                 /* Set the blink bit */
  646                                 cons->c_attr |= 0x8000;
  647                                 break;
  648 
  649                             case 7:     /* REVERSE */
  650                                 cons->c_reverse = TRUE;
  651                                 break;
  652 
  653                             default:    /* COLOR */
  654                                 if (n == 39) n = 37;    /* set default color */
  655                                 if (n == 49) n = 40;
  656 
  657                                 if (!color) {
  658                                         /* Don't mess up a monochrome screen */
  659                                 } else
  660                                 if (30 <= n && n <= 37) {
  661                                         /* Foreground color */
  662                                         cons->c_attr =
  663                                                 (cons->c_attr & 0xF8FF) |
  664                                                 (ansi_colors[(n - 30)] << 8);
  665                                         cons->c_blank =
  666                                                 (cons->c_blank & 0xF8FF) |
  667                                                 (ansi_colors[(n - 30)] << 8);
  668                                 } else
  669                                 if (40 <= n && n <= 47) {
  670                                         /* Background color */
  671                                         cons->c_attr =
  672                                                 (cons->c_attr & 0x8FFF) |
  673                                                 (ansi_colors[(n - 40)] << 12);
  674                                         cons->c_blank =
  675                                                 (cons->c_blank & 0x8FFF) |
  676                                                 (ansi_colors[(n - 40)] << 12);
  677                                 }
  678                         }
  679                         if (cons->c_reverse) {
  680                                 /* Swap fg and bg colors */
  681                                 cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
  682                                                 ((cons->c_attr & 0x0700) << 4) |
  683                                                 ((cons->c_attr & 0x8800));
  684                         }
  685                 }
  686                 break;
  687         }
  688   }
  689   cons->c_esc_state = 0;
  690 }
  691 
  692 /*===========================================================================*
  693  *                              set_6845                                     *
  694  *===========================================================================*/
  695 PRIVATE void set_6845(reg, val)
  696 int reg;                        /* which register pair to set */
  697 unsigned val;                   /* 16-bit value to set it to */
  698 {
  699 /* Set a register pair inside the 6845.
  700  * Registers 12-13 tell the 6845 where in video ram to start
  701  * Registers 14-15 tell the 6845 where to put the cursor
  702  */
  703   pvb_pair_t char_out[4];
  704   pv_set(char_out[0], vid_port + INDEX, reg);   /* set index register */
  705   pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE);    /* high byte */
  706   pv_set(char_out[2], vid_port + INDEX, reg + 1);           /* again */
  707   pv_set(char_out[3], vid_port + DATA, val&BYTE);           /* low byte */
  708   sys_voutb(char_out, 4);                       /* do actual output */
  709 }
  710 
  711 /*===========================================================================*
  712  *                              get_6845                                     *
  713  *===========================================================================*/
  714 PRIVATE void get_6845(reg, val)
  715 int reg;                        /* which register pair to set */
  716 unsigned *val;                  /* 16-bit value to set it to */
  717 {
  718   char v1, v2;
  719 /* Get a register pair inside the 6845.  */
  720   sys_outb(vid_port + INDEX, reg); 
  721   sys_inb(vid_port + DATA, &v1); 
  722   sys_outb(vid_port + INDEX, reg+1); 
  723   sys_inb(vid_port + DATA, &v2); 
  724   *val = (v1 << 8) | v2;
  725 }
  726 
  727 /*===========================================================================*
  728  *                              beep                                         *
  729  *===========================================================================*/
  730 PRIVATE void beep()
  731 {
  732 /* Making a beeping sound on the speaker (output for CRTL-G).
  733  * This routine works by turning on the bits 0 and 1 in port B of the 8255
  734  * chip that drive the speaker.
  735  */
  736   static timer_t tmr_stop_beep;
  737   pvb_pair_t char_out[3];
  738   clock_t now;
  739   int port_b_val, s;
  740   
  741   /* Fetch current time in advance to prevent beeping delay. */
  742   if ((s=getuptime(&now)) != OK)
  743         panic("TTY","Console couldn't get clock's uptime.", s);
  744   if (!beeping) {
  745         /* Set timer channel 2, square wave, with given frequency. */
  746         pv_set(char_out[0], TIMER_MODE, 0xB6);  
  747         pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
  748         pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
  749         if (sys_voutb(char_out, 3)==OK) {
  750                 if (sys_inb(PORT_B, &port_b_val)==OK &&
  751                     sys_outb(PORT_B, (port_b_val|3))==OK)
  752                         beeping = TRUE;
  753         }
  754   }
  755   /* Add a timer to the timers list. Possibly reschedule the alarm. */
  756   tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
  757   if (tty_timers->tmr_exp_time != tty_next_timeout) {
  758         tty_next_timeout = tty_timers->tmr_exp_time;
  759         if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
  760                 panic("TTY","Console couldn't set alarm.", s);
  761   }
  762 }
  763 
  764 /*===========================================================================*
  765  *                              stop_beep                                    *
  766  *===========================================================================*/
  767 PRIVATE void stop_beep(tmrp)
  768 timer_t *tmrp;
  769 {
  770 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
  771   int port_b_val;
  772   if (sys_inb(PORT_B, &port_b_val)==OK && 
  773         sys_outb(PORT_B, (port_b_val & ~3))==OK)
  774                 beeping = FALSE;
  775 }
  776 
  777 /*===========================================================================*
  778  *                              scr_init                                     *
  779  *===========================================================================*/
  780 PUBLIC void scr_init(tp)
  781 tty_t *tp;
  782 {
  783 /* Initialize the screen driver. */
  784   console_t *cons;
  785   phys_bytes vid_base;
  786   u16_t bios_columns, bios_crtbase, bios_fontlines;
  787   u8_t bios_rows;
  788   int line;
  789   int s;
  790   static int vdu_initialized = 0;
  791   unsigned page_size;
  792 
  793   /* Associate console and TTY. */
  794   line = tp - &tty_table[0];
  795   if (line >= nr_cons) return;
  796   cons = &cons_table[line];
  797   cons->c_tty = tp;
  798   tp->tty_priv = cons;
  799 
  800   /* Initialize the keyboard driver. */
  801   kb_init(tp);
  802 
  803   /* Fill in TTY function hooks. */
  804   tp->tty_devwrite = cons_write;
  805   tp->tty_echo = cons_echo;
  806   tp->tty_ioctl = cons_ioctl;
  807 
  808   /* Get the BIOS parameters that describe the VDU. */
  809   if (! vdu_initialized++) {
  810 
  811         /* How about error checking? What to do on failure??? */
  812         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_COLS_ADDR,
  813                 SELF, D, (vir_bytes) &bios_columns, VDU_SCREEN_COLS_SIZE);
  814         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_CRT_BASE_ADDR, 
  815                 SELF, D, (vir_bytes) &bios_crtbase, VDU_CRT_BASE_SIZE);
  816         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_ROWS_ADDR, 
  817                 SELF, D, (vir_bytes) &bios_rows, VDU_SCREEN_ROWS_SIZE);
  818         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_FONTLINES_ADDR, 
  819                 SELF, D, (vir_bytes) &bios_fontlines, VDU_FONTLINES_SIZE);
  820 
  821         vid_port = bios_crtbase;
  822         scr_width = bios_columns;
  823         font_lines = bios_fontlines;
  824         scr_lines = machine.vdu_ega ? bios_rows+1 : 25;
  825 
  826         if (color) {
  827                 vid_base = COLOR_BASE;
  828                 vid_size = COLOR_SIZE;
  829         } else {
  830                 vid_base = MONO_BASE;
  831                 vid_size = MONO_SIZE;
  832         }
  833         if (machine.vdu_ega) vid_size = EGA_SIZE;
  834         wrap = ! machine.vdu_ega;
  835 
  836         s = sys_segctl(&vid_index, &vid_seg, &vid_off, vid_base, vid_size);
  837 
  838         vid_size >>= 1;         /* word count */
  839         vid_mask = vid_size - 1;
  840 
  841         /* Size of the screen (number of displayed characters.) */
  842         scr_size = scr_lines * scr_width;
  843 
  844         /* There can be as many consoles as video memory allows. */
  845         nr_cons = vid_size / scr_size;
  846         if (nr_cons > NR_CONS) nr_cons = NR_CONS;
  847         if (nr_cons > 1) wrap = 0;
  848         page_size = vid_size / nr_cons;
  849   }
  850 
  851   cons->c_start = line * page_size;
  852   cons->c_limit = cons->c_start + page_size;
  853   cons->c_cur = cons->c_org = cons->c_start;
  854   cons->c_attr = cons->c_blank = BLANK_COLOR;
  855 
  856   if (line != 0) {
  857         /* Clear the non-console vtys. */
  858         blank_color = BLANK_COLOR;
  859         mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
  860   } else {
  861         int i, n;
  862         /* Set the cursor of the console vty at the bottom. c_cur
  863          * is updated automatically later.
  864          */
  865         scroll_screen(cons, SCROLL_UP);
  866         cons->c_row = scr_lines - 1;
  867         cons->c_column = 0;
  868   }
  869   select_console(0);
  870   cons_ioctl(tp, 0);
  871 }
  872 
  873 /*===========================================================================*
  874  *                              kputc                                        *
  875  *===========================================================================*/
  876 PUBLIC void kputc(c)
  877 int c;
  878 {
  879 #if 0
  880         cons_putk(c);
  881 #else
  882 /* Accumulate a single character for a kernel message. Send a notification
  883  * the to output driver if an END_OF_KMESS is encountered. 
  884  */
  885   if (c != 0) {
  886       kmess.km_buf[kmess.km_next] = c;  /* put normal char in buffer */
  887       if (kmess.km_size < KMESS_BUF_SIZE)
  888           kmess.km_size += 1;           
  889       kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE;
  890   } else {
  891       notify(LOG_PROC_NR);
  892   }
  893 #endif
  894 }
  895 
  896 /*===========================================================================*
  897  *                              do_new_kmess                                 *
  898  *===========================================================================*/
  899 PUBLIC void do_new_kmess(m)
  900 message *m;
  901 {
  902 /* Notification for a new kernel message. */
  903   struct kmessages kmess;                       /* kmessages structure */
  904   static int prev_next = 0;                     /* previous next seen */
  905   int size, next;
  906   int bytes;
  907   int r;
  908 
  909   /* Try to get a fresh copy of the buffer with kernel messages. */
  910 #if DEAD_CODE   
  911   /* During shutdown, the reply is garbled because new notifications arrive
  912    * while the system task makes a copy of the kernel messages buffer.
  913    * Hence, don't check the return value. 
  914    */
  915   if ((r=sys_getkmessages(&kmess)) != OK) {
  916         printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r,r);
  917         return;
  918   }
  919 #endif
  920   sys_getkmessages(&kmess);
  921 
  922   /* Print only the new part. Determine how many new bytes there are with 
  923    * help of the current and previous 'next' index. Note that the kernel
  924    * buffer is circular. This works fine if less then KMESS_BUF_SIZE bytes
  925    * is new data; else we miss % KMESS_BUF_SIZE here.  
  926    * Check for size being positive, the buffer might as well be emptied!
  927    */
  928   if (kmess.km_size > 0) {
  929       bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE;
  930       r=prev_next;                              /* start at previous old */ 
  931       while (bytes > 0) {                       
  932           cons_putk( kmess.km_buf[(r%KMESS_BUF_SIZE)] );
  933           bytes --;
  934           r ++;
  935       }
  936       cons_putk(0);                     /* terminate to flush output */
  937   }
  938 
  939   /* Almost done, store 'next' so that we can determine what part of the
  940    * kernel messages buffer to print next time a notification arrives.
  941    */
  942   prev_next = kmess.km_next;
  943 }
  944 
  945 /*===========================================================================*
  946  *                              do_diagnostics                               *
  947  *===========================================================================*/
  948 PUBLIC void do_diagnostics(m_ptr)
  949 message *m_ptr;                 /* pointer to request message */
  950 {
  951 /* Print a string for a server. */
  952   char c;
  953   vir_bytes src;
  954   int count;
  955   int result = OK;
  956   int proc_nr = m_ptr->DIAG_PROC_NR;
  957   if (proc_nr == SELF) proc_nr = m_ptr->m_source;
  958 
  959   src = (vir_bytes) m_ptr->DIAG_PRINT_BUF;
  960   for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
  961         if (sys_vircopy(proc_nr, D, src++, SELF, D, (vir_bytes) &c, 1) != OK) {
  962                 result = EFAULT;
  963                 break;
  964         }
  965         cons_putk(c);
  966   }
  967   cons_putk(0);                 /* always terminate, even with EFAULT */
  968   m_ptr->m_type = result;
  969   send(m_ptr->m_source, m_ptr);
  970 }
  971 
  972 /*===========================================================================*
  973  *                              do_get_kmess                                 *
  974  *===========================================================================*/
  975 PUBLIC void do_get_kmess(m_ptr)
  976 message *m_ptr;                 /* pointer to request message */
  977 {
  978 /* Provide the log device with debug output */
  979   vir_bytes dst;
  980   int r;
  981 
  982   dst = (vir_bytes) m_ptr->GETKM_PTR;
  983   r= OK;
  984   if (sys_vircopy(SELF, D, (vir_bytes)&kmess, m_ptr->m_source, D,
  985         dst, sizeof(kmess)) != OK) {
  986         r = EFAULT;
  987   }
  988   m_ptr->m_type = r;
  989   send(m_ptr->m_source, m_ptr);
  990 }
  991 
  992 /*===========================================================================*
  993  *                              cons_putk                                    *
  994  *===========================================================================*/
  995 PRIVATE void cons_putk(c)
  996 int c;                          /* character to print */
  997 {
  998 /* This procedure is used to print a character on the console.
  999  */
 1000   if (c != 0) {
 1001         if (c == '\n') cons_putk('\r');
 1002         out_char(&cons_table[0], (int) c);
 1003   } else {
 1004         flush(&cons_table[0]);
 1005   }
 1006 }
 1007 
 1008 /*===========================================================================*
 1009  *                              toggle_scroll                                *
 1010  *===========================================================================*/
 1011 PUBLIC void toggle_scroll()
 1012 {
 1013 /* Toggle between hardware and software scroll. */
 1014 
 1015   cons_org0();
 1016   softscroll = !softscroll;
 1017   printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
 1018 }
 1019 
 1020 /*===========================================================================*
 1021  *                              cons_stop                                    *
 1022  *===========================================================================*/
 1023 PUBLIC void cons_stop()
 1024 {
 1025 /* Prepare for halt or reboot. */
 1026   cons_org0();
 1027   softscroll = 1;
 1028   select_console(0);
 1029   cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
 1030 }
 1031 
 1032 /*===========================================================================*
 1033  *                              cons_org0                                    *
 1034  *===========================================================================*/
 1035 PRIVATE void cons_org0()
 1036 {
 1037 /* Scroll video memory back to put the origin at 0. */
 1038   int cons_line;
 1039   console_t *cons;
 1040   unsigned n;
 1041 
 1042   for (cons_line = 0; cons_line < nr_cons; cons_line++) {
 1043         cons = &cons_table[cons_line];
 1044         while (cons->c_org > cons->c_start) {
 1045                 n = vid_size - scr_size;        /* amount of unused memory */
 1046                 if (n > cons->c_org - cons->c_start)
 1047                         n = cons->c_org - cons->c_start;
 1048                 vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
 1049                 cons->c_org -= n;
 1050         }
 1051         flush(cons);
 1052   }
 1053   select_console(ccurrent);
 1054 }
 1055 
 1056 /*===========================================================================*
 1057  *                              select_console                               *
 1058  *===========================================================================*/
 1059 PUBLIC void select_console(int cons_line)
 1060 {
 1061 /* Set the current console to console number 'cons_line'. */
 1062 
 1063   if (cons_line < 0 || cons_line >= nr_cons) return;
 1064   ccurrent = cons_line;
 1065   curcons = &cons_table[cons_line];
 1066   set_6845(VID_ORG, curcons->c_org);
 1067   set_6845(CURSOR, curcons->c_cur);
 1068 }
 1069 
 1070 /*===========================================================================*
 1071  *                              con_loadfont                                 *
 1072  *===========================================================================*/
 1073 PUBLIC int con_loadfont(m)
 1074 message *m;
 1075 {
 1076 /* Load a font into the EGA or VGA adapter. */
 1077   int result;
 1078   static struct sequence seq1[7] = {
 1079         { GA_SEQUENCER_INDEX, 0x00, 0x01 },
 1080         { GA_SEQUENCER_INDEX, 0x02, 0x04 },
 1081         { GA_SEQUENCER_INDEX, 0x04, 0x07 },
 1082         { GA_SEQUENCER_INDEX, 0x00, 0x03 },
 1083         { GA_GRAPHICS_INDEX, 0x04, 0x02 },
 1084         { GA_GRAPHICS_INDEX, 0x05, 0x00 },
 1085         { GA_GRAPHICS_INDEX, 0x06, 0x00 },
 1086   };
 1087   static struct sequence seq2[7] = {
 1088         { GA_SEQUENCER_INDEX, 0x00, 0x01 },
 1089         { GA_SEQUENCER_INDEX, 0x02, 0x03 },
 1090         { GA_SEQUENCER_INDEX, 0x04, 0x03 },
 1091         { GA_SEQUENCER_INDEX, 0x00, 0x03 },
 1092         { GA_GRAPHICS_INDEX, 0x04, 0x00 },
 1093         { GA_GRAPHICS_INDEX, 0x05, 0x10 },
 1094         { GA_GRAPHICS_INDEX, 0x06,    0 },
 1095   };
 1096 
 1097   seq2[6].value= color ? 0x0E : 0x0A;
 1098 
 1099   if (!machine.vdu_ega) return(ENOTTY);
 1100   result = ga_program(seq1);    /* bring font memory into view */
 1101 
 1102   result = sys_physcopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS, 
 1103         NONE, PHYS_SEG, (phys_bytes) GA_VIDEO_ADDRESS, (phys_bytes)GA_FONT_SIZE);
 1104 
 1105   result = ga_program(seq2);    /* restore */
 1106 
 1107   return(result);
 1108 }
 1109 
 1110 /*===========================================================================*
 1111  *                              ga_program                                   *
 1112  *===========================================================================*/
 1113 PRIVATE int ga_program(seq)
 1114 struct sequence *seq;
 1115 {
 1116   pvb_pair_t char_out[14];
 1117   int i;
 1118   for (i=0; i<7; i++) {
 1119       pv_set(char_out[2*i], seq->index, seq->port);
 1120       pv_set(char_out[2*i+1], seq->index+1, seq->value);
 1121       seq++;
 1122   } 
 1123   return sys_voutb(char_out, 14);
 1124 }
 1125 
 1126 /*===========================================================================*
 1127  *                              cons_ioctl                                   *
 1128  *===========================================================================*/
 1129 PRIVATE int cons_ioctl(tp, try)
 1130 tty_t *tp;
 1131 int try;
 1132 {
 1133 /* Set the screen dimensions. */
 1134 
 1135   tp->tty_winsize.ws_row= scr_lines;
 1136   tp->tty_winsize.ws_col= scr_width;
 1137   tp->tty_winsize.ws_xpixel= scr_width * 8;
 1138   tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
 1139 }

Cache object: 92b52b7031e174613393cecffd716629


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.