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

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