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