console.c

Go to the documentation of this file.
00001 /* Code and data for the IBM console driver.
00002  *
00003  * The 6845 video controller used by the IBM PC shares its video memory with
00004  * the CPU somewhere in the 0xB0000 memory bank.  To the 6845 this memory
00005  * consists of 16-bit words.  Each word has a character code in the low byte
00006  * and a so-called attribute byte in the high byte.  The CPU directly modifies
00007  * video memory to display characters, and sets two registers on the 6845 that
00008  * specify the video origin and the cursor position.  The video origin is the
00009  * place in video memory where the first character (upper left corner) can
00010  * be found.  Moving the origin is a fast way to scroll the screen.  Some
00011  * video adapters wrap around the top of video memory, so the origin can
00012  * move without bounds.  For other adapters screen memory must sometimes be
00013  * moved to reset the origin.  All computations on video memory use character
00014  * (word) addresses for simplicity and assume there is no wrapping.  The
00015  * assembly support functions translate the word addresses to byte addresses
00016  * and the scrolling function worries about wrapping.
00017  */
00018 
00019 #include "../drivers.h"
00020 #include <termios.h>
00021 #include <sys/ioctl.h>
00022 #include <sys/vm.h>
00023 #include <minix/callnr.h>
00024 #include <minix/com.h>
00025 #include "tty.h"
00026 
00027 #include "../../kernel/const.h"
00028 #include "../../kernel/config.h"
00029 #include "../../kernel/type.h"
00030 
00031 /* Definitions used by the console driver. */
00032 #define MONO_BASE    0xB0000L   /* base of mono video memory */
00033 #define COLOR_BASE   0xB8000L   /* base of color video memory */
00034 #define MONO_SIZE     0x1000    /* 4K mono video memory */
00035 #define COLOR_SIZE    0x4000    /* 16K color video memory */
00036 #define EGA_SIZE      0x8000    /* EGA & VGA have at least 32K */
00037 #define BLANK_COLOR   0x0700    /* determines cursor color on blank screen */
00038 #define SCROLL_UP          0    /* scroll forward */
00039 #define SCROLL_DOWN        1    /* scroll backward */
00040 #define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
00041 #define CONS_RAM_WORDS    80    /* video ram buffer size */
00042 #define MAX_ESC_PARMS      4    /* number of escape sequence params allowed */
00043 
00044 /* Constants relating to the controller chips. */
00045 #define M_6845         0x3B4    /* port for 6845 mono */
00046 #define C_6845         0x3D4    /* port for 6845 color */
00047 #define INDEX              0    /* 6845's index register */
00048 #define DATA               1    /* 6845's data register */
00049 #define STATUS             6    /* 6845's status register */
00050 #define VID_ORG           12    /* 6845's origin register */
00051 #define CURSOR            14    /* 6845's cursor register */
00052 
00053 /* The clock task should provide an interface for this */
00054 #define TIMER_FREQ  1193182L    /* clock frequency for timer in PC and AT */
00055 
00056 /* Beeper. */
00057 #define BEEP_FREQ     0x0533    /* value to put into timer to set beep freq */
00058 #define B_TIME             3    /* length of CTRL-G beep is ticks */
00059 
00060 /* definitions used for font management */
00061 #define GA_SEQUENCER_INDEX      0x3C4
00062 #define GA_SEQUENCER_DATA       0x3C5
00063 #define GA_GRAPHICS_INDEX       0x3CE
00064 #define GA_GRAPHICS_DATA        0x3CF
00065 #define GA_VIDEO_ADDRESS        0xA0000L
00066 #define GA_FONT_SIZE            8192
00067 
00068 /* Global variables used by the console driver and assembly support. */
00069 PUBLIC int vid_index;           /* index of video segment in remote mem map */
00070 PUBLIC u16_t vid_seg;
00071 PUBLIC vir_bytes vid_off;       /* video ram is found at vid_seg:vid_off */
00072 PUBLIC unsigned vid_size;       /* 0x2000 for color or 0x0800 for mono */
00073 PUBLIC unsigned vid_mask;       /* 0x1FFF for color or 0x07FF for mono */
00074 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
00075 
00076 /* Private variables used by the console driver. */
00077 PRIVATE int vid_port;           /* I/O port for accessing 6845 */
00078 PRIVATE int wrap;               /* hardware can wrap? */
00079 PRIVATE int softscroll;         /* 1 = software scrolling, 0 = hardware */
00080 PRIVATE int beeping;            /* speaker is beeping? */
00081 PRIVATE unsigned font_lines;    /* font lines per character */
00082 PRIVATE unsigned scr_width;     /* # characters on a line */
00083 PRIVATE unsigned scr_lines;     /* # lines on the screen */
00084 PRIVATE unsigned scr_size;      /* # characters on the screen */
00085 
00086 /* Per console data. */
00087 typedef struct console {
00088   tty_t *c_tty;                 /* associated TTY struct */
00089   int c_column;                 /* current column number (0-origin) */
00090   int c_row;                    /* current row (0 at top of screen) */
00091   int c_rwords;                 /* number of WORDS (not bytes) in outqueue */
00092   unsigned c_start;             /* start of video memory of this console */
00093   unsigned c_limit;             /* limit of this console's video memory */
00094   unsigned c_org;               /* location in RAM where 6845 base points */
00095   unsigned c_cur;               /* current position of cursor in video RAM */
00096   unsigned c_attr;              /* character attribute */
00097   unsigned c_blank;             /* blank attribute */
00098   char c_reverse;               /* reverse video */
00099   char c_esc_state;             /* 0=normal, 1=ESC, 2=ESC[ */
00100   char c_esc_intro;             /* Distinguishing character following ESC */
00101   int *c_esc_parmp;             /* pointer to current escape parameter */
00102   int c_esc_parmv[MAX_ESC_PARMS];       /* list of escape parameters */
00103   u16_t c_ramqueue[CONS_RAM_WORDS];     /* buffer for video RAM */
00104 } console_t;
00105 
00106 PRIVATE int nr_cons= 1;         /* actual number of consoles */
00107 PRIVATE console_t cons_table[NR_CONS];
00108 PRIVATE console_t *curcons;     /* currently visible */
00109 
00110 /* Color if using a color controller. */
00111 #define color   (vid_port == C_6845)
00112 
00113 /* Map from ANSI colors to the attributes used by the PC */
00114 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
00115 
00116 /* Structure used for font management */
00117 struct sequence {
00118         unsigned short index;
00119         unsigned char port;
00120         unsigned char value;
00121 };
00122 
00123 FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try)           );
00124 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c)                  );
00125 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c)             );
00126 FORWARD _PROTOTYPE( void cons_putk, (int c)                             );
00127 FORWARD _PROTOTYPE( void beep, (void)                                   );
00128 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c)            );
00129 FORWARD _PROTOTYPE( void flush, (console_t *cons)                       );
00130 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c)         );
00131 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir)      );
00132 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val)              );
00133 FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val)             );
00134 FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp)                     );
00135 FORWARD _PROTOTYPE( void cons_org0, (void)                              );
00136 FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq)              );
00137 FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int)                    );
00138 PRIVATE _PROTOTYPE( void ser_putc, (char c)                             );
00139 
00140 /*===========================================================================*
00141  *                              cons_write                                   *
00142  *===========================================================================*/
00143 PRIVATE int cons_write(tp, try)
00144 register struct tty *tp;        /* tells which terminal is to be used */
00145 int try;
00146 {
00147 /* Copy as much data as possible to the output queue, then start I/O.  On
00148  * memory-mapped terminals, such as the IBM console, the I/O will also be
00149  * finished, and the counts updated.  Keep repeating until all I/O done.
00150  */
00151 
00152   int count;
00153   int result;
00154   register char *tbuf;
00155   char buf[64];
00156   console_t *cons = tp->tty_priv;
00157 
00158   if (try) return 1;    /* we can always write to console */
00159 
00160   /* Check quickly for nothing to do, so this can be called often without
00161    * unmodular tests elsewhere.
00162    */
00163   if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
00164 
00165   /* Copy the user bytes to buf[] for decent addressing. Loop over the
00166    * copies, since the user buffer may be much larger than buf[].
00167    */
00168   do {
00169         if (count > sizeof(buf)) count = sizeof(buf);
00170         if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir, 
00171                         SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
00172                 break;
00173         tbuf = buf;
00174 
00175         /* Update terminal data structure. */
00176         tp->tty_out_vir += count;
00177         tp->tty_outcum += count;
00178         tp->tty_outleft -= count;
00179 
00180         /* Output each byte of the copy to the screen.  Avoid calling
00181          * out_char() for the "easy" characters, put them into the buffer
00182          * directly.
00183          */
00184         do {
00185                 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
00186                         || cons->c_column >= scr_width
00187                         || cons->c_rwords >= buflen(cons->c_ramqueue))
00188                 {
00189                         out_char(cons, *tbuf++);
00190                 } else {
00191                         cons->c_ramqueue[cons->c_rwords++] =
00192                                         cons->c_attr | (*tbuf++ & BYTE);
00193                         cons->c_column++;
00194                 }
00195         } while (--count != 0);
00196   } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
00197 
00198   flush(cons);                  /* transfer anything buffered to the screen */
00199 
00200   /* Reply to the writer if all output is finished or if an error occured. */
00201   if (tp->tty_outleft == 0 || result != OK) {
00202         /* REVIVE is not possible. I/O on memory mapped consoles finishes. */
00203         tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
00204                                                         tp->tty_outcum);
00205         tp->tty_outcum = 0;
00206   }
00207 }
00208 
00209 /*===========================================================================*
00210  *                              cons_echo                                    *
00211  *===========================================================================*/
00212 PRIVATE void cons_echo(tp, c)
00213 register tty_t *tp;             /* pointer to tty struct */
00214 int c;                          /* character to be echoed */
00215 {
00216 /* Echo keyboard input (print & flush). */
00217   console_t *cons = tp->tty_priv;
00218 
00219   out_char(cons, c);
00220   flush(cons);
00221 }
00222 
00223 /*===========================================================================*
00224  *                              out_char                                     *
00225  *===========================================================================*/
00226 PRIVATE void out_char(cons, c)
00227 register console_t *cons;       /* pointer to console struct */
00228 int c;                          /* character to be output */
00229 {
00230 /* Output a character on the console.  Check for escape sequences first. */
00231   if (cons->c_esc_state > 0) {
00232         parse_escape(cons, c);
00233         return;
00234   }
00235 
00236   switch(c) {
00237         case 000:               /* null is typically used for padding */
00238                 return;         /* better not do anything */
00239 
00240         case 007:               /* ring the bell */
00241                 flush(cons);    /* print any chars queued for output */
00242                 beep();
00243                 return;
00244 
00245         case '\b':              /* backspace */
00246                 if (--cons->c_column < 0) {
00247                         if (--cons->c_row >= 0) cons->c_column += scr_width;
00248                 }
00249                 flush(cons);
00250                 return;
00251 
00252         case '\n':              /* line feed */
00253                 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
00254                                                 == (OPOST|ONLCR)) {
00255                         cons->c_column = 0;
00256                 }
00257                 /*FALL THROUGH*/
00258         case 013:               /* CTRL-K */
00259         case 014:               /* CTRL-L */
00260                 if (cons->c_row == scr_lines-1) {
00261                         scroll_screen(cons, SCROLL_UP);
00262                 } else {
00263                         cons->c_row++;
00264                 }
00265                 flush(cons);
00266                 return;
00267 
00268         case '\r':              /* carriage return */
00269                 cons->c_column = 0;
00270                 flush(cons);
00271                 return;
00272 
00273         case '\t':              /* tab */
00274                 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
00275                 if (cons->c_column > scr_width) {
00276                         cons->c_column -= scr_width;
00277                         if (cons->c_row == scr_lines-1) {
00278                                 scroll_screen(cons, SCROLL_UP);
00279                         } else {
00280                                 cons->c_row++;
00281                         }
00282                 }
00283                 flush(cons);
00284                 return;
00285 
00286         case 033:               /* ESC - start of an escape sequence */
00287                 flush(cons);    /* print any chars queued for output */
00288                 cons->c_esc_state = 1;  /* mark ESC as seen */
00289                 return;
00290 
00291         default:                /* printable chars are stored in ramqueue */
00292                 if (cons->c_column >= scr_width) {
00293                         if (!LINEWRAP) return;
00294                         if (cons->c_row == scr_lines-1) {
00295                                 scroll_screen(cons, SCROLL_UP);
00296                         } else {
00297                                 cons->c_row++;
00298                         }
00299                         cons->c_column = 0;
00300                         flush(cons);
00301                 }
00302                 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
00303                 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
00304                 cons->c_column++;                       /* next column */
00305                 return;
00306   }
00307 }
00308 
00309 /*===========================================================================*
00310  *                              scroll_screen                                *
00311  *===========================================================================*/
00312 PRIVATE void scroll_screen(cons, dir)
00313 register console_t *cons;       /* pointer to console struct */
00314 int dir;                        /* SCROLL_UP or SCROLL_DOWN */
00315 {
00316   unsigned new_line, new_org, chars;
00317 
00318   flush(cons);
00319   chars = scr_size - scr_width;         /* one screen minus one line */
00320 
00321   /* Scrolling the screen is a real nuisance due to the various incompatible
00322    * video cards.  This driver supports software scrolling (Hercules?),
00323    * hardware scrolling (mono and CGA cards) and hardware scrolling without
00324    * wrapping (EGA cards).  In the latter case we must make sure that
00325    *            c_start <= c_org && c_org + scr_size <= c_limit
00326    * holds, because EGA doesn't wrap around the end of video memory.
00327    */
00328   if (dir == SCROLL_UP) {
00329         /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
00330         if (softscroll) {
00331                 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
00332         } else
00333         if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
00334                 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
00335                 cons->c_org = cons->c_start;
00336         } else {
00337                 cons->c_org = (cons->c_org + scr_width) & vid_mask;
00338         }
00339         new_line = (cons->c_org + chars) & vid_mask;
00340   } else {
00341         /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
00342         if (softscroll) {
00343                 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
00344         } else
00345         if (!wrap && cons->c_org < cons->c_start + scr_width) {
00346                 new_org = cons->c_limit - scr_size;
00347                 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
00348                 cons->c_org = new_org;
00349         } else {
00350                 cons->c_org = (cons->c_org - scr_width) & vid_mask;
00351         }
00352         new_line = cons->c_org;
00353   }
00354   /* Blank the new line at top or bottom. */
00355   blank_color = cons->c_blank;
00356   mem_vid_copy(BLANK_MEM, new_line, scr_width);
00357 
00358   /* Set the new video origin. */
00359   if (cons == curcons) set_6845(VID_ORG, cons->c_org);
00360   flush(cons);
00361 }
00362 
00363 /*===========================================================================*
00364  *                              flush                                        *
00365  *===========================================================================*/
00366 PRIVATE void flush(cons)
00367 register console_t *cons;       /* pointer to console struct */
00368 {
00369 /* Send characters buffered in 'ramqueue' to screen memory, check the new
00370  * cursor position, compute the new hardware cursor position and set it.
00371  */
00372   unsigned cur;
00373   tty_t *tp = cons->c_tty;
00374 
00375   /* Have the characters in 'ramqueue' transferred to the screen. */
00376   if (cons->c_rwords > 0) {
00377         mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
00378         cons->c_rwords = 0;
00379 
00380         /* TTY likes to know the current column and if echoing messed up. */
00381         tp->tty_position = cons->c_column;
00382         tp->tty_reprint = TRUE;
00383   }
00384 
00385   /* Check and update the cursor position. */
00386   if (cons->c_column < 0) cons->c_column = 0;
00387   if (cons->c_column > scr_width) cons->c_column = scr_width;
00388   if (cons->c_row < 0) cons->c_row = 0;
00389   if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
00390   cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
00391   if (cur != cons->c_cur) {
00392         if (cons == curcons) set_6845(CURSOR, cur);
00393         cons->c_cur = cur;
00394   }
00395 }
00396 
00397 /*===========================================================================*
00398  *                              parse_escape                                 *
00399  *===========================================================================*/
00400 PRIVATE void parse_escape(cons, c)
00401 register console_t *cons;       /* pointer to console struct */
00402 char c;                         /* next character in escape sequence */
00403 {
00404 /* The following ANSI escape sequences are currently supported.
00405  * If n and/or m are omitted, they default to 1.
00406  *   ESC [nA moves up n lines
00407  *   ESC [nB moves down n lines
00408  *   ESC [nC moves right n spaces
00409  *   ESC [nD moves left n spaces
00410  *   ESC [m;nH" moves cursor to (m,n)
00411  *   ESC [J clears screen from cursor
00412  *   ESC [K clears line from cursor
00413  *   ESC [nL inserts n lines ar cursor
00414  *   ESC [nM deletes n lines at cursor
00415  *   ESC [nP deletes n chars at cursor
00416  *   ESC [n@ inserts n chars at cursor
00417  *   ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
00418  *   ESC M scrolls the screen backwards if the cursor is on the top line
00419  */
00420 
00421   switch (cons->c_esc_state) {
00422     case 1:                     /* ESC seen */
00423         cons->c_esc_intro = '\0';
00424         cons->c_esc_parmp = bufend(cons->c_esc_parmv);
00425         do {
00426                 *--cons->c_esc_parmp = 0;
00427         } while (cons->c_esc_parmp > cons->c_esc_parmv);
00428         switch (c) {
00429             case '[':   /* Control Sequence Introducer */
00430                 cons->c_esc_intro = c;
00431                 cons->c_esc_state = 2;
00432                 break;
00433             case 'M':   /* Reverse Index */
00434                 do_escape(cons, c);
00435                 break;
00436             default:
00437                 cons->c_esc_state = 0;
00438         }
00439         break;
00440 
00441     case 2:                     /* ESC [ seen */
00442         if (c >= '0' && c <= '9') {
00443                 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
00444                         *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
00445         } else
00446         if (c == ';') {
00447                 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
00448                         cons->c_esc_parmp++;
00449         } else {
00450                 do_escape(cons, c);
00451         }
00452         break;
00453   }
00454 }
00455 
00456 /*===========================================================================*
00457  *                              do_escape                                    *
00458  *===========================================================================*/
00459 PRIVATE void do_escape(cons, c)
00460 register console_t *cons;       /* pointer to console struct */
00461 char c;                         /* next character in escape sequence */
00462 {
00463   int value, n;
00464   unsigned src, dst, count;
00465   int *parmp;
00466 
00467   /* Some of these things hack on screen RAM, so it had better be up to date */
00468   flush(cons);
00469 
00470   if (cons->c_esc_intro == '\0') {
00471         /* Handle a sequence beginning with just ESC */
00472         switch (c) {
00473             case 'M':           /* Reverse Index */
00474                 if (cons->c_row == 0) {
00475                         scroll_screen(cons, SCROLL_DOWN);
00476                 } else {
00477                         cons->c_row--;
00478                 }
00479                 flush(cons);
00480                 break;
00481 
00482             default: break;
00483         }
00484   } else
00485   if (cons->c_esc_intro == '[') {
00486         /* Handle a sequence beginning with ESC [ and parameters */
00487         value = cons->c_esc_parmv[0];
00488         switch (c) {
00489             case 'A':           /* ESC [nA moves up n lines */
00490                 n = (value == 0 ? 1 : value);
00491                 cons->c_row -= n;
00492                 flush(cons);
00493                 break;
00494 
00495             case 'B':           /* ESC [nB moves down n lines */
00496                 n = (value == 0 ? 1 : value);
00497                 cons->c_row += n;
00498                 flush(cons);
00499                 break;
00500 
00501             case 'C':           /* ESC [nC moves right n spaces */
00502                 n = (value == 0 ? 1 : value);
00503                 cons->c_column += n;
00504                 flush(cons);
00505                 break;
00506 
00507             case 'D':           /* ESC [nD moves left n spaces */
00508                 n = (value == 0 ? 1 : value);
00509                 cons->c_column -= n;
00510                 flush(cons);
00511                 break;
00512 
00513             case 'H':           /* ESC [m;nH" moves cursor to (m,n) */
00514                 cons->c_row = cons->c_esc_parmv[0] - 1;
00515                 cons->c_column = cons->c_esc_parmv[1] - 1;
00516                 flush(cons);
00517                 break;
00518 
00519             case 'J':           /* ESC [sJ clears in display */
00520                 switch (value) {
00521                     case 0:     /* Clear from cursor to end of screen */
00522                         count = scr_size - (cons->c_cur - cons->c_org);
00523                         dst = cons->c_cur;
00524                         break;
00525                     case 1:     /* Clear from start of screen to cursor */
00526                         count = cons->c_cur - cons->c_org;
00527                         dst = cons->c_org;
00528                         break;
00529                     case 2:     /* Clear entire screen */
00530                         count = scr_size;
00531                         dst = cons->c_org;
00532                         break;
00533                     default:    /* Do nothing */
00534                         count = 0;
00535                         dst = cons->c_org;
00536                 }
00537                 blank_color = cons->c_blank;
00538                 mem_vid_copy(BLANK_MEM, dst, count);
00539                 break;
00540 
00541             case 'K':           /* ESC [sK clears line from cursor */
00542                 switch (value) {
00543                     case 0:     /* Clear from cursor to end of line */
00544                         count = scr_width - cons->c_column;
00545                         dst = cons->c_cur;
00546                         break;
00547                     case 1:     /* Clear from beginning of line to cursor */
00548                         count = cons->c_column;
00549                         dst = cons->c_cur - cons->c_column;
00550                         break;
00551                     case 2:     /* Clear entire line */
00552                         count = scr_width;
00553                         dst = cons->c_cur - cons->c_column;
00554                         break;
00555                     default:    /* Do nothing */
00556                         count = 0;
00557                         dst = cons->c_cur;
00558                 }
00559                 blank_color = cons->c_blank;
00560                 mem_vid_copy(BLANK_MEM, dst, count);
00561                 break;
00562 
00563             case 'L':           /* ESC [nL inserts n lines at cursor */
00564                 n = value;
00565                 if (n < 1) n = 1;
00566                 if (n > (scr_lines - cons->c_row))
00567                         n = scr_lines - cons->c_row;
00568 
00569                 src = cons->c_org + cons->c_row * scr_width;
00570                 dst = src + n * scr_width;
00571                 count = (scr_lines - cons->c_row - n) * scr_width;
00572                 vid_vid_copy(src, dst, count);
00573                 blank_color = cons->c_blank;
00574                 mem_vid_copy(BLANK_MEM, src, n * scr_width);
00575                 break;
00576 
00577             case 'M':           /* ESC [nM deletes n lines at cursor */
00578                 n = value;
00579                 if (n < 1) n = 1;
00580                 if (n > (scr_lines - cons->c_row))
00581                         n = scr_lines - cons->c_row;
00582 
00583                 dst = cons->c_org + cons->c_row * scr_width;
00584                 src = dst + n * scr_width;
00585                 count = (scr_lines - cons->c_row - n) * scr_width;
00586                 vid_vid_copy(src, dst, count);
00587                 blank_color = cons->c_blank;
00588                 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
00589                 break;
00590 
00591             case '@':           /* ESC [n@ inserts n chars at cursor */
00592                 n = value;
00593                 if (n < 1) n = 1;
00594                 if (n > (scr_width - cons->c_column))
00595                         n = scr_width - cons->c_column;
00596 
00597                 src = cons->c_cur;
00598                 dst = src + n;
00599                 count = scr_width - cons->c_column - n;
00600                 vid_vid_copy(src, dst, count);
00601                 blank_color = cons->c_blank;
00602                 mem_vid_copy(BLANK_MEM, src, n);
00603                 break;
00604 
00605             case 'P':           /* ESC [nP deletes n chars at cursor */
00606                 n = value;
00607                 if (n < 1) n = 1;
00608                 if (n > (scr_width - cons->c_column))
00609                         n = scr_width - cons->c_column;
00610 
00611                 dst = cons->c_cur;
00612                 src = dst + n;
00613                 count = scr_width - cons->c_column - n;
00614                 vid_vid_copy(src, dst, count);
00615                 blank_color = cons->c_blank;
00616                 mem_vid_copy(BLANK_MEM, dst + count, n);
00617                 break;
00618 
00619             case 'm':           /* ESC [nm enables rendition n */
00620                 for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
00621                                 && parmp < bufend(cons->c_esc_parmv); parmp++) {
00622                         if (cons->c_reverse) {
00623                                 /* Unswap fg and bg colors */
00624                                 cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
00625                                                 ((cons->c_attr & 0x0700) << 4) |
00626                                                 ((cons->c_attr & 0x8800));
00627                         }
00628                         switch (n = *parmp) {
00629                             case 0:     /* NORMAL */
00630                                 cons->c_attr = cons->c_blank = BLANK_COLOR;
00631                                 cons->c_reverse = FALSE;
00632                                 break;
00633 
00634                             case 1:     /* BOLD  */
00635                                 /* Set intensity bit */
00636                                 cons->c_attr |= 0x0800;
00637                                 break;
00638 
00639                             case 4:     /* UNDERLINE */
00640                                 if (color) {
00641                                         /* Change white to cyan, i.e. lose red
00642                                          */
00643                                         cons->c_attr = (cons->c_attr & 0xBBFF);
00644                                 } else {
00645                                         /* Set underline attribute */
00646                                         cons->c_attr = (cons->c_attr & 0x99FF);
00647                                 }
00648                                 break;
00649 
00650                             case 5:     /* BLINKING */
00651                                 /* Set the blink bit */
00652                                 cons->c_attr |= 0x8000;
00653                                 break;
00654 
00655                             case 7:     /* REVERSE */
00656                                 cons->c_reverse = TRUE;
00657                                 break;
00658 
00659                             default:    /* COLOR */
00660                                 if (n == 39) n = 37;    /* set default color */
00661                                 if (n == 49) n = 40;
00662 
00663                                 if (!color) {
00664                                         /* Don't mess up a monochrome screen */
00665                                 } else
00666                                 if (30 <= n && n <= 37) {
00667                                         /* Foreground color */
00668                                         cons->c_attr =
00669                                                 (cons->c_attr & 0xF8FF) |
00670                                                 (ansi_colors[(n - 30)] << 8);
00671                                         cons->c_blank =
00672                                                 (cons->c_blank & 0xF8FF) |
00673                                                 (ansi_colors[(n - 30)] << 8);
00674                                 } else
00675                                 if (40 <= n && n <= 47) {
00676                                         /* Background color */
00677                                         cons->c_attr =
00678                                                 (cons->c_attr & 0x8FFF) |
00679                                                 (ansi_colors[(n - 40)] << 12);
00680                                         cons->c_blank =
00681                                                 (cons->c_blank & 0x8FFF) |
00682                                                 (ansi_colors[(n - 40)] << 12);
00683                                 }
00684                         }
00685                         if (cons->c_reverse) {
00686                                 /* Swap fg and bg colors */
00687                                 cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
00688                                                 ((cons->c_attr & 0x0700) << 4) |
00689                                                 ((cons->c_attr & 0x8800));
00690                         }
00691                 }
00692                 break;
00693         }
00694   }
00695   cons->c_esc_state = 0;
00696 }
00697 
00698 /*===========================================================================*
00699  *                              set_6845                                     *
00700  *===========================================================================*/
00701 PRIVATE void set_6845(reg, val)
00702 int reg;                        /* which register pair to set */
00703 unsigned val;                   /* 16-bit value to set it to */
00704 {
00705 /* Set a register pair inside the 6845.
00706  * Registers 12-13 tell the 6845 where in video ram to start
00707  * Registers 14-15 tell the 6845 where to put the cursor
00708  */
00709   pvb_pair_t char_out[4];
00710   pv_set(char_out[0], vid_port + INDEX, reg);   /* set index register */
00711   pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE);    /* high byte */
00712   pv_set(char_out[2], vid_port + INDEX, reg + 1);           /* again */
00713   pv_set(char_out[3], vid_port + DATA, val&BYTE);           /* low byte */
00714   sys_voutb(char_out, 4);                       /* do actual output */
00715 }
00716 
00717 /*===========================================================================*
00718  *                              get_6845                                     *
00719  *===========================================================================*/
00720 PRIVATE void get_6845(reg, val)
00721 int reg;                        /* which register pair to set */
00722 unsigned *val;                  /* 16-bit value to set it to */
00723 {
00724   char v1, v2;
00725   unsigned long v;
00726 /* Get a register pair inside the 6845.  */
00727   sys_outb(vid_port + INDEX, reg); 
00728   sys_inb(vid_port + DATA, &v); 
00729   v1 = v;
00730   sys_outb(vid_port + INDEX, reg+1); 
00731   sys_inb(vid_port + DATA, &v); 
00732   v2 = v;
00733   *val = (v1 << 8) | v2;
00734 }
00735 
00736 /*===========================================================================*
00737  *                              beep                                         *
00738  *===========================================================================*/
00739 PRIVATE void beep()
00740 {
00741 /* Making a beeping sound on the speaker (output for CRTL-G).
00742  * This routine works by turning on the bits 0 and 1 in port B of the 8255
00743  * chip that drive the speaker.
00744  */
00745   static timer_t tmr_stop_beep;
00746   pvb_pair_t char_out[3];
00747   clock_t now;
00748   unsigned long port_b_val;
00749   int s;
00750   
00751   /* Fetch current time in advance to prevent beeping delay. */
00752   if ((s=getuptime(&now)) != OK)
00753         panic("TTY","Console couldn't get clock's uptime.", s);
00754   if (!beeping) {
00755         /* Set timer channel 2, square wave, with given frequency. */
00756         pv_set(char_out[0], TIMER_MODE, 0xB6);  
00757         pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
00758         pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
00759         if (sys_voutb(char_out, 3)==OK) {
00760                 if (sys_inb(PORT_B, &port_b_val)==OK &&
00761                     sys_outb(PORT_B, (port_b_val|3))==OK)
00762                         beeping = TRUE;
00763         }
00764   }
00765   /* Add a timer to the timers list. Possibly reschedule the alarm. */
00766   tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
00767   if (tty_timers->tmr_exp_time != tty_next_timeout) {
00768         tty_next_timeout = tty_timers->tmr_exp_time;
00769         if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
00770                 panic("TTY","Console couldn't set alarm.", s);
00771   }
00772 }
00773 
00774 
00775 /*===========================================================================*
00776  *                              do_video                                     *
00777  *===========================================================================*/
00778 PUBLIC void do_video(message *m)
00779 {
00780         int i, n, r, ops, watch;
00781         unsigned char c;
00782 
00783         /* Execute the requested device driver function. */
00784         r= EINVAL;      /* just in case */
00785         switch (m->m_type) {
00786             case DEV_OPEN:
00787                 /* Should grant IOPL */
00788                 r= OK;
00789                 break;
00790             case DEV_CLOSE:
00791                 r= OK;
00792                 break;
00793             case DEV_IOCTL:
00794                 if (m->TTY_REQUEST == MIOCMAP || m->TTY_REQUEST == MIOCUNMAP)
00795                 {
00796                         int r, do_map;
00797                         struct mapreq mapreq;
00798 
00799                         do_map= (m->REQUEST == MIOCMAP);        /* else unmap */
00800 
00801                         /* Get request structure */
00802                         r= sys_vircopy(m->IO_ENDPT, D,
00803                                 (vir_bytes)m->ADDRESS,
00804                                 SELF, D, (vir_bytes)&mapreq, sizeof(mapreq));
00805                         if (r != OK)
00806                         {
00807                                 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT,
00808                                         r);
00809                                 return;
00810                         }
00811                         r= sys_vm_map(m->IO_ENDPT, do_map,
00812                                 (phys_bytes)mapreq.base, mapreq.size,
00813                                 mapreq.offset);
00814                         tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
00815                         return;
00816                 }
00817                 r= ENOTTY;
00818                 break;
00819 
00820             default:            
00821                 printf(
00822                 "Warning, TTY(video) got unexpected request %d from %d\n",
00823                         m->m_type, m->m_source);
00824                 r= EINVAL;
00825         }
00826         tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
00827 }
00828 
00829 
00830 /*===========================================================================*
00831  *                              beep_x                                       *
00832  *===========================================================================*/
00833 PUBLIC void beep_x(freq, dur)
00834 unsigned freq;
00835 clock_t dur;
00836 {
00837 /* Making a beeping sound on the speaker.
00838  * This routine works by turning on the bits 0 and 1 in port B of the 8255
00839  * chip that drive the speaker.
00840  */
00841   static timer_t tmr_stop_beep;
00842   pvb_pair_t char_out[3];
00843   clock_t now;
00844   unsigned long port_b_val;
00845   int s;
00846   
00847   unsigned long ival= TIMER_FREQ / freq;
00848   if (ival == 0 || ival > 0xffff)
00849         return; /* Frequency out of range */
00850 
00851   /* Fetch current time in advance to prevent beeping delay. */
00852   if ((s=getuptime(&now)) != OK)
00853         panic("TTY","Console couldn't get clock's uptime.", s);
00854   if (!beeping) {
00855         /* Set timer channel 2, square wave, with given frequency. */
00856         pv_set(char_out[0], TIMER_MODE, 0xB6);  
00857         pv_set(char_out[1], TIMER2, (ival >> 0) & BYTE);
00858         pv_set(char_out[2], TIMER2, (ival >> 8) & BYTE);
00859         if (sys_voutb(char_out, 3)==OK) {
00860                 if (sys_inb(PORT_B, &port_b_val)==OK &&
00861                     sys_outb(PORT_B, (port_b_val|3))==OK)
00862                         beeping = TRUE;
00863         }
00864   }
00865   /* Add a timer to the timers list. Possibly reschedule the alarm. */
00866   tmrs_settimer(&tty_timers, &tmr_stop_beep, now+dur, stop_beep, NULL);
00867   if (tty_timers->tmr_exp_time != tty_next_timeout) {
00868         tty_next_timeout = tty_timers->tmr_exp_time;
00869         if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
00870                 panic("TTY","Console couldn't set alarm.", s);
00871   }
00872 }
00873 
00874 /*===========================================================================*
00875  *                              stop_beep                                    *
00876  *===========================================================================*/
00877 PRIVATE void stop_beep(tmrp)
00878 timer_t *tmrp;
00879 {
00880 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
00881   unsigned long port_b_val;
00882   if (sys_inb(PORT_B, &port_b_val)==OK && 
00883         sys_outb(PORT_B, (port_b_val & ~3))==OK)
00884                 beeping = FALSE;
00885 }
00886 
00887 /*===========================================================================*
00888  *                              scr_init                                     *
00889  *===========================================================================*/
00890 PUBLIC void scr_init(tp)
00891 tty_t *tp;
00892 {
00893 /* Initialize the screen driver. */
00894   console_t *cons;
00895   phys_bytes vid_base;
00896   u16_t bios_columns, bios_crtbase, bios_fontlines;
00897   u8_t bios_rows;
00898   int line;
00899   int s;
00900   static int vdu_initialized = 0;
00901   unsigned page_size;
00902 
00903   /* Associate console and TTY. */
00904   line = tp - &tty_table[0];
00905   if (line >= nr_cons) return;
00906   cons = &cons_table[line];
00907   cons->c_tty = tp;
00908   tp->tty_priv = cons;
00909 
00910   /* Fill in TTY function hooks. */
00911   tp->tty_devwrite = cons_write;
00912   tp->tty_echo = cons_echo;
00913   tp->tty_ioctl = cons_ioctl;
00914 
00915   /* Get the BIOS parameters that describe the VDU. */
00916   if (! vdu_initialized++) {
00917 
00918         /* How about error checking? What to do on failure??? */
00919         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_COLS_ADDR,
00920                 SELF, D, (vir_bytes) &bios_columns, VDU_SCREEN_COLS_SIZE);
00921         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_CRT_BASE_ADDR, 
00922                 SELF, D, (vir_bytes) &bios_crtbase, VDU_CRT_BASE_SIZE);
00923         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_ROWS_ADDR, 
00924                 SELF, D, (vir_bytes) &bios_rows, VDU_SCREEN_ROWS_SIZE);
00925         s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_FONTLINES_ADDR, 
00926                 SELF, D, (vir_bytes) &bios_fontlines, VDU_FONTLINES_SIZE);
00927 
00928         vid_port = bios_crtbase;
00929         scr_width = bios_columns;
00930         font_lines = bios_fontlines;
00931         scr_lines = machine.vdu_ega ? bios_rows+1 : 25;
00932 
00933         if (color) {
00934                 vid_base = COLOR_BASE;
00935                 vid_size = COLOR_SIZE;
00936         } else {
00937                 vid_base = MONO_BASE;
00938                 vid_size = MONO_SIZE;
00939         }
00940         if (machine.vdu_ega) vid_size = EGA_SIZE;
00941         wrap = ! machine.vdu_ega;
00942 
00943         s = sys_segctl(&vid_index, &vid_seg, &vid_off, vid_base, vid_size);
00944 
00945         vid_size >>= 1;         /* word count */
00946         vid_mask = vid_size - 1;
00947 
00948         /* Size of the screen (number of displayed characters.) */
00949         scr_size = scr_lines * scr_width;
00950 
00951         /* There can be as many consoles as video memory allows. */
00952         nr_cons = vid_size / scr_size;
00953         if (nr_cons > NR_CONS) nr_cons = NR_CONS;
00954         if (nr_cons > 1) wrap = 0;
00955         page_size = vid_size / nr_cons;
00956   }
00957 
00958   cons->c_start = line * page_size;
00959   cons->c_limit = cons->c_start + page_size;
00960   cons->c_cur = cons->c_org = cons->c_start;
00961   cons->c_attr = cons->c_blank = BLANK_COLOR;
00962 
00963   if (line != 0) {
00964         /* Clear the non-console vtys. */
00965         blank_color = BLANK_COLOR;
00966         mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
00967   } else {
00968         int i, n;
00969         /* Set the cursor of the console vty at the bottom. c_cur
00970          * is updated automatically later.
00971          */
00972         scroll_screen(cons, SCROLL_UP);
00973         cons->c_row = scr_lines - 1;
00974         cons->c_column = 0;
00975   }
00976   select_console(0);
00977   cons_ioctl(tp, 0);
00978 }
00979 
00980 /*===========================================================================*
00981  *                              kputc                                        *
00982  *===========================================================================*/
00983 PUBLIC void kputc(c)
00984 int c;
00985 {
00986 /* Accumulate a single character for a kernel message. Send a notification
00987  * the to output driver if an END_OF_KMESS is encountered. 
00988  */
00989 #if 0
00990   ser_putc(c);
00991   return;
00992 #endif
00993 
00994   if (panicing)
00995         cons_putk(c);
00996   if (c != 0) {
00997       kmess.km_buf[kmess.km_next] = c;  /* put normal char in buffer */
00998       if (kmess.km_size < KMESS_BUF_SIZE)
00999           kmess.km_size += 1;           
01000       kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE;
01001   } else {
01002       notify(LOG_PROC_NR);
01003   }
01004 }
01005 
01006 /*===========================================================================*
01007  *                              do_new_kmess                                 *
01008  *===========================================================================*/
01009 PUBLIC void do_new_kmess(m)
01010 message *m;
01011 {
01012 /* Notification for a new kernel message. */
01013   struct kmessages kmess;                       /* kmessages structure */
01014   static int prev_next = 0;                     /* previous next seen */
01015   int size, next;
01016   int bytes;
01017   int r;
01018 
01019   /* Try to get a fresh copy of the buffer with kernel messages. */
01020 #if DEAD_CODE   
01021   /* During shutdown, the reply is garbled because new notifications arrive
01022    * while the system task makes a copy of the kernel messages buffer.
01023    * Hence, don't check the return value. 
01024    */
01025   if ((r=sys_getkmessages(&kmess)) != OK) {
01026         printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r,r);
01027         return;
01028   }
01029 #endif
01030   sys_getkmessages(&kmess);
01031 
01032   /* Print only the new part. Determine how many new bytes there are with 
01033    * help of the current and previous 'next' index. Note that the kernel
01034    * buffer is circular. This works fine if less then KMESS_BUF_SIZE bytes
01035    * is new data; else we miss % KMESS_BUF_SIZE here.  
01036    * Check for size being positive, the buffer might as well be emptied!
01037    */
01038   if (kmess.km_size > 0) {
01039       bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE;
01040       r=prev_next;                              /* start at previous old */ 
01041       while (bytes > 0) {                       
01042           cons_putk( kmess.km_buf[(r%KMESS_BUF_SIZE)] );
01043           bytes --;
01044           r ++;
01045       }
01046       cons_putk(0);                     /* terminate to flush output */
01047   }
01048 
01049   /* Almost done, store 'next' so that we can determine what part of the
01050    * kernel messages buffer to print next time a notification arrives.
01051    */
01052   prev_next = kmess.km_next;
01053 }
01054 
01055 /*===========================================================================*
01056  *                              do_diagnostics                               *
01057  *===========================================================================*/
01058 PUBLIC void do_diagnostics(m_ptr)
01059 message *m_ptr;                 /* pointer to request message */
01060 {
01061 /* Print a string for a server. */
01062   char c;
01063   vir_bytes src;
01064   int count;
01065   int result = OK;
01066   int proc_nr = m_ptr->DIAG_ENDPT;
01067   if (proc_nr == SELF) proc_nr = m_ptr->m_source;
01068 
01069   src = (vir_bytes) m_ptr->DIAG_PRINT_BUF;
01070   for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
01071         if (sys_vircopy(proc_nr, D, src++, SELF, D, (vir_bytes) &c, 1) != OK) {
01072                 result = EFAULT;
01073                 break;
01074         }
01075         cons_putk(c);
01076   }
01077   cons_putk(0);                 /* always terminate, even with EFAULT */
01078   m_ptr->m_type = result;
01079   send(m_ptr->m_source, m_ptr);
01080 }
01081 
01082 /*===========================================================================*
01083  *                              do_get_kmess                                 *
01084  *===========================================================================*/
01085 PUBLIC void do_get_kmess(m_ptr)
01086 message *m_ptr;                 /* pointer to request message */
01087 {
01088 /* Provide the log device with debug output */
01089   vir_bytes dst;
01090   int r;
01091 
01092   dst = (vir_bytes) m_ptr->GETKM_PTR;
01093   r= OK;
01094   if (sys_vircopy(SELF, D, (vir_bytes)&kmess, m_ptr->m_source, D,
01095         dst, sizeof(kmess)) != OK) {
01096         r = EFAULT;
01097   }
01098   m_ptr->m_type = r;
01099   send(m_ptr->m_source, m_ptr);
01100 }
01101 
01102 /*===========================================================================*
01103  *                              cons_putk                                    *
01104  *===========================================================================*/
01105 PRIVATE void cons_putk(c)
01106 int c;                          /* character to print */
01107 {
01108 /* This procedure is used to print a character on the console.
01109  */
01110   if (c != 0) {
01111         if (c == '\n') cons_putk('\r');
01112         out_char(&cons_table[0], (int) c);
01113   } else {
01114         flush(&cons_table[0]);
01115   }
01116 }
01117 
01118 /*===========================================================================*
01119  *                              toggle_scroll                                *
01120  *===========================================================================*/
01121 PUBLIC void toggle_scroll()
01122 {
01123 /* Toggle between hardware and software scroll. */
01124 
01125   cons_org0();
01126   softscroll = !softscroll;
01127   printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
01128 }
01129 
01130 /*===========================================================================*
01131  *                              cons_stop                                    *
01132  *===========================================================================*/
01133 PUBLIC void cons_stop()
01134 {
01135 /* Prepare for halt or reboot. */
01136   cons_org0();
01137   softscroll = 1;
01138   select_console(0);
01139   cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
01140 }
01141 
01142 /*===========================================================================*
01143  *                              cons_org0                                    *
01144  *===========================================================================*/
01145 PRIVATE void cons_org0()
01146 {
01147 /* Scroll video memory back to put the origin at 0. */
01148   int cons_line;
01149   console_t *cons;
01150   unsigned n;
01151 
01152   for (cons_line = 0; cons_line < nr_cons; cons_line++) {
01153         cons = &cons_table[cons_line];
01154         while (cons->c_org > cons->c_start) {
01155                 n = vid_size - scr_size;        /* amount of unused memory */
01156                 if (n > cons->c_org - cons->c_start)
01157                         n = cons->c_org - cons->c_start;
01158                 vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
01159                 cons->c_org -= n;
01160         }
01161         flush(cons);
01162   }
01163   select_console(ccurrent);
01164 }
01165 
01166 /*===========================================================================*
01167  *                              select_console                               *
01168  *===========================================================================*/
01169 PUBLIC void select_console(int cons_line)
01170 {
01171 /* Set the current console to console number 'cons_line'. */
01172 
01173   if (cons_line < 0 || cons_line >= nr_cons) return;
01174   ccurrent = cons_line;
01175   curcons = &cons_table[cons_line];
01176   set_6845(VID_ORG, curcons->c_org);
01177   set_6845(CURSOR, curcons->c_cur);
01178 }
01179 
01180 /*===========================================================================*
01181  *                              con_loadfont                                 *
01182  *===========================================================================*/
01183 PUBLIC int con_loadfont(m)
01184 message *m;
01185 {
01186 /* Load a font into the EGA or VGA adapter. */
01187   int result;
01188   static struct sequence seq1[7] = {
01189         { GA_SEQUENCER_INDEX, 0x00, 0x01 },
01190         { GA_SEQUENCER_INDEX, 0x02, 0x04 },
01191         { GA_SEQUENCER_INDEX, 0x04, 0x07 },
01192         { GA_SEQUENCER_INDEX, 0x00, 0x03 },
01193         { GA_GRAPHICS_INDEX, 0x04, 0x02 },
01194         { GA_GRAPHICS_INDEX, 0x05, 0x00 },
01195         { GA_GRAPHICS_INDEX, 0x06, 0x00 },
01196   };
01197   static struct sequence seq2[7] = {
01198         { GA_SEQUENCER_INDEX, 0x00, 0x01 },
01199         { GA_SEQUENCER_INDEX, 0x02, 0x03 },
01200         { GA_SEQUENCER_INDEX, 0x04, 0x03 },
01201         { GA_SEQUENCER_INDEX, 0x00, 0x03 },
01202         { GA_GRAPHICS_INDEX, 0x04, 0x00 },
01203         { GA_GRAPHICS_INDEX, 0x05, 0x10 },
01204         { GA_GRAPHICS_INDEX, 0x06,    0 },
01205   };
01206 
01207   seq2[6].value= color ? 0x0E : 0x0A;
01208 
01209   if (!machine.vdu_ega) return(ENOTTY);
01210   result = ga_program(seq1);    /* bring font memory into view */
01211 
01212   result = sys_physcopy(m->IO_ENDPT, D, (vir_bytes) m->ADDRESS, 
01213         NONE, PHYS_SEG, (phys_bytes) GA_VIDEO_ADDRESS, (phys_bytes)GA_FONT_SIZE);
01214 
01215   result = ga_program(seq2);    /* restore */
01216 
01217   return(result);
01218 }
01219 
01220 /*===========================================================================*
01221  *                              ga_program                                   *
01222  *===========================================================================*/
01223 PRIVATE int ga_program(seq)
01224 struct sequence *seq;
01225 {
01226   pvb_pair_t char_out[14];
01227   int i;
01228   for (i=0; i<7; i++) {
01229       pv_set(char_out[2*i], seq->index, seq->port);
01230       pv_set(char_out[2*i+1], seq->index+1, seq->value);
01231       seq++;
01232   } 
01233   return sys_voutb(char_out, 14);
01234 }
01235 
01236 /*===========================================================================*
01237  *                              cons_ioctl                                   *
01238  *===========================================================================*/
01239 PRIVATE int cons_ioctl(tp, try)
01240 tty_t *tp;
01241 int try;
01242 {
01243 /* Set the screen dimensions. */
01244 
01245   tp->tty_winsize.ws_row= scr_lines;
01246   tp->tty_winsize.ws_col= scr_width;
01247   tp->tty_winsize.ws_xpixel= scr_width * 8;
01248   tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
01249 }
01250 
01251 #define COM1_BASE       0x3F8
01252 #define COM1_THR        (COM1_BASE + 0)
01253 #define         LSR_THRE        0x20
01254 #define COM1_LSR        (COM1_BASE + 5)
01255 
01256 PRIVATE void ser_putc(char c)
01257 {
01258         unsigned long b;
01259         int i;
01260         int lsr, thr;
01261 
01262         lsr= COM1_LSR;
01263         thr= COM1_THR;
01264         for (i= 0; i<100; i++)
01265         {
01266                 sys_inb(lsr, &b);
01267                 if (b & LSR_THRE)
01268                         break;
01269         }
01270         sys_outb(thr, c);
01271 }

Generated on Fri Apr 14 22:57:19 2006 for minix by  doxygen 1.4.6