root/drivers/char/console.c

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

DEFINITIONS

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

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

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