root/drivers/char/console.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. memcpyw
  2. vc_cons_allocated
  3. vc_allocate
  4. vc_resize
  5. vc_disallocate
  6. gotoxy
  7. __set_origin
  8. scrollback
  9. scrollfront
  10. set_origin
  11. hide_cursor
  12. set_cursor
  13. scrup
  14. scrdown
  15. lf
  16. ri
  17. cr
  18. bs
  19. del
  20. csi_J
  21. csi_K
  22. csi_X
  23. update_attr
  24. default_attr
  25. csi_m
  26. respond_string
  27. cursor_report
  28. status_report
  29. respond_ID
  30. mouse_report
  31. mouse_reporting
  32. screenpos
  33. invert_screen
  34. complement_pos
  35. screen_word
  36. screen_pos
  37. getconsxy
  38. putconsxy
  39. set_mode
  40. setterm_command
  41. insert_char
  42. insert_line
  43. delete_char
  44. delete_line
  45. csi_at
  46. csi_L
  47. csi_P
  48. csi_M
  49. save_cur
  50. restore_cur
  51. reset_terminal
  52. con_stop
  53. con_start
  54. con_write
  55. con_write_room
  56. con_chars_in_buffer
  57. poke_blanked_console
  58. console_print
  59. con_throttle
  60. con_unthrottle
  61. vc_init
  62. con_setsize
  63. con_init
  64. get_scrmem
  65. set_scrmem
  66. do_blank_screen
  67. do_unblank_screen
  68. blank_screen
  69. unblank_screen
  70. update_screen
  71. con_open
  72. set_get_font
  73. con_set_font
  74. con_get_font

   1 /*
   2  *  linux/drivers/char/console.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  *      console.c
   9  *
  10  * This module exports the console io functions:
  11  * 
  12  *     'void do_keyboard_interrupt(void)'
  13  *
  14  *     'int vc_allocate(unsigned int console)' 
  15  *     'int vc_cons_allocated(unsigned int console)'
  16  *     'int vc_resize(unsigned long lines, unsigned long cols)'
  17  *     'void vc_disallocate(unsigned int currcons)'
  18  *
  19  *     'long con_init(long)'
  20  *     'int con_open(struct tty_struct *tty, struct file * filp)'
  21  *     'void con_write(struct tty_struct * tty)'
  22  *     'void console_print(const char * b)'
  23  *     'void update_screen(int new_console)'
  24  *
  25  *     'void do_blank_screen(int)'
  26  *     'void do_unblank_screen(void)'
  27  *     'void poke_blanked_console(void)'
  28  *
  29  *     'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
  30  *     'void complement_pos(int currcons, int offset)'
  31  *     'void invert_screen(int currcons, int offset, int count, int shift)'
  32  *
  33  *     'void scrollback(int lines)'
  34  *     'void scrollfront(int lines)'
  35  *
  36  *     'int con_get_font(char *)' 
  37  *     'int con_set_font(char *)'
  38  *
  39  *     'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
  40  *     'int mouse_reporting(void)'
  41  *
  42  * Hopefully this will be a rather complete VT102 implementation.
  43  *
  44  * Beeping thanks to John T Kohl.
  45  * 
  46  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
  47  *   Chars, and VT100 enhancements by Peter MacDonald.
  48  *
  49  * Copy and paste function by Andrew Haylett,
  50  *   some enhancements by Alessandro Rubini.
  51  *
  52  * User definable mapping table and font loading by Eugene G. Crosser,
  53  * <crosser@pccross.msk.su>
  54  *
  55  * Code to check for different video-cards mostly by Galen Hunt,
  56  * <g-hunt@ee.utah.edu>
  57  *
  58  * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
  59  * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
  60  *
  61  * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
  62  * Resizing of consoles, aeb, 940926
  63  *
  64  * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
  65  * <poe@daimi.aau.dk>
  66  *
  67  */
  68 
  69 #define BLANK 0x0020
  70 #define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
  71 
  72 /* A bitmap for codes <32. A bit of 1 indicates that the code
  73  * corresponding to that bit number invokes some special action
  74  * (such as cursor movement) and should not be displayed as a
  75  * glyph unless the disp_ctrl mode is explicitly enabled.
  76  */
  77 #define CTRL_ACTION 0xd00ff80
  78 
  79 /*
  80  *  NOTE!!! We sometimes disable and enable interrupts for a short while
  81  * (to put a word in video IO), but this will work even for keyboard
  82  * interrupts. We know interrupts aren't enabled when getting a keyboard
  83  * interrupt, as we use trap-gates. Hopefully all is well.
  84  */
  85 
  86 #include <linux/sched.h>
  87 #include <linux/timer.h>
  88 #include <linux/interrupt.h>
  89 #include <linux/tty.h>
  90 #include <linux/tty_flip.h>
  91 #include <linux/config.h>
  92 #include <linux/kernel.h>
  93 #include <linux/string.h>
  94 #include <linux/errno.h>
  95 #include <linux/kd.h>
  96 #include <linux/malloc.h>
  97 #include <linux/major.h>
  98 #include <linux/mm.h>
  99 #include <linux/ioport.h>
 100 
 101 #include <asm/io.h>
 102 #include <asm/system.h>
 103 #include <asm/segment.h>
 104 #include <asm/bitops.h>
 105 
 106 #include "kbd_kern.h"
 107 #include "vt_kern.h"
 108 #include "consolemap.h"
 109 #include "selection.h"
 110 
 111 
 112 #ifndef MIN
 113 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
 114 #endif
 115 
 116 struct tty_driver console_driver;
 117 static int console_refcount;
 118 static struct tty_struct *console_table[MAX_NR_CONSOLES];
 119 static struct termios *console_termios[MAX_NR_CONSOLES];
 120 static struct termios *console_termios_locked[MAX_NR_CONSOLES];
 121 
 122 #define NPAR 16
 123 
 124 static void con_setsize(unsigned long rows, unsigned long cols);
 125 static void vc_init(unsigned int console, unsigned long rows, unsigned long cols,
 126                     int do_clear);
 127 static void get_scrmem(int currcons);
 128 static void set_scrmem(int currcons, long offset);
 129 static void set_origin(int currcons);
 130 static void blank_screen(void);
 131 static void unblank_screen(void);
 132 void poke_blanked_console(void);
 133 static void gotoxy(int currcons, int new_x, int new_y);
 134 static void save_cur(int currcons);
 135 static inline void set_cursor(int currcons);
 136 static void reset_terminal(int currcons, int do_clear);
 137 extern void reset_vc(unsigned int new_console);
 138 extern void vt_init(void);
 139 extern void register_console(void (*proc)(const char *));
 140 extern void vesa_blank(void);
 141 extern void vesa_unblank(void);
 142 extern void compute_shiftstate(void);
 143 extern int conv_uni_to_pc(unsigned long ucs);
 144 
 145 /* Description of the hardware situation */
 146 static unsigned char    video_type;             /* Type of display being used   */
 147 static unsigned long    video_mem_base;         /* Base of video memory         */
 148 static unsigned long    video_mem_term;         /* End of video memory          */
 149 static unsigned char    video_page;             /* Initial video page (unused)  */
 150        /* these two also used in vesa_blank.c */
 151        unsigned short   video_port_reg;         /* Video register select port   */
 152        unsigned short   video_port_val;         /* Video register value port    */
 153        /* these three also used in selection.c */
 154        unsigned long    video_num_columns;      /* Number of text columns       */
 155        unsigned long    video_num_lines;        /* Number of text lines         */
 156        unsigned long    video_size_row;
 157 static unsigned long    video_screen_size;
 158 static int can_do_color = 0;
 159 static int printable = 0;                       /* Is console ready for printing? */
 160 
 161 static unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
 162 
 163 static int console_blanked = 0;
 164 static int blankinterval = 10*60*HZ;
 165 static long blank_origin, blank__origin, unblank_origin;
 166 
 167 struct vc_data {
 168         unsigned long   vc_screenbuf_size;
 169         unsigned short  vc_video_erase_char;    /* Background erase character */
 170         unsigned char   vc_attr;                /* Current attributes */
 171         unsigned char   vc_def_color;           /* Default colors */
 172         unsigned char   vc_color;               /* Foreground & background */
 173         unsigned char   vc_s_color;             /* Saved foreground & background */
 174         unsigned char   vc_ulcolor;             /* Colour for underline mode */
 175         unsigned char   vc_halfcolor;           /* Colour for half intensity mode */
 176         unsigned long   vc_origin;              /* Used for EGA/VGA fast scroll */
 177         unsigned long   vc_scr_end;             /* Used for EGA/VGA fast scroll */
 178         unsigned long   vc_pos;
 179         unsigned long   vc_x,vc_y;
 180         unsigned long   vc_top,vc_bottom;
 181         unsigned long   vc_state;
 182         unsigned long   vc_npar,vc_par[NPAR];
 183         unsigned long   vc_video_mem_start;     /* Start of video RAM           */
 184         unsigned long   vc_video_mem_end;       /* End of video RAM (sort of)   */
 185         unsigned long   vc_saved_x;
 186         unsigned long   vc_saved_y;
 187         /* mode flags */
 188         unsigned long   vc_charset      : 1;    /* Character set G0 / G1 */
 189         unsigned long   vc_s_charset    : 1;    /* Saved character set */
 190         unsigned long   vc_disp_ctrl    : 1;    /* Display chars < 32? */
 191         unsigned long   vc_toggle_meta  : 1;    /* Toggle high bit? */
 192         unsigned long   vc_decscnm      : 1;    /* Screen Mode */
 193         unsigned long   vc_decom        : 1;    /* Origin Mode */
 194         unsigned long   vc_decawm       : 1;    /* Autowrap Mode */
 195         unsigned long   vc_deccm        : 1;    /* Cursor Visible */
 196         unsigned long   vc_decim        : 1;    /* Insert Mode */
 197         unsigned long   vc_deccolm      : 1;    /* 80/132 Column Mode */
 198         /* attribute flags */
 199         unsigned long   vc_intensity    : 2;    /* 0=half-bright, 1=normal, 2=bold */
 200         unsigned long   vc_underline    : 1;
 201         unsigned long   vc_blink        : 1;
 202         unsigned long   vc_reverse      : 1;
 203         unsigned long   vc_s_intensity  : 2;    /* saved rendition */
 204         unsigned long   vc_s_underline  : 1;
 205         unsigned long   vc_s_blink      : 1;
 206         unsigned long   vc_s_reverse    : 1;
 207         /* misc */
 208         unsigned long   vc_ques         : 1;
 209         unsigned long   vc_need_wrap    : 1;
 210         unsigned long   vc_has_scrolled : 1;    /* Info for unblank_screen */
 211         unsigned long   vc_kmalloced    : 1;    /* kfree_s() needed */
 212         unsigned long   vc_report_mouse : 2;
 213         unsigned char   vc_utf          : 1;    /* Unicode UTF-8 encoding */
 214         unsigned char   vc_utf_count;
 215         unsigned long   vc_utf_char;
 216         unsigned long   vc_tab_stop[5];         /* Tab stops. 160 columns. */
 217         unsigned char * vc_translate;
 218         unsigned char   vc_G0_charset;
 219         unsigned char   vc_G1_charset;
 220         unsigned char   vc_saved_G0;
 221         unsigned char   vc_saved_G1;
 222         /* additional information is in vt_kern.h */
 223 };
 224 
 225 static struct vc {
 226         struct vc_data *d;
 227 
 228         /* might add  scrmem, vt_struct, kbd  at some time,
 229            to have everything in one place - the disadvantage
 230            would be that vc_cons etc can no longer be static */
 231 } vc_cons [MAX_NR_CONSOLES];
 232 
 233 #define screenbuf_size  (vc_cons[currcons].d->vc_screenbuf_size)
 234 #define origin          (vc_cons[currcons].d->vc_origin)
 235 #define scr_end         (vc_cons[currcons].d->vc_scr_end)
 236 #define pos             (vc_cons[currcons].d->vc_pos)
 237 #define top             (vc_cons[currcons].d->vc_top)
 238 #define bottom          (vc_cons[currcons].d->vc_bottom)
 239 #define x               (vc_cons[currcons].d->vc_x)
 240 #define y               (vc_cons[currcons].d->vc_y)
 241 #define vc_state        (vc_cons[currcons].d->vc_state)
 242 #define npar            (vc_cons[currcons].d->vc_npar)
 243 #define par             (vc_cons[currcons].d->vc_par)
 244 #define ques            (vc_cons[currcons].d->vc_ques)
 245 #define attr            (vc_cons[currcons].d->vc_attr)
 246 #define saved_x         (vc_cons[currcons].d->vc_saved_x)
 247 #define saved_y         (vc_cons[currcons].d->vc_saved_y)
 248 #define translate       (vc_cons[currcons].d->vc_translate)
 249 #define G0_charset      (vc_cons[currcons].d->vc_G0_charset)
 250 #define G1_charset      (vc_cons[currcons].d->vc_G1_charset)
 251 #define saved_G0        (vc_cons[currcons].d->vc_saved_G0)
 252 #define saved_G1        (vc_cons[currcons].d->vc_saved_G1)
 253 #define utf             (vc_cons[currcons].d->vc_utf)
 254 #define utf_count       (vc_cons[currcons].d->vc_utf_count)
 255 #define utf_char        (vc_cons[currcons].d->vc_utf_char)
 256 #define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
 257 #define video_mem_end   (vc_cons[currcons].d->vc_video_mem_end)
 258 #define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)     
 259 #define disp_ctrl       (vc_cons[currcons].d->vc_disp_ctrl)
 260 #define toggle_meta     (vc_cons[currcons].d->vc_toggle_meta)
 261 #define decscnm         (vc_cons[currcons].d->vc_decscnm)
 262 #define decom           (vc_cons[currcons].d->vc_decom)
 263 #define decawm          (vc_cons[currcons].d->vc_decawm)
 264 #define deccm           (vc_cons[currcons].d->vc_deccm)
 265 #define decim           (vc_cons[currcons].d->vc_decim)
 266 #define deccolm         (vc_cons[currcons].d->vc_deccolm)
 267 #define need_wrap       (vc_cons[currcons].d->vc_need_wrap)
 268 #define has_scrolled    (vc_cons[currcons].d->vc_has_scrolled)
 269 #define kmalloced       (vc_cons[currcons].d->vc_kmalloced)
 270 #define report_mouse    (vc_cons[currcons].d->vc_report_mouse)
 271 #define color           (vc_cons[currcons].d->vc_color)
 272 #define s_color         (vc_cons[currcons].d->vc_s_color)
 273 #define def_color       (vc_cons[currcons].d->vc_def_color)
 274 #define foreground      (color & 0x0f)
 275 #define background      (color & 0xf0)
 276 #define charset         (vc_cons[currcons].d->vc_charset)
 277 #define s_charset       (vc_cons[currcons].d->vc_s_charset)
 278 #define intensity       (vc_cons[currcons].d->vc_intensity)
 279 #define underline       (vc_cons[currcons].d->vc_underline)
 280 #define blink           (vc_cons[currcons].d->vc_blink)
 281 #define reverse         (vc_cons[currcons].d->vc_reverse)
 282 #define s_intensity     (vc_cons[currcons].d->vc_s_intensity)
 283 #define s_underline     (vc_cons[currcons].d->vc_s_underline)
 284 #define s_blink         (vc_cons[currcons].d->vc_s_blink)
 285 #define s_reverse       (vc_cons[currcons].d->vc_s_reverse)
 286 #define ulcolor         (vc_cons[currcons].d->vc_ulcolor)
 287 #define halfcolor       (vc_cons[currcons].d->vc_halfcolor)
 288 #define tab_stop        (vc_cons[currcons].d->vc_tab_stop)
 289 
 290 #define vcmode          (vt_cons[currcons]->vc_mode)
 291 #define structsize      (sizeof(struct vc_data) + sizeof(struct vt_struct))
 292 
 293 static void memsetw(void * s, unsigned short c, unsigned int count)
 294 {
 295         unsigned short * addr = (unsigned short *) s;
 296 
 297         count /= 2;
 298         while (count) {
 299                 count--;
 300                 scr_writew(c, addr++);
 301         }
 302 }
 303 
 304 static inline void memcpyw(unsigned short *to, unsigned short *from,
     /* [previous][next][first][last][top][bottom][index][help] */
 305                            unsigned int count)
 306 {
 307         count /= 2;
 308         while (count) {
 309                 count--;
 310                 scr_writew(scr_readw(from++), to++);
 311         }
 312 }
 313 
 314 int vc_cons_allocated(unsigned int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316         return (i < MAX_NR_CONSOLES && vc_cons[i].d);
 317 }
 318 
 319 int vc_allocate(unsigned int i)         /* return 0 on success */
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         if (i >= MAX_NR_CONSOLES)
 322           return -ENODEV;
 323         if (!vc_cons[i].d) {
 324             long p, q;
 325 
 326             /* prevent users from taking too much memory */
 327             if (i >= MAX_NR_USER_CONSOLES && !suser())
 328               return -EPERM;
 329 
 330             /* due to the granularity of kmalloc, we waste some memory here */
 331             /* the alloc is done in two steps, to optimize the common situation
 332                of a 25x80 console (structsize=216, video_screen_size=4000) */
 333             q = (long) kmalloc(video_screen_size, GFP_KERNEL);
 334             if (!q)
 335               return -ENOMEM;
 336             p = (long) kmalloc(structsize, GFP_KERNEL);
 337             if (!p) {
 338                 kfree_s((char *) q, video_screen_size);
 339                 return -ENOMEM;
 340             }
 341 
 342             vc_cons[i].d = (struct vc_data *) p;
 343             p += sizeof(struct vc_data);
 344             vt_cons[i] = (struct vt_struct *) p;
 345             vc_scrbuf[i] = (unsigned short *) q;
 346             vc_cons[i].d->vc_kmalloced = 1;
 347             vc_cons[i].d->vc_screenbuf_size = video_screen_size;
 348             vc_init (i, video_num_lines, video_num_columns, 1);
 349         }
 350         return 0;
 351 }
 352 
 353 /*
 354  * Change # of rows and columns (0 means unchanged)
 355  * [this is to be used together with some user program
 356  * like resize that changes the hardware videomode]
 357  */
 358 int vc_resize(unsigned long lines, unsigned long cols)
     /* [previous][next][first][last][top][bottom][index][help] */
 359 {
 360         unsigned long cc, ll, ss, sr;
 361         unsigned long occ, oll, oss, osr;
 362         unsigned short *p;
 363         unsigned int currcons, i;
 364         unsigned short *newscreens[MAX_NR_CONSOLES];
 365         long ol, nl, rlth, rrem;
 366 
 367         cc = (cols ? cols : video_num_columns);
 368         ll = (lines ? lines : video_num_lines);
 369         sr = cc << 1;
 370         ss = sr * ll;
 371 
 372         if (ss > video_mem_term - video_mem_base)
 373           return -ENOMEM;
 374 
 375         /*
 376          * Some earlier version had all consoles of potentially
 377          * different sizes, but that was really messy.
 378          * So now we only change if there is room for all consoles
 379          * of the same size.
 380          */
 381         for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
 382             if (!vc_cons_allocated(currcons))
 383               newscreens[currcons] = 0;
 384             else {
 385                 p = (unsigned short *) kmalloc(ss, GFP_USER);
 386                 if (!p) {
 387                     for (i = 0; i< currcons; i++)
 388                       if (newscreens[i])
 389                         kfree_s(newscreens[i], ss);
 390                     return -ENOMEM;
 391                 }
 392                 newscreens[currcons] = p;
 393             }
 394         }
 395 
 396         get_scrmem(fg_console);
 397 
 398         oll = video_num_lines;
 399         occ = video_num_columns;
 400         osr = video_size_row;
 401         oss = video_screen_size;
 402 
 403         video_num_lines = ll;
 404         video_num_columns = cc;
 405         video_size_row = sr;
 406         video_screen_size = ss;
 407 
 408         for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
 409             if (!vc_cons_allocated(currcons))
 410               continue;
 411 
 412             rlth = MIN(osr, sr);
 413             rrem = sr - rlth;
 414             ol = origin;
 415             nl = (long) newscreens[currcons];
 416             if (ll < oll)
 417               ol += (oll - ll) * osr;
 418 
 419             while (ol < scr_end) {
 420                 memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
 421                 if (rrem)
 422                   memsetw((void *)(nl + rlth), video_erase_char, rrem);
 423                 ol += osr;
 424                 nl += sr;
 425             }
 426 
 427             if (kmalloced)
 428               kfree_s(vc_scrbuf[currcons], screenbuf_size);
 429             vc_scrbuf[currcons] = newscreens[currcons];
 430             kmalloced = 1;
 431             screenbuf_size = ss;
 432 
 433             origin = video_mem_start = (long) vc_scrbuf[currcons];
 434             scr_end = video_mem_end = video_mem_start + ss;
 435 
 436             if (scr_end > nl)
 437               memsetw((void *) nl, video_erase_char, scr_end - nl);
 438 
 439             /* do part of a reset_terminal() */
 440             top = 0;
 441             bottom = video_num_lines;
 442             gotoxy(currcons, x, y);
 443             save_cur(currcons);
 444         }
 445 
 446         set_scrmem(fg_console, 0);
 447         set_origin(fg_console);
 448         set_cursor(fg_console);
 449 
 450         return 0;
 451 }
 452 
 453 void vc_disallocate(unsigned int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 454 {
 455         if (vc_cons_allocated(currcons)) {
 456             if (kmalloced)
 457               kfree_s(vc_scrbuf[currcons], screenbuf_size);
 458             if (currcons >= MIN_NR_CONSOLES)
 459               kfree_s(vc_cons[currcons].d, structsize);
 460             vc_cons[currcons].d = 0;
 461         }
 462 }
 463 
 464 
 465 #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
 466 #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
 467 #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
 468 
 469 #define decarm          VC_REPEAT
 470 #define decckm          VC_CKMODE
 471 #define kbdapplic       VC_APPLIC
 472 #define lnm             VC_CRLF
 473 
 474 /*
 475  * this is what the terminal answers to a ESC-Z or csi0c query.
 476  */
 477 #define VT100ID "\033[?1;2c"
 478 #define VT102ID "\033[?6c"
 479 
 480 static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
 481                                        8,12,10,14, 9,13,11,15 };
 482 
 483 /*
 484  * gotoxy() must verify all boundaries, because the arguments
 485  * might also be negative. If the given position is out of
 486  * bounds, the cursor is placed at the nearest margin.
 487  */
 488 static void gotoxy(int currcons, int new_x, int new_y)
     /* [previous][next][first][last][top][bottom][index][help] */
 489 {
 490         int max_y;
 491 
 492         if (new_x < 0)
 493                 x = 0;
 494         else
 495                 if (new_x >= video_num_columns)
 496                         x = video_num_columns - 1;
 497                 else
 498                         x = new_x;
 499         if (decom) {
 500                 new_y += top;
 501                 max_y = bottom;
 502         } else
 503                 max_y = video_num_lines;
 504         if (new_y < 0)
 505                 y = 0;
 506         else
 507                 if (new_y >= max_y)
 508                         y = max_y - 1;
 509                 else
 510                         y = new_y;
 511         pos = origin + y*video_size_row + (x<<1);
 512         need_wrap = 0;
 513 }
 514 
 515 /*
 516  * *Very* limited hardware scrollback support..
 517  */
 518 static unsigned short __real_origin;
 519 static unsigned short __origin;         /* offset of currently displayed screen */
 520 
 521 static inline void __set_origin(unsigned short offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523         unsigned long flags;
 524 
 525         clear_selection();
 526 
 527         save_flags(flags); cli();
 528         __origin = offset;
 529         outb_p(12, video_port_reg);
 530         outb_p(offset >> 8, video_port_val);
 531         outb_p(13, video_port_reg);
 532         outb_p(offset, video_port_val);
 533         restore_flags(flags);
 534 }
 535 
 536 void scrollback(int lines)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538         if (!lines)
 539                 lines = video_num_lines/2;
 540         lines *= video_num_columns;
 541         lines = __origin - lines;
 542         if (lines < 0)
 543                 lines = 0;
 544         __set_origin(lines);
 545 }
 546 
 547 void scrollfront(int lines)
     /* [previous][next][first][last][top][bottom][index][help] */
 548 {
 549         if (!lines)
 550                 lines = video_num_lines/2;
 551         lines *= video_num_columns;
 552         lines = __origin + lines;
 553         if (lines > __real_origin)
 554                 lines = __real_origin;
 555         __set_origin(lines);
 556 }
 557 
 558 static void set_origin(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 559 {
 560         if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
 561                 return;
 562         if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 563                 return;
 564         __real_origin = (origin-video_mem_base) >> 1;
 565         __set_origin(__real_origin);
 566 }
 567 
 568 /*
 569  * Put the cursor just beyond the end of the display adaptor memory.
 570  */
 571 static inline void hide_cursor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 572 {
 573   /* This is inefficient, we could just put the cursor at 0xffff,
 574      but perhaps the delays due to the inefficiency are useful for
 575      some hardware... */
 576         outb_p(14, video_port_reg);
 577         outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
 578         outb_p(15, video_port_reg);
 579         outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
 580 }
 581 
 582 static inline void set_cursor(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584         unsigned long flags;
 585 
 586         if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 587                 return;
 588         if (__real_origin != __origin)
 589                 __set_origin(__real_origin);
 590         save_flags(flags); cli();
 591         if (deccm) {
 592                 outb_p(14, video_port_reg);
 593                 outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
 594                 outb_p(15, video_port_reg);
 595                 outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 596         } else
 597                 hide_cursor();
 598         restore_flags(flags);
 599 }
 600 
 601 static void scrup(int currcons, unsigned int t, unsigned int b)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603         int hardscroll = 1;
 604 
 605         if (b > video_num_lines || t >= b)
 606                 return;
 607         if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
 608                 hardscroll = 0;
 609         else if (t || b != video_num_lines)
 610                 hardscroll = 0;
 611         if (hardscroll) {
 612                 origin += video_size_row;
 613                 pos += video_size_row;
 614                 scr_end += video_size_row;
 615                 if (scr_end > video_mem_end) {
 616                         unsigned short * d = (unsigned short *) video_mem_start;
 617                         unsigned short * s = (unsigned short *) origin;
 618                         unsigned int count;
 619 
 620                         count = (video_num_lines-1)*video_num_columns;
 621                         while (count) {
 622                                 count--;
 623                                 scr_writew(scr_readw(s++),d++);
 624                         }
 625                         count = video_num_columns;
 626                         while (count) {
 627                                 count--;
 628                                 scr_writew(video_erase_char, d++);
 629                         }
 630                         scr_end -= origin-video_mem_start;
 631                         pos -= origin-video_mem_start;
 632                         origin = video_mem_start;
 633                         has_scrolled = 1;
 634                 } else {
 635                         unsigned short * d;
 636                         unsigned int count;
 637 
 638                         d = (unsigned short *) (scr_end - video_size_row);
 639                         count = video_num_columns;
 640                         while (count) {
 641                                 count--;
 642                                 scr_writew(video_erase_char, d++);
 643                         }
 644                 }
 645                 set_origin(currcons);
 646         } else {
 647                 unsigned short * d = (unsigned short *) (origin+video_size_row*t);
 648                 unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1));
 649                 unsigned int count = (b-t-1) * video_num_columns;
 650 
 651                 while (count) {
 652                         count--;
 653                         scr_writew(scr_readw(s++), d++);
 654                 }
 655                 count = video_num_columns;
 656                 while (count) {
 657                         count--;
 658                         scr_writew(video_erase_char, d++);
 659                 }
 660         }
 661 }
 662 
 663 static void scrdown(int currcons, unsigned int t, unsigned int b)
     /* [previous][next][first][last][top][bottom][index][help] */
 664 {
 665         unsigned short *d, *s;
 666         unsigned int count;
 667 
 668         if (b > video_num_lines || t >= b)
 669                 return;
 670         d = (unsigned short *) (origin+video_size_row*b);
 671         s = (unsigned short *) (origin+video_size_row*(b-1));
 672         count = (b-t-1)*video_num_columns;
 673         while (count) {
 674                 count--;
 675                 scr_writew(scr_readw(--s), --d);
 676         }
 677         count = video_num_columns;
 678         while (count) {
 679                 count--;
 680                 scr_writew(video_erase_char, --d);
 681         }
 682         has_scrolled = 1;
 683 }
 684 
 685 static void lf(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 686 {
 687         /* don't scroll if above bottom of scrolling region, or
 688          * if below scrolling region
 689          */
 690         if (y+1 == bottom)
 691                 scrup(currcons,top,bottom);
 692         else if (y < video_num_lines-1) {
 693                 y++;
 694                 pos += video_size_row;
 695         }
 696         need_wrap = 0;
 697 }
 698 
 699 static void ri(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 700 {
 701         /* don't scroll if below top of scrolling region, or
 702          * if above scrolling region
 703          */
 704         if (y == top)
 705                 scrdown(currcons,top,bottom);
 706         else if (y > 0) {
 707                 y--;
 708                 pos -= video_size_row;
 709         }
 710         need_wrap = 0;
 711 }
 712 
 713 static inline void cr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 714 {
 715         pos -= x<<1;
 716         need_wrap = x = 0;
 717 }
 718 
 719 static inline void bs(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 720 {
 721         if (x) {
 722                 pos -= 2;
 723                 x--;
 724                 need_wrap = 0;
 725         }
 726 }
 727 
 728 static inline void del(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 729 {
 730         /* ignored */
 731 }
 732 
 733 static void csi_J(int currcons, int vpar)
     /* [previous][next][first][last][top][bottom][index][help] */
 734 {
 735         unsigned long count;
 736         unsigned short * start;
 737 
 738         switch (vpar) {
 739                 case 0: /* erase from cursor to end of display */
 740                         count = (scr_end-pos)>>1;
 741                         start = (unsigned short *) pos;
 742                         break;
 743                 case 1: /* erase from start to cursor */
 744                         count = ((pos-origin)>>1)+1;
 745                         start = (unsigned short *) origin;
 746                         break;
 747                 case 2: /* erase whole display */
 748                         count = video_num_columns * video_num_lines;
 749                         start = (unsigned short *) origin;
 750                         break;
 751                 default:
 752                         return;
 753         }
 754         while (count) {
 755                 count--;
 756                 scr_writew(video_erase_char, start++);
 757         }
 758         need_wrap = 0;
 759 }
 760 
 761 static void csi_K(int currcons, int vpar)
     /* [previous][next][first][last][top][bottom][index][help] */
 762 {
 763         unsigned long count;
 764         unsigned short * start;
 765 
 766         switch (vpar) {
 767                 case 0: /* erase from cursor to end of line */
 768                         count = video_num_columns-x;
 769                         start = (unsigned short *) pos;
 770                         break;
 771                 case 1: /* erase from start of line to cursor */
 772                         start = (unsigned short *) (pos - (x<<1));
 773                         count = x+1;
 774                         break;
 775                 case 2: /* erase whole line */
 776                         start = (unsigned short *) (pos - (x<<1));
 777                         count = video_num_columns;
 778                         break;
 779                 default:
 780                         return;
 781         }
 782         while (count) {
 783                 count--;
 784                 scr_writew(video_erase_char, start++);
 785         }
 786         need_wrap = 0;
 787 }
 788 
 789 static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
     /* [previous][next][first][last][top][bottom][index][help] */
 790 {                                         /* not vt100? */
 791         unsigned long count;
 792         unsigned short * start;
 793 
 794         if (!vpar)
 795                 vpar++;
 796 
 797         start = (unsigned short *) pos;
 798         count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
 799 
 800         while (count) {
 801                 count--;
 802                 scr_writew(video_erase_char, start++);
 803         }
 804         need_wrap = 0;
 805 }
 806 
 807 static void update_attr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 808 {
 809         attr = color;
 810         if (can_do_color) {
 811                 if (underline)
 812                         attr = (attr & 0xf0) | ulcolor;
 813                 else if (intensity == 0)
 814                         attr = (attr & 0xf0) | halfcolor;
 815         }
 816         if (reverse ^ decscnm)
 817                 attr = reverse_video_char(attr);
 818         if (blink)
 819                 attr ^= 0x80;
 820         if (intensity == 2)
 821                 attr ^= 0x08;
 822         if (!can_do_color) {
 823                 if (underline)
 824                         attr = (attr & 0xf8) | 0x01;
 825                 else if (intensity == 0)
 826                         attr = (attr & 0xf0) | 0x08;
 827         }
 828         if (decscnm)
 829                 video_erase_char = (reverse_video_char(color) << 8) | ' ';
 830         else
 831                 video_erase_char = (color << 8) | ' ';
 832 }
 833 
 834 static void default_attr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 835 {
 836         intensity = 1;
 837         underline = 0;
 838         reverse = 0;
 839         blink = 0;
 840         color = def_color;
 841 }
 842 
 843 static void csi_m(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 844 {
 845         int i;
 846 
 847         for (i=0;i<=npar;i++)
 848                 switch (par[i]) {
 849                         case 0: /* all attributes off */
 850                                 default_attr(currcons);
 851                                 break;
 852                         case 1:
 853                                 intensity = 2;
 854                                 break;
 855                         case 2:
 856                                 intensity = 0;
 857                                 break;
 858                         case 4:
 859                                 underline = 1;
 860                                 break;
 861                         case 5:
 862                                 blink = 1;
 863                                 break;
 864                         case 7:
 865                                 reverse = 1;
 866                                 break;
 867                         case 10: /* ANSI X3.64-1979 (SCO-ish?)
 868                                   * Select primary font, don't display
 869                                   * control chars if defined, don't set
 870                                   * bit 8 on output.
 871                                   */
 872                                 translate = set_translate(charset == 0
 873                                                 ? G0_charset
 874                                                 : G1_charset);
 875                                 disp_ctrl = 0;
 876                                 toggle_meta = 0;
 877                                 break;
 878                         case 11: /* ANSI X3.64-1979 (SCO-ish?)
 879                                   * Select first alternate font, let's
 880                                   * chars < 32 be displayed as ROM chars.
 881                                   */
 882                                 translate = set_translate(NULL_MAP);
 883                                 disp_ctrl = 1;
 884                                 toggle_meta = 0;
 885                                 break;
 886                         case 12: /* ANSI X3.64-1979 (SCO-ish?)
 887                                   * Select second alternate font, toggle
 888                                   * high bit before displaying as ROM char.
 889                                   */
 890                                 translate = set_translate(NULL_MAP);
 891                                 disp_ctrl = 1;
 892                                 toggle_meta = 1;
 893                                 break;
 894                         case 21:
 895                         case 22:
 896                                 intensity = 1;
 897                                 break;
 898                         case 24:
 899                                 underline = 0;
 900                                 break;
 901                         case 25:
 902                                 blink = 0;
 903                                 break;
 904                         case 27:
 905                                 reverse = 0;
 906                                 break;
 907                         case 38: /* ANSI X3.64-1979 (SCO-ish?)
 908                                   * Enables underscore, white foreground
 909                                   * with white underscore (Linux - use
 910                                   * default foreground).
 911                                   */
 912                                 color = (def_color & 0x0f) | background;
 913                                 underline = 1;
 914                                 break;
 915                         case 39: /* ANSI X3.64-1979 (SCO-ish?)
 916                                   * Disable underline option.
 917                                   * Reset colour to default? It did this
 918                                   * before...
 919                                   */
 920                                 color = (def_color & 0x0f) | background;
 921                                 underline = 0;
 922                                 break;
 923                         case 49:
 924                                 color = (def_color & 0xf0) | foreground;
 925                                 break;
 926                         default:
 927                                 if (par[i] >= 30 && par[i] <= 37)
 928                                         color = color_table[par[i]-30]
 929                                                 | background; 
 930                                 else if (par[i] >= 40 && par[i] <= 47)
 931                                         color = (color_table[par[i]-40]<<4)
 932                                                 | foreground;
 933                                 break;
 934                 }
 935         update_attr(currcons);
 936 }
 937 
 938 static void respond_string(char * p, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 939 {
 940         while (*p) {
 941                 tty_insert_flip_char(tty, *p, 0);
 942                 p++;
 943         }
 944         tty_schedule_flip(tty);
 945 }
 946 
 947 static void cursor_report(int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 948 {
 949         char buf[40];
 950 
 951         sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
 952         respond_string(buf, tty);
 953 }
 954 
 955 static inline void status_report(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 956 {
 957         respond_string("\033[0n", tty); /* Terminal ok */
 958 }
 959 
 960 static inline void respond_ID(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 961 {
 962         respond_string(VT102ID, tty);
 963 }
 964 
 965 void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
     /* [previous][next][first][last][top][bottom][index][help] */
 966 {
 967         char buf[8];
 968 
 969         sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
 970                 (char)('!' + mry));
 971         respond_string(buf, tty);
 972 }
 973 
 974 /* invoked via ioctl(TIOCLINUX) */
 975 int mouse_reporting(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 976 {
 977         int currcons = fg_console;
 978 
 979         return report_mouse;
 980 }
 981 
 982 static inline unsigned short *screenpos(int currcons, int offset, int viewed)
     /* [previous][next][first][last][top][bottom][index][help] */
 983 {
 984         unsigned short *p = (unsigned short *)(origin + offset);
 985         if (viewed && currcons == fg_console)
 986                 p -= (__real_origin - __origin);
 987         return p;
 988 }
 989 
 990 /* Note: inverting the screen twice should revert to the original state */
 991 void invert_screen(int currcons, int offset, int count, int viewed)
     /* [previous][next][first][last][top][bottom][index][help] */
 992 {
 993         unsigned short *p;
 994 
 995         count /= 2;
 996         p = screenpos(currcons, offset, viewed);
 997         if (can_do_color)
 998                 while (count--) {
 999                         unsigned short old = scr_readw(p);
1000                         scr_writew(reverse_video_short(old), p);
1001                         p++;
1002                 }
1003         else
1004                 while (count--) {
1005                         unsigned short old = scr_readw(p);
1006                         scr_writew(old ^ (((old & 0x0700) == 0x0100)
1007                                           ? 0x7000 : 0x7700), p);
1008                 }
1009 }
1010 
1011 /* used by selection: complement pointer position */
1012 void complement_pos(int currcons, int offset)
     /* [previous][next][first][last][top][bottom][index][help] */
1013 {
1014         static unsigned short *p = NULL;
1015         static unsigned short old = 0;
1016 
1017         if (p)
1018                 scr_writew(old, p);
1019         if (offset == -1)
1020                 p = NULL;
1021         else {
1022                 p = screenpos(currcons, offset, 1);
1023                 old = scr_readw(p);
1024                 scr_writew(old ^ 0x7700, p);
1025         }
1026 }
1027 
1028 /* used by selection */
1029 unsigned short screen_word(int currcons, int offset, int viewed)
     /* [previous][next][first][last][top][bottom][index][help] */
1030 {
1031         return scr_readw(screenpos(currcons, offset, viewed));
1032 }
1033 
1034 /* used by vcs - note the word offset */
1035 unsigned short *screen_pos(int currcons, int w_offset, int viewed)
     /* [previous][next][first][last][top][bottom][index][help] */
1036 {
1037         return screenpos(currcons, 2 * w_offset, viewed);
1038 }
1039 
1040 void getconsxy(int currcons, char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1041 {
1042         p[0] = x;
1043         p[1] = y;
1044 }
1045 
1046 void putconsxy(int currcons, char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1047 {
1048         gotoxy(currcons, p[0], p[1]);
1049         set_cursor(currcons);
1050 }
1051 
1052 static void set_mode(int currcons, int on_off)
     /* [previous][next][first][last][top][bottom][index][help] */
1053 {
1054         int i;
1055 
1056         for (i=0; i<=npar; i++)
1057                 if (ques) switch(par[i]) {      /* DEC private modes set/reset */
1058                         case 1:                 /* Cursor keys send ^[Ox/^[[x */
1059                                 if (on_off)
1060                                         set_kbd(decckm);
1061                                 else
1062                                         clr_kbd(decckm);
1063                                 break;
1064                         case 3: /* 80/132 mode switch unimplemented */
1065                                 deccolm = on_off;
1066 #if 0
1067                                 (void) vc_resize(video_num_lines, deccolm ? 132 : 80);
1068                                 /* this alone does not suffice; some user mode
1069                                    utility has to change the hardware regs */
1070 #endif
1071                                 break;
1072                         case 5:                 /* Inverted screen on/off */
1073                                 if (decscnm != on_off) {
1074                                         decscnm = on_off;
1075                                         invert_screen(currcons, 0, video_screen_size, 0);
1076                                         update_attr(currcons);
1077                                 }
1078                                 break;
1079                         case 6:                 /* Origin relative/absolute */
1080                                 decom = on_off;
1081                                 gotoxy(currcons,0,0);
1082                                 break;
1083                         case 7:                 /* Autowrap on/off */
1084                                 decawm = on_off;
1085                                 break;
1086                         case 8:                 /* Autorepeat on/off */
1087                                 if (on_off)
1088                                         set_kbd(decarm);
1089                                 else
1090                                         clr_kbd(decarm);
1091                                 break;
1092                         case 9:
1093                                 report_mouse = on_off ? 1 : 0;
1094                                 break;
1095                         case 25:                /* Cursor on/off */
1096                                 deccm = on_off;
1097                                 set_cursor(currcons);
1098                                 break;
1099                         case 1000:
1100                                 report_mouse = on_off ? 2 : 0;
1101                                 break;
1102                 } else switch(par[i]) {         /* ANSI modes set/reset */
1103                         case 3:                 /* Monitor (display ctrls) */
1104                                 disp_ctrl = on_off;
1105                                 break;
1106                         case 4:                 /* Insert Mode on/off */
1107                                 decim = on_off;
1108                                 break;
1109                         case 20:                /* Lf, Enter == CrLf/Lf */
1110                                 if (on_off)
1111                                         set_kbd(lnm);
1112                                 else
1113                                         clr_kbd(lnm);
1114                                 break;
1115                 }
1116 }
1117 
1118 static void setterm_command(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1119 {
1120         switch(par[0]) {
1121                 case 1: /* set color for underline mode */
1122                         if (can_do_color && par[1] < 16) {
1123                                 ulcolor = color_table[par[1]];
1124                                 if (underline)
1125                                         update_attr(currcons);
1126                         }
1127                         break;
1128                 case 2: /* set color for half intensity mode */
1129                         if (can_do_color && par[1] < 16) {
1130                                 halfcolor = color_table[par[1]];
1131                                 if (intensity == 0)
1132                                         update_attr(currcons);
1133                         }
1134                         break;
1135                 case 8: /* store colors as defaults */
1136                         def_color = attr;
1137                         default_attr(currcons);
1138                         update_attr(currcons);
1139                         break;
1140                 case 9: /* set blanking interval */
1141                         blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1142                         poke_blanked_console();
1143                         break;
1144         }
1145 }
1146 
1147 static void insert_char(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1148 {
1149         unsigned int i = x;
1150         unsigned short tmp, old = video_erase_char;
1151         unsigned short * p = (unsigned short *) pos;
1152 
1153         while (i++ < video_num_columns) {
1154                 tmp = scr_readw(p);
1155                 scr_writew(old, p);
1156                 old = tmp;
1157                 p++;
1158         }
1159         need_wrap = 0;
1160 }
1161 
1162 static void insert_line(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1163 {
1164         scrdown(currcons,y,bottom);
1165         need_wrap = 0;
1166 }
1167 
1168 static void delete_char(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1169 {
1170         unsigned int i = x;
1171         unsigned short * p = (unsigned short *) pos;
1172 
1173         while (++i < video_num_columns) {
1174                 scr_writew(scr_readw(p+1), p);
1175                 p++;
1176         }
1177         scr_writew(video_erase_char, p);
1178         need_wrap = 0;
1179 }
1180 
1181 static void delete_line(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1182 {
1183         scrup(currcons,y,bottom);
1184         need_wrap = 0;
1185 }
1186 
1187 static void csi_at(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
1188 {
1189         if (nr > video_num_columns)
1190                 nr = video_num_columns;
1191         else if (!nr)
1192                 nr = 1;
1193         while (nr--)
1194                 insert_char(currcons);
1195 }
1196 
1197 static void csi_L(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
1198 {
1199         if (nr > video_num_lines)
1200                 nr = video_num_lines;
1201         else if (!nr)
1202                 nr = 1;
1203         while (nr--)
1204                 insert_line(currcons);
1205 }
1206 
1207 static void csi_P(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
1208 {
1209         if (nr > video_num_columns)
1210                 nr = video_num_columns;
1211         else if (!nr)
1212                 nr = 1;
1213         while (nr--)
1214                 delete_char(currcons);
1215 }
1216 
1217 static void csi_M(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
1218 {
1219         if (nr > video_num_lines)
1220                 nr = video_num_lines;
1221         else if (!nr)
1222                 nr=1;
1223         while (nr--)
1224                 delete_line(currcons);
1225 }
1226 
1227 static void save_cur(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1228 {
1229         saved_x         = x;
1230         saved_y         = y;
1231         s_intensity     = intensity;
1232         s_underline     = underline;
1233         s_blink         = blink;
1234         s_reverse       = reverse;
1235         s_charset       = charset;
1236         s_color         = color;
1237         saved_G0        = G0_charset;
1238         saved_G1        = G1_charset;
1239 }
1240 
1241 static void restore_cur(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1242 {
1243         gotoxy(currcons,saved_x,saved_y);
1244         intensity       = s_intensity;
1245         underline       = s_underline;
1246         blink           = s_blink;
1247         reverse         = s_reverse;
1248         charset         = s_charset;
1249         color           = s_color;
1250         G0_charset      = saved_G0;
1251         G1_charset      = saved_G1;
1252         translate       = set_translate(charset ? G1_charset : G0_charset);
1253         update_attr(currcons);
1254         need_wrap = 0;
1255 }
1256 
1257 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, 
1258         EShash, ESsetG0, ESsetG1, ESpercent, ESignore };
1259 
1260 static void reset_terminal(int currcons, int do_clear)
     /* [previous][next][first][last][top][bottom][index][help] */
1261 {
1262         top             = 0;
1263         bottom          = video_num_lines;
1264         vc_state        = ESnormal;
1265         ques            = 0;
1266         translate       = set_translate(NORM_MAP);
1267         G0_charset      = NORM_MAP;
1268         G1_charset      = GRAF_MAP;
1269         charset         = 0;
1270         need_wrap       = 0;
1271         report_mouse    = 0;
1272         utf             = 0;
1273         utf_count       = 0;
1274 
1275         disp_ctrl       = 0;
1276         toggle_meta     = 0;
1277 
1278         decscnm         = 0;
1279         decom           = 0;
1280         decawm          = 1;
1281         deccm           = 1;
1282         decim           = 0;
1283 
1284         set_kbd(decarm);
1285         clr_kbd(decckm);
1286         clr_kbd(kbdapplic);
1287         clr_kbd(lnm);
1288         kbd_table[currcons].lockstate = 0;
1289         kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1290         kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1291         set_leds();
1292 
1293         default_attr(currcons);
1294         update_attr(currcons);
1295 
1296         tab_stop[0]     = 0x01010100;
1297         tab_stop[1]     =
1298         tab_stop[2]     =
1299         tab_stop[3]     =
1300         tab_stop[4]     = 0x01010101;
1301 
1302         gotoxy(currcons,0,0);
1303         save_cur(currcons);
1304         if (do_clear)
1305             csi_J(currcons,2);
1306 }
1307 
1308 /*
1309  * Turn the Scroll-Lock LED on when the tty is stopped
1310  */
1311 static void con_stop(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1312 {
1313         int console_num;
1314         if (!tty)
1315                 return;
1316         console_num = MINOR(tty->device) - (tty->driver.minor_start);
1317         if (!vc_cons_allocated(console_num))
1318                 return;
1319         set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
1320         set_leds();
1321 }
1322 
1323 /*
1324  * Turn the Scroll-Lock LED off when the console is started
1325  */
1326 static void con_start(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1327 {
1328         int console_num;
1329         if (!tty)
1330                 return;
1331         console_num = MINOR(tty->device) - (tty->driver.minor_start);
1332         if (!vc_cons_allocated(console_num))
1333                 return;
1334         clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
1335         set_leds();
1336 }
1337 
1338 static int con_write(struct tty_struct * tty, int from_user,
     /* [previous][next][first][last][top][bottom][index][help] */
1339                      unsigned char *buf, int count)
1340 {
1341         int c, tc, ok, n = 0;
1342         unsigned int currcons;
1343         struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1344 
1345         currcons = vt->vc_num;
1346         if (!vc_cons_allocated(currcons)) {
1347             /* could this happen? */
1348             static int error = 0;
1349             if (!error) {
1350                 error = 1;
1351                 printk("con_write: tty %d not allocated\n", currcons+1);
1352             }
1353             return 0;
1354         }
1355 
1356         if (currcons == sel_cons)
1357                 clear_selection();
1358 
1359         disable_bh(KEYBOARD_BH);
1360         while (!tty->stopped && count) {
1361                 c = from_user ? get_fs_byte(buf) : *buf;
1362                 buf++; n++; count--;
1363 
1364                 if (utf) {
1365                     /* Combine UTF-8 into Unicode */
1366                     /* Incomplete characters silently ignored */
1367                     if(c > 0x7f) {   
1368                         if (utf_count > 0 && (c & 0xc0) == 0x80) {
1369                                 utf_char = (utf_char << 6) | (c & 0x3f);
1370                                 utf_count--;
1371                                 if (utf_count == 0)
1372                                     c = utf_char;
1373                                 else continue;
1374                         } else {
1375                                 if ((c & 0xe0) == 0xc0) {
1376                                     utf_count = 1;
1377                                     utf_char = (c & 0x1f);
1378                                 } else if ((c & 0xf0) == 0xe0) {
1379                                     utf_count = 2;
1380                                     utf_char = (c & 0x0f);
1381                                 } else
1382                                     utf_count = 0;
1383                                 continue;
1384                         }
1385                     } else
1386                         utf_count = 0;
1387 
1388                     /* Now try to find out how to display it */
1389                     tc = conv_uni_to_pc(c);
1390                     if (tc == -1 || tc == -2)
1391                       continue;
1392                     if (tc == -3 || tc == -4) { /* hashtable not valid */
1393                                                 /* or symbol not found */
1394                         tc = (c <= 0xff) ? translate[c] : 040;
1395                         ok = 0;
1396                     } else
1397                         ok = 1;
1398                 } else {        /* no utf */
1399                     tc = translate[toggle_meta ? (c|0x80) : c];
1400                     ok = 0;
1401                 }
1402 
1403                 /* If the original code was < 32 we only allow a
1404                  * glyph to be displayed if the code is not normally
1405                  * used (such as for cursor movement) or if the
1406                  * disp_ctrl mode has been explicitly enabled.
1407                  * Note: ESC is *never* allowed to be displayed as
1408                  * that would disable all escape sequences!
1409                  */
1410                 if (!ok && tc && (c >= 32 || (disp_ctrl && c != 0x1b)
1411                 || !((CTRL_ACTION >> c) & 1)))
1412                     ok = 1;
1413 
1414                 if (vc_state == ESnormal && ok) {
1415                         if (need_wrap) {
1416                                 cr(currcons);
1417                                 lf(currcons);
1418                         }
1419                         if (decim)
1420                                 insert_char(currcons);
1421                         scr_writew((attr << 8) + tc, (unsigned short *) pos);
1422                         if (x == video_num_columns - 1)
1423                                 need_wrap = decawm;
1424                         else {
1425                                 x++;
1426                                 pos+=2;
1427                         }
1428                         continue;
1429                 }
1430 
1431                 /*
1432                  *  Control characters can be used in the _middle_
1433                  *  of an escape sequence.
1434                  */
1435                 switch (c) {
1436                         case 7:
1437                                 kd_mksound(0x637, HZ/8);
1438                                 continue;
1439                         case 8:
1440                                 bs(currcons);
1441                                 continue;
1442                         case 9:
1443                                 pos -= (x << 1);
1444                                 while (x < video_num_columns - 1) {
1445                                         x++;
1446                                         if (tab_stop[x >> 5] & (1 << (x & 31)))
1447                                                 break;
1448                                 }
1449                                 pos += (x << 1);
1450                                 continue;
1451                         case 10: case 11: case 12:
1452                                 lf(currcons);
1453                                 if (!is_kbd(lnm))
1454                                         continue;
1455                         case 13:
1456                                 cr(currcons);
1457                                 continue;
1458                         case 14:
1459                                 charset = 1;
1460                                 translate = set_translate(G1_charset);
1461                                 disp_ctrl = 1;
1462                                 continue;
1463                         case 15:
1464                                 charset = 0;
1465                                 translate = set_translate(G0_charset);
1466                                 disp_ctrl = 0;
1467                                 continue;
1468                         case 24: case 26:
1469                                 vc_state = ESnormal;
1470                                 continue;
1471                         case 27:
1472                                 vc_state = ESesc;
1473                                 continue;
1474                         case 127:
1475                                 del(currcons);
1476                                 continue;
1477                         case 128+27:
1478                                 vc_state = ESsquare;
1479                                 continue;
1480                 }
1481                 switch(vc_state) {
1482                         case ESesc:
1483                                 vc_state = ESnormal;
1484                                 switch (c) {
1485                                   case '[':
1486                                         vc_state = ESsquare;
1487                                         continue;
1488                                   case '%':
1489                                         vc_state = ESpercent;
1490                                         continue;
1491                                   case 'E':
1492                                         cr(currcons);
1493                                         lf(currcons);
1494                                         continue;
1495                                   case 'M':
1496                                         ri(currcons);
1497                                         continue;
1498                                   case 'D':
1499                                         lf(currcons);
1500                                         continue;
1501                                   case 'H':
1502                                         tab_stop[x >> 5] |= (1 << (x & 31));
1503                                         continue;
1504                                   case 'Z':
1505                                         respond_ID(tty);
1506                                         continue;
1507                                   case '7':
1508                                         save_cur(currcons);
1509                                         continue;
1510                                   case '8':
1511                                         restore_cur(currcons);
1512                                         continue;
1513                                   case '(':
1514                                         vc_state = ESsetG0;
1515                                         continue;
1516                                   case ')':
1517                                         vc_state = ESsetG1;
1518                                         continue;
1519                                   case '#':
1520                                         vc_state = EShash;
1521                                         continue;
1522                                   case 'c':
1523                                         reset_terminal(currcons,1);
1524                                         continue;
1525                                   case '>':  /* Numeric keypad */
1526                                         clr_kbd(kbdapplic);
1527                                         continue;
1528                                   case '=':  /* Appl. keypad */
1529                                         set_kbd(kbdapplic);
1530                                         continue;
1531                                 }       
1532                                 continue;
1533                         case ESsquare:
1534                                 for(npar = 0 ; npar < NPAR ; npar++)
1535                                         par[npar] = 0;
1536                                 npar = 0;
1537                                 vc_state = ESgetpars;
1538                                 if (c == '[') { /* Function key */
1539                                         vc_state=ESfunckey;
1540                                         continue;
1541                                 }
1542                                 ques = (c=='?');
1543                                 if (ques)
1544                                         continue;
1545                         case ESgetpars:
1546                                 if (c==';' && npar<NPAR-1) {
1547                                         npar++;
1548                                         continue;
1549                                 } else if (c>='0' && c<='9') {
1550                                         par[npar] *= 10;
1551                                         par[npar] += c-'0';
1552                                         continue;
1553                                 } else vc_state=ESgotpars;
1554                         case ESgotpars:
1555                                 vc_state = ESnormal;
1556                                 switch(c) {
1557                                         case 'h':
1558                                                 set_mode(currcons,1);
1559                                                 continue;
1560                                         case 'l':
1561                                                 set_mode(currcons,0);
1562                                                 continue;
1563                                         case 'n':
1564                                                 if (!ques)
1565                                                         if (par[0] == 5)
1566                                                                 status_report(tty);
1567                                                         else if (par[0] == 6)
1568                                                                 cursor_report(currcons,tty);
1569                                                 continue;
1570                                 }
1571                                 if (ques) {
1572                                         ques = 0;
1573                                         continue;
1574                                 }
1575                                 switch(c) {
1576                                         case 'G': case '`':
1577                                                 if (par[0]) par[0]--;
1578                                                 gotoxy(currcons,par[0],y);
1579                                                 continue;
1580                                         case 'A':
1581                                                 if (!par[0]) par[0]++;
1582                                                 gotoxy(currcons,x,y-par[0]);
1583                                                 continue;
1584                                         case 'B': case 'e':
1585                                                 if (!par[0]) par[0]++;
1586                                                 gotoxy(currcons,x,y+par[0]);
1587                                                 continue;
1588                                         case 'C': case 'a':
1589                                                 if (!par[0]) par[0]++;
1590                                                 gotoxy(currcons,x+par[0],y);
1591                                                 continue;
1592                                         case 'D':
1593                                                 if (!par[0]) par[0]++;
1594                                                 gotoxy(currcons,x-par[0],y);
1595                                                 continue;
1596                                         case 'E':
1597                                                 if (!par[0]) par[0]++;
1598                                                 gotoxy(currcons,0,y+par[0]);
1599                                                 continue;
1600                                         case 'F':
1601                                                 if (!par[0]) par[0]++;
1602                                                 gotoxy(currcons,0,y-par[0]);
1603                                                 continue;
1604                                         case 'd':
1605                                                 if (par[0]) par[0]--;
1606                                                 gotoxy(currcons,x,par[0]);
1607                                                 continue;
1608                                         case 'H': case 'f':
1609                                                 if (par[0]) par[0]--;
1610                                                 if (par[1]) par[1]--;
1611                                                 gotoxy(currcons,par[1],par[0]);
1612                                                 continue;
1613                                         case 'J':
1614                                                 csi_J(currcons,par[0]);
1615                                                 continue;
1616                                         case 'K':
1617                                                 csi_K(currcons,par[0]);
1618                                                 continue;
1619                                         case 'L':
1620                                                 csi_L(currcons,par[0]);
1621                                                 continue;
1622                                         case 'M':
1623                                                 csi_M(currcons,par[0]);
1624                                                 continue;
1625                                         case 'P':
1626                                                 csi_P(currcons,par[0]);
1627                                                 continue;
1628                                         case 'c':
1629                                                 if (!par[0])
1630                                                         respond_ID(tty);
1631                                                 continue;
1632                                         case 'g':
1633                                                 if (!par[0])
1634                                                         tab_stop[x >> 5] &= ~(1 << (x & 31));
1635                                                 else if (par[0] == 3) {
1636                                                         tab_stop[0] =
1637                                                         tab_stop[1] =
1638                                                         tab_stop[2] =
1639                                                         tab_stop[3] =
1640                                                         tab_stop[4] = 0;
1641                                                 }
1642                                                 continue;
1643                                         case 'm':
1644                                                 csi_m(currcons);
1645                                                 continue;
1646                                         case 'q': /* DECLL - but only 3 leds */
1647                                                 /* map 0,1,2,3 to 0,1,2,4 */
1648                                                 if (par[0] < 4)
1649                                                   setledstate(kbd_table + currcons,
1650                                                               (par[0] < 3) ? par[0] : 4);
1651                                                 continue;
1652                                         case 'r':
1653                                                 if (!par[0])
1654                                                         par[0]++;
1655                                                 if (!par[1])
1656                                                         par[1] = video_num_lines;
1657                                                 /* Minimum allowed region is 2 lines */
1658                                                 if (par[0] < par[1] &&
1659                                                     par[1] <= video_num_lines) {
1660                                                         top=par[0]-1;
1661                                                         bottom=par[1];
1662                                                         gotoxy(currcons,0,0);
1663                                                 }
1664                                                 continue;
1665                                         case 's':
1666                                                 save_cur(currcons);
1667                                                 continue;
1668                                         case 'u':
1669                                                 restore_cur(currcons);
1670                                                 continue;
1671                                         case 'X':
1672                                                 csi_X(currcons, par[0]);
1673                                                 continue;
1674                                         case '@':
1675                                                 csi_at(currcons,par[0]);
1676                                                 continue;
1677                                         case ']': /* setterm functions */
1678                                                 setterm_command(currcons);
1679                                                 continue;
1680                                 }
1681                                 continue;
1682                         case ESpercent:
1683                                 vc_state = ESnormal;
1684                                 switch (c) {
1685                                   case '@':  /* defined in ISO 2022 */
1686                                         utf = 0;
1687                                         continue;
1688                                   case '8':
1689                                         /* ISO/ECMA hasn't yet registered an
1690                                            official ESC sequence for UTF-8,
1691                                            so this one (ESC %8) will likely
1692                                            change in the future. */
1693                                         utf = 1;
1694                                         continue;
1695                                 }
1696                                 continue;
1697                         case ESfunckey:
1698                                 vc_state = ESnormal;
1699                                 continue;
1700                         case EShash:
1701                                 vc_state = ESnormal;
1702                                 if (c == '8') {
1703                                         /* DEC screen alignment test. kludge :-) */
1704                                         video_erase_char =
1705                                                 (video_erase_char & 0xff00) | 'E';
1706                                         csi_J(currcons, 2);
1707                                         video_erase_char =
1708                                                 (video_erase_char & 0xff00) | ' ';
1709                                 }
1710                                 continue;
1711                         case ESsetG0:
1712                                 if (c == '0')
1713                                         G0_charset = GRAF_MAP;
1714                                 else if (c == 'B')
1715                                         G0_charset = NORM_MAP;
1716                                 else if (c == 'U')
1717                                         G0_charset = NULL_MAP;
1718                                 else if (c == 'K')
1719                                         G0_charset = USER_MAP;
1720                                 if (charset == 0)
1721                                         translate = set_translate(G0_charset);
1722                                 vc_state = ESnormal;
1723                                 continue;
1724                         case ESsetG1:
1725                                 if (c == '0')
1726                                         G1_charset = GRAF_MAP;
1727                                 else if (c == 'B')
1728                                         G1_charset = NORM_MAP;
1729                                 else if (c == 'U')
1730                                         G1_charset = NULL_MAP;
1731                                 else if (c == 'K')
1732                                         G1_charset = USER_MAP;
1733                                 if (charset == 1)
1734                                         translate = set_translate(G1_charset);
1735                                 vc_state = ESnormal;
1736                                 continue;
1737                         default:
1738                                 vc_state = ESnormal;
1739                 }
1740         }
1741         if (vcmode != KD_GRAPHICS)
1742                 set_cursor(currcons);
1743         enable_bh(KEYBOARD_BH);
1744         return n;
1745 }
1746 
1747 static int con_write_room(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1748 {
1749         if (tty->stopped)
1750                 return 0;
1751         return 4096;            /* No limit, really; we're not buffering */
1752 }
1753 
1754 static int con_chars_in_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1755 {
1756         return 0;               /* we're not buffering */
1757 }
1758 
1759 void poke_blanked_console(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1760 {
1761         timer_active &= ~(1<<BLANK_TIMER);
1762         if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
1763                 return;
1764         if (console_blanked) {
1765                 timer_table[BLANK_TIMER].expires = 0;
1766                 timer_active |= 1<<BLANK_TIMER;
1767         } else if (blankinterval) {
1768                 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1769                 timer_active |= 1<<BLANK_TIMER;
1770         }
1771 }
1772 
1773 void console_print(const char * b)
     /* [previous][next][first][last][top][bottom][index][help] */
1774 {
1775         int currcons = fg_console;
1776         unsigned char c;
1777         static int printing = 0;
1778 
1779         if (!printable || printing)
1780                 return;  /* console not yet initialized */
1781         printing = 1;
1782 
1783         if (!vc_cons_allocated(currcons)) {
1784                 /* impossible */
1785                 printk("console_print: tty %d not allocated ??\n", currcons+1);
1786                 return;
1787         }
1788 
1789         while ((c = *(b++)) != 0) {
1790                 if (c == 10 || c == 13 || need_wrap) {
1791                         if (c != 13)
1792                                 lf(currcons);
1793                         cr(currcons);
1794                         if (c == 10 || c == 13)
1795                                 continue;
1796                 }
1797                 scr_writew((attr << 8) + c, (unsigned short *) pos);
1798                 if (x == video_num_columns - 1) {
1799                         need_wrap = 1;
1800                         continue;
1801                 }
1802                 x++;
1803                 pos+=2;
1804         }
1805         set_cursor(currcons);
1806         poke_blanked_console();
1807         printing = 0;
1808 }
1809 
1810 /*
1811  * con_throttle and con_unthrottle are only used for
1812  * paste_selection(), which has to stuff in a large number of
1813  * characters...
1814  */
1815 static void con_throttle(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1816 {
1817 }
1818 
1819 static void con_unthrottle(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1820 {
1821         struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
1822 
1823         wake_up_interruptible(&vt->paste_wait);
1824 }
1825 
1826 static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
     /* [previous][next][first][last][top][bottom][index][help] */
1827 {
1828         long base = (long) vc_scrbuf[currcons];
1829 
1830         video_num_columns = cols;
1831         video_num_lines = rows;
1832         video_size_row = cols<<1;
1833         video_screen_size = video_num_lines * video_size_row;
1834 
1835         pos = origin = video_mem_start = base;
1836         scr_end = base + video_screen_size;
1837         video_mem_end = base + video_screen_size;
1838         reset_vc(currcons);
1839         def_color       = 0x07;   /* white */
1840         ulcolor         = 0x0f;   /* bold white */
1841         halfcolor       = 0x08;   /* grey */
1842         vt_cons[currcons]->paste_wait = 0;
1843         reset_terminal(currcons, do_clear);
1844 }
1845 
1846 static void con_setsize(unsigned long rows, unsigned long cols)
     /* [previous][next][first][last][top][bottom][index][help] */
1847 {
1848         video_num_lines = rows;
1849         video_num_columns = cols;
1850         video_size_row = 2 * cols;
1851         video_screen_size = video_num_lines * video_size_row;
1852 }
1853 
1854 /*
1855  *  long con_init(long);
1856  *
1857  * This routine initializes console interrupts, and does nothing
1858  * else. If you want the screen to clear, call tty_write with
1859  * the appropriate escape-sequence.
1860  *
1861  * Reads the information preserved by setup.s to determine the current display
1862  * type and sets everything accordingly.
1863  */
1864 long con_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
1865 {
1866         char *display_desc = "????";
1867         int currcons = 0;
1868         int orig_x = ORIG_X;
1869         int orig_y = ORIG_Y;
1870 
1871         memset(&console_driver, 0, sizeof(struct tty_driver));
1872         console_driver.magic = TTY_DRIVER_MAGIC;
1873         console_driver.name = "tty";
1874         console_driver.name_base = 1;
1875         console_driver.major = TTY_MAJOR;
1876         console_driver.minor_start = 1;
1877         console_driver.num = MAX_NR_CONSOLES;
1878         console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
1879         console_driver.init_termios = tty_std_termios;
1880         console_driver.flags = TTY_DRIVER_REAL_RAW;
1881         console_driver.refcount = &console_refcount;
1882         console_driver.table = console_table;
1883         console_driver.termios = console_termios;
1884         console_driver.termios_locked = console_termios_locked;
1885 
1886         console_driver.open = con_open;
1887         console_driver.write = con_write;
1888         console_driver.write_room = con_write_room;
1889         console_driver.chars_in_buffer = con_chars_in_buffer;
1890         console_driver.ioctl = vt_ioctl;
1891         console_driver.stop = con_stop;
1892         console_driver.start = con_start;
1893         console_driver.throttle = con_throttle;
1894         console_driver.unthrottle = con_unthrottle;
1895         
1896         if (tty_register_driver(&console_driver))
1897                 panic("Couldn't register console driver\n");
1898         
1899         con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
1900         video_page = ORIG_VIDEO_PAGE;                   /* never used */
1901 
1902         timer_table[BLANK_TIMER].fn = blank_screen;
1903         timer_table[BLANK_TIMER].expires = 0;
1904         if (blankinterval) {
1905                 timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
1906                 timer_active |= 1<<BLANK_TIMER;
1907         }
1908         
1909         if (ORIG_VIDEO_MODE == 7)       /* Is this a monochrome display? */
1910         {
1911                 video_mem_base = 0xb0000;
1912                 video_port_reg = 0x3b4;
1913                 video_port_val = 0x3b5;
1914                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1915                 {
1916                         video_type = VIDEO_TYPE_EGAM;
1917                         video_mem_term = 0xb8000;
1918                         display_desc = "EGA+";
1919                         request_region(0x3b4,2,"ega+");
1920                 }
1921                 else
1922                 {
1923                         video_type = VIDEO_TYPE_MDA;
1924                         video_mem_term = 0xb2000;
1925                         display_desc = "*MDA";
1926                         request_region(0x3b4,2,"mda");
1927                         request_region(0x3b8,1,"mda");
1928                         request_region(0x3bf,1,"mda");
1929                 }
1930         }
1931         else                            /* If not, it is color. */
1932         {
1933                 can_do_color = 1;
1934                 video_mem_base = 0xb8000;
1935                 video_port_reg  = 0x3d4;
1936                 video_port_val  = 0x3d5;
1937                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1938                 {
1939                         video_type = VIDEO_TYPE_EGAC;
1940                         video_mem_term = 0xc0000;
1941                         display_desc = "EGA+";
1942                         request_region(0x3d4,2,"ega+");
1943                 }
1944                 else
1945                 {
1946                         video_type = VIDEO_TYPE_CGA;
1947                         video_mem_term = 0xba000;
1948                         display_desc = "*CGA";
1949                         request_region(0x3d4,2,"cga");
1950                 }
1951         }
1952         
1953         /* Initialize the variables used for scrolling (mostly EGA/VGA) */
1954 
1955         /* Due to kmalloc roundup allocating statically is more efficient -
1956            so provide MIN_NR_CONSOLES for people with very little memory */
1957         for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
1958                 vc_cons[currcons].d = (struct vc_data *) kmem_start;
1959                 kmem_start += sizeof(struct vc_data);
1960                 vt_cons[currcons] = (struct vt_struct *) kmem_start;
1961                 kmem_start += sizeof(struct vt_struct);
1962                 vc_scrbuf[currcons] = (unsigned short *) kmem_start;
1963                 kmem_start += video_screen_size;
1964                 kmalloced = 0;
1965                 screenbuf_size = video_screen_size;
1966                 vc_init(currcons, video_num_lines, video_num_columns, currcons);
1967         }
1968 
1969         currcons = fg_console = 0;
1970 
1971         video_mem_start = video_mem_base;
1972         video_mem_end = video_mem_term;
1973         origin = video_mem_start;
1974         scr_end = video_mem_start + video_num_lines * video_size_row;
1975         gotoxy(currcons,orig_x,orig_y);
1976         set_origin(currcons);
1977         csi_J(currcons, 0);
1978         printable = 1;
1979         printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
1980                 can_do_color ? "colour" : "mono",
1981                 display_desc,
1982                 video_num_columns,video_num_lines,
1983                 MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES);
1984         register_console(console_print);
1985         return kmem_start;
1986 }
1987 
1988 static void get_scrmem(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1989 {
1990         memcpyw((unsigned short *)vc_scrbuf[currcons],
1991                 (unsigned short *)origin, video_screen_size);
1992         origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
1993         scr_end = video_mem_end = video_mem_start + video_screen_size;
1994         pos = origin + y*video_size_row + (x<<1);
1995 }
1996 
1997 static void set_scrmem(int currcons, long offset)
     /* [previous][next][first][last][top][bottom][index][help] */
1998 {
1999 #ifdef CONFIG_HGA
2000   /* This works with XFree86 1.2, 1.3 and 2.0
2001      This code could be extended and made more generally useful if we could
2002      determine the actual video mode. It appears that this should be
2003      possible on a genuine Hercules card, but I (WM) haven't been able to
2004      read from any of the required registers on my clone card.
2005      */
2006         /* This code should work with Hercules and MDA cards. */
2007         if (video_type == VIDEO_TYPE_MDA)
2008           {
2009             if (vcmode == KD_TEXT)
2010               {
2011                 /* Ensure that the card is in text mode. */
2012                 int     i;
2013                 static char herc_txt_tbl[12] = {
2014                   0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
2015                 outb_p(0, 0x3bf);  /* Back to power-on defaults */
2016                 outb_p(0, 0x3b8);  /* Blank the screen, select page 0, etc */
2017                 for ( i = 0 ; i < 12 ; i++ )
2018                   {
2019                     outb_p(i, 0x3b4);
2020                     outb_p(herc_txt_tbl[i], 0x3b5);
2021                   }
2022               }
2023 #define HGA_BLINKER_ON 0x20
2024 #define HGA_SCREEN_ON  8
2025             /* Make sure that the hardware is not blanked */
2026             outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
2027           }
2028 #endif CONFIG_HGA
2029 
2030         if (video_mem_term - video_mem_base < offset + video_screen_size)
2031           offset = 0;   /* strange ... */
2032         memcpyw((unsigned short *)(video_mem_base + offset),
2033                 (unsigned short *) origin, video_screen_size);
2034         video_mem_start = video_mem_base;
2035         video_mem_end = video_mem_term;
2036         origin = video_mem_base + offset;
2037         scr_end = origin + video_screen_size;
2038         pos = origin + y*video_size_row + (x<<1);
2039 }
2040 
2041 void do_blank_screen(int nopowersave)
     /* [previous][next][first][last][top][bottom][index][help] */
2042 {
2043         int currcons;
2044 
2045         if (console_blanked)
2046                 return;
2047 
2048         timer_active &= ~(1<<BLANK_TIMER);
2049         timer_table[BLANK_TIMER].fn = unblank_screen;
2050 
2051         /* try not to lose information by blanking, and not to waste memory */
2052         currcons = fg_console;
2053         has_scrolled = 0;
2054         blank__origin = __origin;
2055         blank_origin = origin;
2056         set_origin(fg_console);
2057         get_scrmem(fg_console);
2058         unblank_origin = origin;
2059         memsetw((void *)blank_origin, BLANK, video_mem_term-blank_origin);
2060         hide_cursor();
2061         console_blanked = fg_console + 1;
2062 
2063         if(!nopowersave)
2064             vesa_blank();
2065 }
2066 
2067 void do_unblank_screen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2068 {
2069         int currcons;
2070         int resetorg;
2071         long offset;
2072 
2073         if (!console_blanked)
2074                 return;
2075         if (!vc_cons_allocated(fg_console)) {
2076                 /* impossible */
2077                 printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2078                 return;
2079         }
2080         timer_table[BLANK_TIMER].fn = blank_screen;
2081         if (blankinterval) {
2082                 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
2083                 timer_active |= 1<<BLANK_TIMER;
2084         }
2085 
2086         currcons = fg_console;
2087         offset = 0;
2088         resetorg = 0;
2089         if (console_blanked == fg_console + 1 && origin == unblank_origin
2090             && !has_scrolled) {
2091                 /* try to restore the exact situation before blanking */
2092                 resetorg = 1;
2093                 offset = (blank_origin - video_mem_base)
2094                         - (unblank_origin - video_mem_start);
2095         }
2096 
2097         console_blanked = 0;
2098         set_scrmem(fg_console, offset);
2099         set_origin(fg_console);
2100         set_cursor(fg_console);
2101         if (resetorg)
2102                 __set_origin(blank__origin);
2103 
2104         vesa_unblank();
2105 }
2106 
2107 /*
2108  * If a blank_screen is due to a timer, then a power save is allowed.
2109  * If it is related to console_switching, then avoid vesa_blank().
2110  */
2111 static void blank_screen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2112 {
2113         do_blank_screen(0);
2114 }
2115 
2116 static void unblank_screen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2117 {
2118         do_unblank_screen();
2119 }
2120 
2121 void update_screen(int new_console)
     /* [previous][next][first][last][top][bottom][index][help] */
2122 {
2123         static int lock = 0;
2124 
2125         if (new_console == fg_console || lock)
2126                 return;
2127         if (!vc_cons_allocated(new_console)) {
2128                 /* strange ... */
2129                 printk("update_screen: tty %d not allocated ??\n", new_console+1);
2130                 return;
2131         }
2132         lock = 1;
2133 
2134         clear_selection();
2135 
2136         if (!console_blanked)
2137                 get_scrmem(fg_console);
2138         else
2139                 console_blanked = -1;      /* no longer of the form console+1 */
2140         fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
2141                                   /* consequently, fg_console will always be allocated */
2142         set_scrmem(fg_console, 0); 
2143         set_origin(fg_console);
2144         set_cursor(fg_console);
2145         set_leds();
2146         compute_shiftstate();
2147         lock = 0;
2148 }
2149 
2150 /*
2151  * Allocate the console screen memory.
2152  */
2153 int con_open(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
2154 {
2155         unsigned int    idx;
2156         int i;
2157 
2158         idx = MINOR(tty->device) - tty->driver.minor_start;
2159         
2160         i = vc_allocate(idx);
2161         if (i)
2162                 return i;
2163 
2164         vt_cons[idx]->vc_num = idx;
2165         tty->driver_data = vt_cons[idx];
2166         
2167         if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2168                 tty->winsize.ws_row = video_num_lines;
2169                 tty->winsize.ws_col = video_num_columns;
2170         }
2171         return 0;
2172 }
2173 
2174 
2175 /*
2176  * PIO_FONT support.
2177  *
2178  * The font loading code goes back to the codepage package by
2179  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
2180  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
2181  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
2182  *
2183  * Change for certain monochrome monitors by Yury Shevchuck
2184  * (sizif@botik.yaroslavl.su).
2185  */
2186 
2187 #define colourmap ((char *)0xa0000)
2188 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
2189    should use 0xA0000 for the bwmap as well.. */
2190 #define blackwmap ((char *)0xa0000)
2191 #define cmapsz 8192
2192 #define seq_port_reg (0x3c4)
2193 #define seq_port_val (0x3c5)
2194 #define gr_port_reg (0x3ce)
2195 #define gr_port_val (0x3cf)
2196 
2197 static int set_get_font(char * arg, int set)
     /* [previous][next][first][last][top][bottom][index][help] */
2198 {
2199 #ifdef CAN_LOAD_EGA_FONTS
2200         int i;
2201         char *charmap;
2202         int beg;
2203 
2204         /* no use to "load" CGA... */
2205 
2206         if (video_type == VIDEO_TYPE_EGAC) {
2207                 charmap = colourmap;
2208                 beg = 0x0e;
2209         } else if (video_type == VIDEO_TYPE_EGAM) {
2210                 charmap = blackwmap;
2211                 beg = 0x0a;
2212         } else
2213                 return -EINVAL;
2214 
2215         i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
2216         if (i)
2217                 return i;
2218 
2219         cli();
2220         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
2221         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
2222         outb_p( 0x02, seq_port_reg );
2223         outb_p( 0x04, seq_port_val );   /* CPU writes only to map 2 */
2224         outb_p( 0x04, seq_port_reg );
2225         outb_p( 0x07, seq_port_val );   /* Sequential addressing */
2226         outb_p( 0x00, seq_port_reg );
2227         outb_p( 0x03, seq_port_val );   /* Clear synchronous reset */
2228 
2229         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
2230         outb_p( 0x02, gr_port_val );    /* select map 2 */
2231         outb_p( 0x05, gr_port_reg );
2232         outb_p( 0x00, gr_port_val );    /* disable odd-even addressing */
2233         outb_p( 0x06, gr_port_reg );
2234         outb_p( 0x00, gr_port_val );    /* map start at A000:0000 */
2235         sti();
2236 
2237         if (set)
2238                 for (i=0; i<cmapsz ; i++)
2239                         *(charmap+i) = get_fs_byte(arg+i);
2240         else
2241                 for (i=0; i<cmapsz ; i++)
2242                         put_fs_byte(*(charmap+i), arg+i);
2243 
2244         cli();
2245         outb_p( 0x00, seq_port_reg );   /* First, the sequencer */
2246         outb_p( 0x01, seq_port_val );   /* Synchronous reset */
2247         outb_p( 0x02, seq_port_reg );
2248         outb_p( 0x03, seq_port_val );   /* CPU writes to maps 0 and 1 */
2249         outb_p( 0x04, seq_port_reg );
2250         outb_p( 0x03, seq_port_val );   /* odd-even addressing */
2251         outb_p( 0x00, seq_port_reg );
2252         outb_p( 0x03, seq_port_val );   /* clear synchronous reset */
2253 
2254         outb_p( 0x04, gr_port_reg );    /* Now, the graphics controller */
2255         outb_p( 0x00, gr_port_val );    /* select map 0 for CPU */
2256         outb_p( 0x05, gr_port_reg );
2257         outb_p( 0x10, gr_port_val );    /* enable even-odd addressing */
2258         outb_p( 0x06, gr_port_reg );
2259         outb_p( beg, gr_port_val );     /* map starts at b800:0 or b000:0 */
2260         sti();
2261 
2262         return 0;
2263 #else
2264         return -EINVAL;
2265 #endif
2266 }
2267 
2268 /*
2269  * Load font into the EGA/VGA character generator. arg points to a 8192
2270  * byte map, 32 bytes per character. Only first H of them are used for
2271  * 8xH fonts (0 < H <= 32).
2272  */
2273 
2274 int con_set_font (char *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
2275 {
2276         hashtable_contents_valid = 0;
2277         return set_get_font (arg,1);
2278 }
2279 
2280 int con_get_font (char *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
2281 {
2282         return set_get_font (arg,0);
2283 }

/* [previous][next][first][last][top][bottom][index][help] */