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

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