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. respond_num
  22. cursor_report
  23. status_report
  24. respond_ID
  25. invert_screen
  26. set_mode
  27. setterm_command
  28. insert_char
  29. insert_line
  30. delete_char
  31. delete_line
  32. csi_at
  33. csi_L
  34. csi_P
  35. csi_M
  36. save_cur
  37. restore_cur
  38. reset_terminal
  39. con_write
  40. do_keyboard_interrupt
  41. memsetw
  42. console_print
  43. con_init
  44. kbdsave
  45. get_scrmem
  46. set_scrmem
  47. blank_screen
  48. unblank_screen
  49. update_screen
  50. do_screendump
  51. con_open
  52. highlight
  53. inword
  54. atedge
  55. limit
  56. set_selection
  57. paste_selection
  58. clear_selection

   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  * Hopefully this will be a rather complete VT102 implementation.
  19  *
  20  * Beeping thanks to John T Kohl.
  21  * 
  22  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
  23  *   Chars, and VT100 enhancements by Peter MacDonald.
  24  *
  25  * Copy and paste function by Andrew Haylett.
  26  */
  27 
  28 /*
  29  *  NOTE!!! We sometimes disable and enable interrupts for a short while
  30  * (to put a word in video IO), but this will work even for keyboard
  31  * interrupts. We know interrupts aren't enabled when getting a keyboard
  32  * interrupt, as we use trap-gates. Hopefully all is well.
  33  */
  34 
  35 /*
  36  * Code to check for different video-cards mostly by Galen Hunt,
  37  * <g-hunt@ee.utah.edu>
  38  */
  39 
  40 #include <linux/sched.h>
  41 #include <linux/timer.h>
  42 #include <linux/tty.h>
  43 #include <linux/config.h>
  44 #include <linux/kernel.h>
  45 #include <linux/string.h>
  46 #include <linux/errno.h>
  47 #include <linux/kd.h>
  48 #include <linux/keyboard.h>
  49 
  50 #include <asm/io.h>
  51 #include <asm/system.h>
  52 #include <asm/segment.h>
  53 
  54 #include "vt_kern.h"
  55 
  56 #ifdef CONFIG_SELECTION
  57 #include <linux/ctype.h>
  58 
  59 /* Routines for selection control. */
  60 int set_selection(const int arg);
  61 int paste_selection(struct tty_struct *tty);
  62 static void clear_selection(void);
  63 
  64 /* Variables for selection control. */
  65 #define SEL_BUFFER_SIZE TTY_BUF_SIZE
  66 static int sel_cons;
  67 static int sel_start = -1;
  68 static int sel_end;
  69 static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
  70 #endif /* CONFIG_SELECTION */
  71 
  72 #define NPAR 16
  73 
  74 extern void vt_init(void);
  75 extern void register_console(void (*proc)(const char *));
  76 extern void compute_shiftstate(void);
  77 
  78 unsigned long   video_num_columns;              /* Number of text columns       */
  79 unsigned long   video_num_lines;                /* Number of text lines         */
  80 
  81 static unsigned char    video_type;             /* Type of display being used   */
  82 static unsigned long    video_mem_base;         /* Base of video memory         */
  83 static unsigned long    video_mem_term;         /* End of video memory          */
  84 static unsigned long    video_size_row;         /* Bytes per row                */
  85 static unsigned char    video_page;             /* Initial video page           */
  86 static unsigned short   video_port_reg;         /* Video register select port   */
  87 static unsigned short   video_port_val;         /* Video register value port    */
  88 static int can_do_color = 0;
  89 static int printable = 0;
  90 
  91 static struct {
  92         unsigned short  vc_video_erase_char;    /* Background erase character */
  93         unsigned char   vc_attr;                /* Current attributes */
  94         unsigned char   vc_def_color;           /* Default colors */
  95         unsigned char   vc_color;               /* Foreground & background */
  96         unsigned char   vc_s_color;             /* Saved foreground & background */
  97         unsigned char   vc_ulcolor;             /* Colour for underline mode */
  98         unsigned char   vc_halfcolor;           /* Colour for half intensity mode */
  99         unsigned long   vc_origin;              /* Used for EGA/VGA fast scroll */
 100         unsigned long   vc_scr_end;             /* Used for EGA/VGA fast scroll */
 101         unsigned long   vc_pos;
 102         unsigned long   vc_x,vc_y;
 103         unsigned long   vc_top,vc_bottom;
 104         unsigned long   vc_state;
 105         unsigned long   vc_npar,vc_par[NPAR];
 106         unsigned long   vc_video_mem_start;     /* Start of video RAM           */
 107         unsigned long   vc_video_mem_end;       /* End of video RAM (sort of)   */
 108         unsigned long   vc_saved_x;
 109         unsigned long   vc_saved_y;
 110         /* mode flags */
 111         unsigned long   vc_charset      : 1;    /* Character set G0 / G1 */
 112         unsigned long   vc_s_charset    : 1;    /* Saved character set */
 113         unsigned long   vc_decscnm      : 1;    /* Screen Mode */
 114         unsigned long   vc_decom        : 1;    /* Origin Mode */
 115         unsigned long   vc_decawm       : 1;    /* Autowrap Mode */
 116         unsigned long   vc_deccm        : 1;    /* Cursor Visible */
 117         unsigned long   vc_decim        : 1;    /* Insert Mode */
 118         /* attribute flags */
 119         unsigned long   vc_intensity    : 2;    /* 0=half-bright, 1=normal, 2=bold */
 120         unsigned long   vc_underline    : 1;
 121         unsigned long   vc_blink        : 1;
 122         unsigned long   vc_reverse      : 1;
 123         unsigned long   vc_s_intensity  : 2;    /* saved rendition */
 124         unsigned long   vc_s_underline  : 1;
 125         unsigned long   vc_s_blink      : 1;
 126         unsigned long   vc_s_reverse    : 1;
 127         /* misc */
 128         unsigned long   vc_ques         : 1;
 129         unsigned long   vc_need_wrap    : 1;
 130         unsigned long   vc_tab_stop[5];         /* Tab stops. 160 columns. */
 131         unsigned char   vc_kbdmode;
 132         unsigned char * vc_translate;
 133         unsigned char * vc_G0_charset;
 134         unsigned char * vc_G1_charset;
 135         unsigned char * vc_saved_G0;
 136         unsigned char * vc_saved_G1;
 137         /* additional information is in vt_kern.h */
 138 } vc_cons [NR_CONSOLES];
 139 
 140 unsigned short *vc_scrbuf[NR_CONSOLES];
 141 static unsigned short * vc_scrmembuf;
 142 static int console_blanked = 0;
 143 
 144 #define origin          (vc_cons[currcons].vc_origin)
 145 #define scr_end         (vc_cons[currcons].vc_scr_end)
 146 #define pos             (vc_cons[currcons].vc_pos)
 147 #define top             (vc_cons[currcons].vc_top)
 148 #define bottom          (vc_cons[currcons].vc_bottom)
 149 #define x               (vc_cons[currcons].vc_x)
 150 #define y               (vc_cons[currcons].vc_y)
 151 #define state           (vc_cons[currcons].vc_state)
 152 #define npar            (vc_cons[currcons].vc_npar)
 153 #define par             (vc_cons[currcons].vc_par)
 154 #define ques            (vc_cons[currcons].vc_ques)
 155 #define attr            (vc_cons[currcons].vc_attr)
 156 #define saved_x         (vc_cons[currcons].vc_saved_x)
 157 #define saved_y         (vc_cons[currcons].vc_saved_y)
 158 #define translate       (vc_cons[currcons].vc_translate)
 159 #define G0_charset      (vc_cons[currcons].vc_G0_charset)
 160 #define G1_charset      (vc_cons[currcons].vc_G1_charset)
 161 #define saved_G0        (vc_cons[currcons].vc_saved_G0)
 162 #define saved_G1        (vc_cons[currcons].vc_saved_G1)
 163 #define video_mem_start (vc_cons[currcons].vc_video_mem_start)
 164 #define video_mem_end   (vc_cons[currcons].vc_video_mem_end)
 165 #define video_erase_char (vc_cons[currcons].vc_video_erase_char)        
 166 #define decscnm         (vc_cons[currcons].vc_decscnm)
 167 #define decom           (vc_cons[currcons].vc_decom)
 168 #define decawm          (vc_cons[currcons].vc_decawm)
 169 #define deccm           (vc_cons[currcons].vc_deccm)
 170 #define decim           (vc_cons[currcons].vc_decim)
 171 #define need_wrap       (vc_cons[currcons].vc_need_wrap)
 172 #define color           (vc_cons[currcons].vc_color)
 173 #define s_color         (vc_cons[currcons].vc_s_color)
 174 #define def_color       (vc_cons[currcons].vc_def_color)
 175 #define foreground      (color & 0x0f)
 176 #define background      (color & 0xf0)
 177 #define charset         (vc_cons[currcons].vc_charset)
 178 #define s_charset       (vc_cons[currcons].vc_s_charset)
 179 #define intensity       (vc_cons[currcons].vc_intensity)
 180 #define underline       (vc_cons[currcons].vc_underline)
 181 #define blink           (vc_cons[currcons].vc_blink)
 182 #define reverse         (vc_cons[currcons].vc_reverse)
 183 #define s_intensity     (vc_cons[currcons].vc_s_intensity)
 184 #define s_underline     (vc_cons[currcons].vc_s_underline)
 185 #define s_blink         (vc_cons[currcons].vc_s_blink)
 186 #define s_reverse       (vc_cons[currcons].vc_s_reverse)
 187 #define ulcolor         (vc_cons[currcons].vc_ulcolor)
 188 #define halfcolor       (vc_cons[currcons].vc_halfcolor)
 189 #define kbdmode         (vc_cons[currcons].vc_kbdmode)
 190 #define tab_stop        (vc_cons[currcons].vc_tab_stop)
 191 #define vcmode          (vt_cons[currcons].vc_mode)
 192 #define vtmode          (vt_cons[currcons].vt_mode)
 193 #define vtpid           (vt_cons[currcons].vt_pid)
 194 #define vtnewvt         (vt_cons[currcons].vt_newvt)
 195 
 196 #define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x)
 197 #define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x)
 198 #define is_kbd(x) vc_kbd_flag(kbd_table+currcons,x)
 199 
 200 #define decarm          VC_REPEAT
 201 #define decckm          VC_CKMODE
 202 #define kbdapplic       VC_APPLIC
 203 #define kbdraw          VC_RAW
 204 #define lnm             VC_CRLF
 205 
 206 int blankinterval = 10*60*HZ;
 207 static int screen_size = 0;
 208 
 209 /*
 210  * this is what the terminal answers to a ESC-Z or csi0c query.
 211  */
 212 #define VT100ID "\033[?1;2c"
 213 #define VT102ID "\033[?6c"
 214 
 215 static unsigned char * translations[] = {
 216 /* 8-bit Latin-1 mapped to the PC charater set: '\0' means non-printable */
 217 (unsigned char *)
 218         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 219         "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
 220         " !\"#$%&'()*+,-./0123456789:;<=>?"
 221         "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
 222         "`abcdefghijklmnopqrstuvwxyz{|}~\0"
 223         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 224         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 225         "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
 226         "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
 227         "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
 228         "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
 229         "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
 230         "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
 231 /* vt100 graphics */
 232 (unsigned char *)
 233         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 234         "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
 235         " !\"#$%&'()*+,-./0123456789:;<=>?"
 236         "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
 237         "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
 238         "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
 239         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 240         "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
 241         "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
 242         "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
 243         "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
 244         "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
 245         "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
 246         "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
 247 /* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
 248 (unsigned char *)
 249         "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
 250         "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
 251         "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
 252         "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
 253         "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
 254         "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
 255         "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
 256         "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
 257         "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
 258         "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
 259         "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
 260         "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
 261         "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
 262         "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
 263         "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
 264         "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
 265 };
 266 
 267 #define NORM_TRANS (translations[0])
 268 #define GRAF_TRANS (translations[1])
 269 #define NULL_TRANS (translations[2])
 270 
 271 static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
 272                                        8,12,10,14, 9,13,11,15 };
 273 
 274 /*
 275  * gotoxy() must verify all boundaries, because the arguments
 276  * might also be negative. If the given position is out of
 277  * bounds, the cursor is placed at the nearest margin.
 278  */
 279 static void gotoxy(int currcons, int new_x, int new_y)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281         int max_y;
 282 
 283         if (new_x < 0)
 284                 x = 0;
 285         else
 286                 if (new_x >= video_num_columns)
 287                         x = video_num_columns - 1;
 288                 else
 289                         x = new_x;
 290         if (decom) {
 291                 new_y += top;
 292                 max_y = bottom;
 293         } else
 294                 max_y = video_num_lines;
 295         if (new_y < 0)
 296                 y = 0;
 297         else
 298                 if (new_y >= max_y)
 299                         y = max_y - 1;
 300                 else
 301                         y = new_y;
 302         pos = origin + y*video_size_row + (x<<1);
 303         need_wrap = 0;
 304 }
 305 
 306 /*
 307  * *Very* limited hardware scrollback support..
 308  */
 309 static unsigned short __real_origin;
 310 static unsigned short __origin;
 311 
 312 static inline void __set_origin(unsigned short offset)
     /* [previous][next][first][last][top][bottom][index][help] */
 313 {
 314         unsigned long flags;
 315 #ifdef CONFIG_SELECTION
 316         clear_selection();
 317 #endif /* CONFIG_SELECTION */
 318         save_flags(flags); cli();
 319         __origin = offset;
 320         outb_p(12, video_port_reg);
 321         outb_p(offset >> 8, video_port_val);
 322         outb_p(13, video_port_reg);
 323         outb_p(offset, video_port_val);
 324         restore_flags(flags);
 325 }
 326 
 327 void scrollback(int lines)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329         if (!lines)
 330                 lines = video_num_lines/2;
 331         lines *= video_num_columns;
 332         lines = __origin - lines;
 333         if (lines < 0)
 334                 lines = 0;
 335         __set_origin(lines);
 336 }
 337 
 338 void scrollfront(int lines)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340         if (!lines)
 341                 lines = video_num_lines/2;
 342         lines *= video_num_columns;
 343         lines = __origin + lines;
 344         if (lines > __real_origin)
 345                 lines = __real_origin;
 346         __set_origin(lines);
 347 }
 348 
 349 static void set_origin(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 350 {
 351         if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
 352                 return;
 353         if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 354                 return;
 355         __real_origin = (origin-video_mem_base) >> 1;
 356         __set_origin(__real_origin);
 357 }
 358 
 359 static inline void hide_cursor(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361         outb_p(14, video_port_reg);
 362         outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
 363         outb_p(15, video_port_reg);
 364         outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
 365 }
 366 
 367 static inline void set_cursor(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369         unsigned long flags;
 370 
 371         if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 372                 return;
 373         if (__real_origin != __origin)
 374                 set_origin(__real_origin);
 375         save_flags(flags); cli();
 376         if (deccm) {
 377                 outb_p(14, video_port_reg);
 378                 outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
 379                 outb_p(15, video_port_reg);
 380                 outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 381         } else
 382                 hide_cursor(currcons);
 383         restore_flags(flags);
 384 }
 385 
 386 static void scrup(int currcons, unsigned int t, unsigned int b)
     /* [previous][next][first][last][top][bottom][index][help] */
 387 {
 388         int hardscroll = 1;
 389 
 390         if (b > video_num_lines || t >= b)
 391                 return;
 392         if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
 393                 hardscroll = 0;
 394         else if (t || b != video_num_lines)
 395                 hardscroll = 0;
 396         if (hardscroll) {
 397                 origin += video_size_row;
 398                 pos += video_size_row;
 399                 scr_end += video_size_row;
 400                 if (scr_end > video_mem_end) {
 401                         __asm__("cld\n\t"
 402                                 "rep\n\t"
 403                                 "movsl\n\t"
 404                                 "movl _video_num_columns,%1\n\t"
 405                                 "rep\n\t"
 406                                 "stosw"
 407                                 : /* no output */
 408                                 :"a" (video_erase_char),
 409                                 "c" ((video_num_lines-1)*video_num_columns>>1),
 410                                 "D" (video_mem_start),
 411                                 "S" (origin)
 412                                 :"cx","di","si");
 413                         scr_end -= origin-video_mem_start;
 414                         pos -= origin-video_mem_start;
 415                         origin = video_mem_start;
 416                 } else {
 417                         __asm__("cld\n\t"
 418                                 "rep\n\t"
 419                                 "stosw"
 420                                 : /* no output */
 421                                 :"a" (video_erase_char),
 422                                 "c" (video_num_columns),
 423                                 "D" (scr_end-video_size_row)
 424                                 :"cx","di");
 425                 }
 426                 set_origin(currcons);
 427         } else {
 428                 __asm__("cld\n\t"
 429                         "rep\n\t"
 430                         "movsl\n\t"
 431                         "movl _video_num_columns,%%ecx\n\t"
 432                         "rep\n\t"
 433                         "stosw"
 434                         : /* no output */
 435                         :"a" (video_erase_char),
 436                         "c" ((b-t-1)*video_num_columns>>1),
 437                         "D" (origin+video_size_row*t),
 438                         "S" (origin+video_size_row*(t+1))
 439                         :"cx","di","si");
 440         }
 441 }
 442 
 443 static void scrdown(int currcons, unsigned int t, unsigned int b)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445         if (b > video_num_lines || t >= b)
 446                 return;
 447         __asm__("std\n\t"
 448                 "rep\n\t"
 449                 "movsl\n\t"
 450                 "addl $2,%%edi\n\t"     /* %edi has been decremented by 4 */
 451                 "movl _video_num_columns,%%ecx\n\t"
 452                 "rep\n\t"
 453                 "stosw\n\t"
 454                 "cld"
 455                 : /* no output */
 456                 :"a" (video_erase_char),
 457                 "c" ((b-t-1)*video_num_columns>>1),
 458                 "D" (origin+video_size_row*b-4),
 459                 "S" (origin+video_size_row*(b-1)-4)
 460                 :"ax","cx","di","si");
 461 }
 462 
 463 static void lf(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465         if (y+1<bottom) {
 466                 y++;
 467                 pos += video_size_row;
 468                 return;
 469         } else 
 470                 scrup(currcons,top,bottom);
 471         need_wrap = 0;
 472 }
 473 
 474 static void ri(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 475 {
 476         if (y>top) {
 477                 y--;
 478                 pos -= video_size_row;
 479                 return;
 480         } else
 481                 scrdown(currcons,top,bottom);
 482         need_wrap = 0;
 483 }
 484 
 485 static inline void cr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 486 {
 487         pos -= x<<1;
 488         need_wrap = x = 0;
 489 }
 490 
 491 static inline void bs(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 492 {
 493         if (x) {
 494                 pos -= 2;
 495                 x--;
 496                 need_wrap = 0;
 497         }
 498 }
 499 
 500 static inline void del(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502 #if 0
 503         if (x) {
 504                 if (!need_wrap) {    /* this is not the right condition */
 505                         pos -= 2;
 506                         x--;
 507                 }
 508                 *(unsigned short *)pos = video_erase_char;
 509                 need_wrap = 0;
 510         }
 511 #endif
 512 }
 513 
 514 static void csi_J(int currcons, int vpar)
     /* [previous][next][first][last][top][bottom][index][help] */
 515 {
 516         unsigned long count;
 517         unsigned long start;
 518 
 519         switch (vpar) {
 520                 case 0: /* erase from cursor to end of display */
 521                         count = (scr_end-pos)>>1;
 522                         start = pos;
 523                         break;
 524                 case 1: /* erase from start to cursor */
 525                         count = ((pos-origin)>>1)+1;
 526                         start = origin;
 527                         break;
 528                 case 2: /* erase whole display */
 529                         count = video_num_columns * video_num_lines;
 530                         start = origin;
 531                         break;
 532                 default:
 533                         return;
 534         }
 535         __asm__("cld\n\t"
 536                 "rep\n\t"
 537                 "stosw\n\t"
 538                 : /* no output */
 539                 :"c" (count),
 540                 "D" (start),"a" (video_erase_char)
 541                 :"cx","di");
 542         need_wrap = 0;
 543 }
 544 
 545 static void csi_K(int currcons, int vpar)
     /* [previous][next][first][last][top][bottom][index][help] */
 546 {
 547         long count;
 548         long start;
 549 
 550         switch (vpar) {
 551                 case 0: /* erase from cursor to end of line */
 552                         count = video_num_columns-x;
 553                         start = pos;
 554                         break;
 555                 case 1: /* erase from start of line to cursor */
 556                         start = pos - (x<<1);
 557                         count = x+1;
 558                         break;
 559                 case 2: /* erase whole line */
 560                         start = pos - (x<<1);
 561                         count = video_num_columns;
 562                         break;
 563                 default:
 564                         return;
 565         }
 566         __asm__("cld\n\t"
 567                 "rep\n\t"
 568                 "stosw\n\t"
 569                 : /* no output */
 570                 :"c" (count),
 571                 "D" (start),"a" (video_erase_char)
 572                 :"cx","di");
 573         need_wrap = 0;
 574 }
 575 
 576 /*
 577  *  I hope this works. The monochrome part is untested.
 578  */
 579 static void update_attr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 580 {
 581         attr = color;
 582         if (can_do_color) {
 583                 if (underline)
 584                         attr = (attr & 0xf0) | ulcolor;
 585                 else if (intensity == 0)
 586                         attr = (attr & 0xf0) | halfcolor;
 587         }
 588         if (reverse ^ decscnm)
 589                 attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77);
 590         if (blink)
 591                 attr ^= 0x80;
 592         if (intensity == 2)
 593                 attr ^= 0x08;
 594         if (!can_do_color) {
 595                 if (underline)
 596                         attr = (attr & 0xf8) | 0x01;
 597                 else if (intensity == 0)
 598                         attr = (attr & 0xf0) | 0x08;
 599         }
 600         if (decscnm)
 601                 video_erase_char = ((color & 0x88) | (((color >> 4) |
 602                         (color << 4)) & 0x77) << 8) | ' ';
 603         else
 604                 video_erase_char = (color << 8) | ' ';
 605 }
 606 
 607 static void default_attr(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 608 {
 609         intensity = 1;
 610         underline = 0;
 611         reverse = 0;
 612         blink = 0;
 613         color = def_color;
 614 }
 615 
 616 static void csi_m(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 {
 618         int i;
 619 
 620         for (i=0;i<=npar;i++)
 621                 switch (par[i]) {
 622                         case 0: /* all attributes off */
 623                                 default_attr(currcons);
 624                                 break;
 625                         case 1:
 626                                 intensity = 2;
 627                                 break;
 628                         case 2:
 629                                 intensity = 0;
 630                                 break;
 631                         case 4:
 632                                 underline = 1;
 633                                 break;
 634                         case 5:
 635                                 blink = 1;
 636                                 break;
 637                         case 7:
 638                                 reverse = 1;
 639                                 break;
 640                         case 21:
 641                         case 22:
 642                                 intensity = 1;
 643                                 break;
 644                         case 24:
 645                                 underline = 0;
 646                                 break;
 647                         case 25:
 648                                 blink = 0;
 649                                 break;
 650                         case 27:
 651                                 reverse = 0;
 652                                 break;
 653                         case 39:
 654                                 color = (def_color & 0x0f) | background;
 655                                 break;
 656                         case 49:
 657                                 color = (def_color & 0xf0) | foreground;
 658                                 break;
 659                         default:
 660                                 if (par[i] >= 30 && par[i] <= 37)
 661                                         color = color_table[par[i]-30]
 662                                                 | background; 
 663                                 else if (par[i] >= 40 && par[i] <= 47)
 664                                         color = (color_table[par[i]-40]<<4)
 665                                                 | foreground;
 666                                 break;
 667                 }
 668         update_attr(currcons);
 669 }
 670 
 671 static void respond_string(char * p, int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 672 {
 673         while (*p) {
 674                 put_tty_queue(*p, &tty->read_q);
 675                 p++;
 676         }
 677         TTY_READ_FLUSH(tty);
 678 }
 679 
 680 static void respond_num(unsigned int n, int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 681 {
 682         char buff[3];
 683         int i = 0;
 684 
 685         do {
 686                 buff[i++] = (n%10)+'0';
 687                 n /= 10;
 688         } while(n && i < 3);    /* We'll take no chances */
 689         while (i--) {
 690                 put_tty_queue(buff[i], &tty->read_q);
 691         }
 692         /* caller must flush */
 693 }
 694 
 695 static void cursor_report(int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 696 {
 697         put_tty_queue('\033', &tty->read_q);
 698         put_tty_queue('[', &tty->read_q);
 699         respond_num(y + (decom ? top+1 : 1), currcons, tty);
 700         put_tty_queue(';', &tty->read_q);
 701         respond_num(x+1, currcons, tty);
 702         put_tty_queue('R', &tty->read_q);
 703         TTY_READ_FLUSH(tty);
 704 }
 705 
 706 static inline void status_report(int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 707 {
 708         respond_string("\033[0n", currcons, tty);       /* Terminal ok */
 709 }
 710 
 711 static inline void respond_ID(int currcons, struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 712 {
 713         respond_string(VT102ID, currcons, tty);
 714 }
 715 
 716 static void invert_screen(int currcons) {
     /* [previous][next][first][last][top][bottom][index][help] */
 717         unsigned char *p;
 718 
 719         if (can_do_color)
 720                 for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
 721                         *p = (*p & 0x88) | (((*p >> 4) | (*p << 4)) & 0x77);
 722         else
 723                 for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
 724                         *p ^= *p & 0x07 == 1 ? 0x70 : 0x77;
 725 }
 726 
 727 static void set_mode(int currcons, int on_off)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729         int i;
 730 
 731         for (i=0; i<=npar; i++)
 732                 if (ques) switch(par[i]) {      /* DEC private modes set/reset */
 733                         case 1:                 /* Cursor keys send ^[Ox/^[[x */
 734                                 if (on_off)
 735                                         set_kbd(decckm);
 736                                 else
 737                                         clr_kbd(decckm);
 738                                 break;
 739                         case 3: /* 80/132 mode switch unimplemented */
 740                                 csi_J(currcons,2);
 741                                 gotoxy(currcons,0,0);
 742                                 break;
 743                         case 5:                 /* Inverted screen on/off */
 744                                 if (decscnm != on_off) {
 745                                         decscnm = on_off;
 746                                         invert_screen(currcons);
 747                                         update_attr(currcons);
 748                                 }
 749                                 break;
 750                         case 6:                 /* Origin relative/absolute */
 751                                 decom = on_off;
 752                                 gotoxy(currcons,0,0);
 753                                 break;
 754                         case 7:                 /* Autowrap on/off */
 755                                 decawm = on_off;
 756                                 break;
 757                         case 8:                 /* Autorepeat on/off */
 758                                 if (on_off)
 759                                         set_kbd(decarm);
 760                                 else
 761                                         clr_kbd(decarm);
 762                                 break;
 763                         case 25:                /* Cursor on/off */
 764                                 deccm = on_off;
 765                                 set_cursor(currcons);
 766                                 break;
 767                 } else switch(par[i]) {         /* ANSI modes set/reset */
 768                         case 4:                 /* Insert Mode on/off */
 769                                 decim = on_off;
 770                                 break;
 771                         case 20:                /* Lf, Enter == CrLf/Lf */
 772                                 if (on_off)
 773                                         set_kbd(lnm);
 774                                 else
 775                                         clr_kbd(lnm);
 776                                 break;
 777                 }
 778 }
 779 
 780 static void setterm_command(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 781 {
 782         switch(par[0]) {
 783                 case 1: /* set color for underline mode */
 784                         if (can_do_color && par[1] < 16) {
 785                                 ulcolor = color_table[par[1]];
 786                                 if (underline)
 787                                         update_attr(currcons);
 788                         }
 789                         break;
 790                 case 2: /* set color for half intensity mode */
 791                         if (can_do_color && par[1] < 16) {
 792                                 halfcolor = color_table[par[1]];
 793                                 if (intensity == 0)
 794                                         update_attr(currcons);
 795                         }
 796                         break;
 797                 case 8: /* store colors as defaults */
 798                         def_color = attr;
 799                         default_attr(currcons);
 800                         update_attr(currcons);
 801                         break;
 802                 case 9: /* set blanking interval */
 803                         blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
 804                         break;
 805         }
 806 }
 807 
 808 static void insert_char(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 809 {
 810         unsigned int i = x;
 811         unsigned short tmp, old = video_erase_char;
 812         unsigned short * p = (unsigned short *) pos;
 813 
 814         while (i++ < video_num_columns) {
 815                 tmp = *p;
 816                 *p = old;
 817                 old = tmp;
 818                 p++;
 819         }
 820         need_wrap = 0;
 821 }
 822 
 823 static void insert_line(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 824 {
 825         scrdown(currcons,y,bottom);
 826         need_wrap = 0;
 827 }
 828 
 829 static void delete_char(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 830 {
 831         unsigned int i = x;
 832         unsigned short * p = (unsigned short *) pos;
 833 
 834         while (++i < video_num_columns) {
 835                 *p = *(p+1);
 836                 p++;
 837         }
 838         *p = video_erase_char;
 839         need_wrap = 0;
 840 }
 841 
 842 static void delete_line(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 843 {
 844         scrup(currcons,y,bottom);
 845         need_wrap = 0;
 846 }
 847 
 848 static void csi_at(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 849 {
 850         if (nr > video_num_columns)
 851                 nr = video_num_columns;
 852         else if (!nr)
 853                 nr = 1;
 854         while (nr--)
 855                 insert_char(currcons);
 856 }
 857 
 858 static void csi_L(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 859 {
 860         if (nr > video_num_lines)
 861                 nr = video_num_lines;
 862         else if (!nr)
 863                 nr = 1;
 864         while (nr--)
 865                 insert_line(currcons);
 866 }
 867 
 868 static void csi_P(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 869 {
 870         if (nr > video_num_columns)
 871                 nr = video_num_columns;
 872         else if (!nr)
 873                 nr = 1;
 874         while (nr--)
 875                 delete_char(currcons);
 876 }
 877 
 878 static void csi_M(int currcons, unsigned int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 879 {
 880         if (nr > video_num_lines)
 881                 nr = video_num_lines;
 882         else if (!nr)
 883                 nr=1;
 884         while (nr--)
 885                 delete_line(currcons);
 886 }
 887 
 888 static void save_cur(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 889 {
 890         saved_x         = x;
 891         saved_y         = y;
 892         s_intensity     = intensity;
 893         s_underline     = underline;
 894         s_blink         = blink;
 895         s_reverse       = reverse;
 896         s_charset       = charset;
 897         s_color         = color;
 898         saved_G0        = G0_charset;
 899         saved_G1        = G1_charset;
 900 }
 901 
 902 static void restore_cur(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
 903 {
 904         gotoxy(currcons,saved_x,saved_y);
 905         intensity       = s_intensity;
 906         underline       = s_underline;
 907         blink           = s_blink;
 908         reverse         = s_reverse;
 909         charset         = s_charset;
 910         color           = s_color;
 911         G0_charset      = saved_G0;
 912         G1_charset      = saved_G1;
 913         translate       = charset ? G1_charset : G0_charset;
 914         update_attr(currcons);
 915         need_wrap = 0;
 916 }
 917 
 918 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, 
 919         EShash, ESsetG0, ESsetG1, ESignore };
 920 
 921 static void reset_terminal(int currcons, int do_clear)
     /* [previous][next][first][last][top][bottom][index][help] */
 922 {
 923         top             = 0;
 924         bottom          = video_num_lines;
 925         state           = ESnormal;
 926         ques            = 0;
 927         translate       = NORM_TRANS;
 928         G0_charset      = NORM_TRANS;
 929         G1_charset      = GRAF_TRANS;
 930         charset         = 0;
 931         need_wrap       = 0;
 932 
 933         decscnm         = 0;
 934         decom           = 0;
 935         decawm          = 1;
 936         deccm           = 1;
 937         decim           = 0;
 938 
 939         set_kbd(decarm);
 940         clr_kbd(decckm);
 941         clr_kbd(kbdapplic);
 942         clr_kbd(lnm);
 943         kbd_table[currcons].flags =
 944                 (kbd_table[currcons].flags & ~LED_MASK) |
 945                 (kbd_table[currcons].default_flags & LED_MASK);
 946         kbdmode         = 0;
 947         set_leds();
 948 
 949         default_attr(currcons);
 950         update_attr(currcons);
 951 
 952         tab_stop[0]     = 0x01010100;
 953         tab_stop[1]     =
 954         tab_stop[2]     =
 955         tab_stop[3]     =
 956         tab_stop[4]     = 0x01010101;
 957 
 958         if (do_clear) {
 959                 gotoxy(currcons,0,0);
 960                 csi_J(currcons,2);
 961                 save_cur(currcons);
 962         }
 963 }
 964 
 965 void con_write(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 966 {
 967         int c;
 968         unsigned int currcons;
 969 
 970         currcons = tty->line - 1;
 971         if (currcons >= NR_CONSOLES) {
 972                 printk("con_write: illegal tty (%d)\n", currcons);
 973                 return;
 974         }
 975 #ifdef CONFIG_SELECTION
 976         /* clear the selection as soon as any characters are to be written
 977            out on the console holding the selection. */
 978         if (!EMPTY(&tty->write_q) && currcons == sel_cons)
 979                 clear_selection();
 980 #endif /* CONFIG_SELECTION */
 981         disable_bh(KEYBOARD_BH);
 982         while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) {
 983                 if (state == ESnormal && translate[c]) {
 984                         if (need_wrap) {
 985                                 cr(currcons);
 986                                 lf(currcons);
 987                         }
 988                         if (decim)
 989                                 insert_char(currcons);
 990                         c = translate[c];
 991                         *(unsigned short *) pos = (attr << 8) + c;
 992                         if (x == video_num_columns - 1)
 993                                 need_wrap = decawm;
 994                         else {
 995                                 x++;
 996                                 pos+=2;
 997                         }
 998                         continue;
 999                 }
1000 
1001                 /*
1002                  *  Control characters can be used in the _middle_
1003                  *  of an escape sequence.
1004                  */
1005                 switch (c) {
1006                         case 7:
1007                                 kd_mksound(0x637, HZ/8);
1008                                 continue;
1009                         case 8:
1010                                 bs(currcons);
1011                                 continue;
1012                         case 9:
1013                                 pos -= (x << 1);
1014                                 while (x < video_num_columns - 1) {
1015                                         x++;
1016                                         if (tab_stop[x >> 5] & (1 << (x & 31)))
1017                                                 break;
1018                                 }
1019                                 pos += (x << 1);
1020                                 continue;
1021                         case 10: case 11: case 12:
1022                                 lf(currcons);
1023                                 if (!is_kbd(lnm))
1024                                         continue;
1025                         case 13:
1026                                 cr(currcons);
1027                                 continue;
1028                         case 14:
1029                                 charset = 1;
1030                                 translate = G1_charset;
1031                                 continue;
1032                         case 15:
1033                                 charset = 0;
1034                                 translate = G0_charset;
1035                                 continue;
1036                         case 24: case 26:
1037                                 state = ESnormal;
1038                                 continue;
1039                         case 27:
1040                                 state = ESesc;
1041                                 continue;
1042                         case 127:
1043                                 del(currcons);
1044                                 continue;
1045                         case 128+27:
1046                                 state = ESsquare;
1047                                 continue;
1048                 }
1049                 switch(state) {
1050                         case ESesc:
1051                                 state = ESnormal;
1052                                 switch (c) {
1053                                   case '[':
1054                                         state = ESsquare;
1055                                         continue;
1056                                   case 'E':
1057                                         cr(currcons);
1058                                         lf(currcons);
1059                                         continue;
1060                                   case 'M':
1061                                         ri(currcons);
1062                                         continue;
1063                                   case 'D':
1064                                         lf(currcons);
1065                                         continue;
1066                                   case 'H':
1067                                         tab_stop[x >> 5] |= (1 << (x & 31));
1068                                         continue;
1069                                   case 'Z':
1070                                         respond_ID(currcons,tty);
1071                                         continue;
1072                                   case '7':
1073                                         save_cur(currcons);
1074                                         continue;
1075                                   case '8':
1076                                         restore_cur(currcons);
1077                                         continue;
1078                                   case '(':
1079                                         state = ESsetG0;
1080                                         continue;
1081                                   case ')':
1082                                         state = ESsetG1;
1083                                         continue;
1084                                   case '#':
1085                                         state = EShash;
1086                                         continue;
1087                                   case 'c':
1088                                         reset_terminal(currcons,1);
1089                                         continue;
1090                                   case '>':  /* Numeric keypad */
1091                                         clr_kbd(kbdapplic);
1092                                         continue;
1093                                   case '=':  /* Appl. keypad */
1094                                         set_kbd(kbdapplic);
1095                                         continue;
1096                                 }       
1097                                 continue;
1098                         case ESsquare:
1099                                 for(npar = 0 ; npar < NPAR ; npar++)
1100                                         par[npar] = 0;
1101                                 npar = 0;
1102                                 state = ESgetpars;
1103                                 if (c == '[') { /* Function key */
1104                                         state=ESfunckey;
1105                                         continue;
1106                                 }
1107                                 ques = (c=='?');
1108                                 if (ques)
1109                                         continue;
1110                         case ESgetpars:
1111                                 if (c==';' && npar<NPAR-1) {
1112                                         npar++;
1113                                         continue;
1114                                 } else if (c>='0' && c<='9') {
1115                                         par[npar] *= 10;
1116                                         par[npar] += c-'0';
1117                                         continue;
1118                                 } else state=ESgotpars;
1119                         case ESgotpars:
1120                                 state = ESnormal;
1121                                 switch(c) {
1122                                         case 'h':
1123                                                 set_mode(currcons,1);
1124                                                 continue;
1125                                         case 'l':
1126                                                 set_mode(currcons,0);
1127                                                 continue;
1128                                         case 'n':
1129                                                 if (!ques)
1130                                                         if (par[0] == 5)
1131                                                                 status_report(currcons,tty);
1132                                                         else if (par[0] == 6)
1133                                                                 cursor_report(currcons,tty);
1134                                                 continue;
1135                                 }
1136                                 if (ques) {
1137                                         ques = 0;
1138                                         continue;
1139                                 }
1140                                 switch(c) {
1141                                         case 'G': case '`':
1142                                                 if (par[0]) par[0]--;
1143                                                 gotoxy(currcons,par[0],y);
1144                                                 continue;
1145                                         case 'A':
1146                                                 if (!par[0]) par[0]++;
1147                                                 gotoxy(currcons,x,y-par[0]);
1148                                                 continue;
1149                                         case 'B': case 'e':
1150                                                 if (!par[0]) par[0]++;
1151                                                 gotoxy(currcons,x,y+par[0]);
1152                                                 continue;
1153                                         case 'C': case 'a':
1154                                                 if (!par[0]) par[0]++;
1155                                                 gotoxy(currcons,x+par[0],y);
1156                                                 continue;
1157                                         case 'D':
1158                                                 if (!par[0]) par[0]++;
1159                                                 gotoxy(currcons,x-par[0],y);
1160                                                 continue;
1161                                         case 'E':
1162                                                 if (!par[0]) par[0]++;
1163                                                 gotoxy(currcons,0,y+par[0]);
1164                                                 continue;
1165                                         case 'F':
1166                                                 if (!par[0]) par[0]++;
1167                                                 gotoxy(currcons,0,y-par[0]);
1168                                                 continue;
1169                                         case 'd':
1170                                                 if (par[0]) par[0]--;
1171                                                 gotoxy(currcons,x,par[0]);
1172                                                 continue;
1173                                         case 'H': case 'f':
1174                                                 if (par[0]) par[0]--;
1175                                                 if (par[1]) par[1]--;
1176                                                 gotoxy(currcons,par[1],par[0]);
1177                                                 continue;
1178                                         case 'J':
1179                                                 csi_J(currcons,par[0]);
1180                                                 continue;
1181                                         case 'K':
1182                                                 csi_K(currcons,par[0]);
1183                                                 continue;
1184                                         case 'L':
1185                                                 csi_L(currcons,par[0]);
1186                                                 continue;
1187                                         case 'M':
1188                                                 csi_M(currcons,par[0]);
1189                                                 continue;
1190                                         case 'P':
1191                                                 csi_P(currcons,par[0]);
1192                                                 continue;
1193                                         case 'c':
1194                                                 if (!par[0])
1195                                                         respond_ID(currcons,tty);
1196                                                 continue;
1197                                         case 'g':
1198                                                 if (!par[0])
1199                                                         tab_stop[x >> 5] &= ~(1 << (x & 31));
1200                                                 else if (par[0] == 3) {
1201                                                         tab_stop[0] =
1202                                                         tab_stop[1] =
1203                                                         tab_stop[2] =
1204                                                         tab_stop[3] =
1205                                                         tab_stop[4] = 0;
1206                                                 }
1207                                                 continue;
1208                                         case 'm':
1209                                                 csi_m(currcons);
1210                                                 continue;
1211                                         case 'r':
1212                                                 if (!par[0])
1213                                                         par[0]++;
1214                                                 if (!par[1])
1215                                                         par[1] = video_num_lines;
1216                                                 /* Minimum allowed region is 2 lines */
1217                                                 if (par[0] < par[1] &&
1218                                                     par[1] <= video_num_lines) {
1219                                                         top=par[0]-1;
1220                                                         bottom=par[1];
1221                                                         gotoxy(currcons,0,0);
1222                                                 }
1223                                                 continue;
1224                                         case 's':
1225                                                 save_cur(currcons);
1226                                                 continue;
1227                                         case 'u':
1228                                                 restore_cur(currcons);
1229                                                 continue;
1230                                         case '@':
1231                                                 csi_at(currcons,par[0]);
1232                                                 continue;
1233                                         case ']': /* setterm functions */
1234                                                 setterm_command(currcons);
1235                                                 continue;
1236                                 }
1237                                 continue;
1238                         case ESfunckey:
1239                                 state = ESnormal;
1240                                 continue;
1241                         case EShash:
1242                                 state = ESnormal;
1243                                 if (c == '8') {
1244                                         /* DEC screen alignment test. kludge :-) */
1245                                         video_erase_char =
1246                                                 (video_erase_char & 0xff00) | 'E';
1247                                         csi_J(currcons, 2);
1248                                         video_erase_char =
1249                                                 (video_erase_char & 0xff00) | ' ';
1250                                 }
1251                                 continue;
1252                         case ESsetG0:
1253                                 if (c == '0')
1254                                         G0_charset = GRAF_TRANS;
1255                                 else if (c == 'B')
1256                                         G0_charset = NORM_TRANS;
1257                                 else if (c == 'U')
1258                                         G0_charset = NULL_TRANS;
1259                                 if (charset == 0)
1260                                         translate = G0_charset;
1261                                 state = ESnormal;
1262                                 continue;
1263                         case ESsetG1:
1264                                 if (c == '0')
1265                                         G1_charset = GRAF_TRANS;
1266                                 else if (c == 'B')
1267                                         G1_charset = NORM_TRANS;
1268                                 else if (c == 'U')
1269                                         G1_charset = NULL_TRANS;
1270                                 if (charset == 1)
1271                                         translate = G1_charset;
1272                                 state = ESnormal;
1273                                 continue;
1274                         default:
1275                                 state = ESnormal;
1276                 }
1277         }
1278         if (vcmode != KD_GRAPHICS)
1279                 set_cursor(currcons);
1280         enable_bh(KEYBOARD_BH);
1281         if (LEFT(&tty->write_q) > WAKEUP_CHARS)
1282                 wake_up_interruptible(&tty->write_q.proc_list);
1283 }
1284 
1285 void do_keyboard_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1286 {
1287         TTY_READ_FLUSH(TTY_TABLE(0));
1288         timer_active &= ~(1<<BLANK_TIMER);
1289         if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
1290                 return;
1291         if (console_blanked) {
1292                 timer_table[BLANK_TIMER].expires = 0;
1293                 timer_active |= 1<<BLANK_TIMER;
1294         } else if (blankinterval) {
1295                 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1296                 timer_active |= 1<<BLANK_TIMER;
1297         }
1298 }
1299 
1300 void * memsetw(void * s,unsigned short c,int count)
     /* [previous][next][first][last][top][bottom][index][help] */
1301 {
1302 __asm__("cld\n\t"
1303         "rep\n\t"
1304         "stosw"
1305         : /* no output */
1306         :"a" (c),"D" (s),"c" (count)
1307         :"cx","di");
1308 return s;
1309 }
1310 
1311 void console_print(const char * b)
     /* [previous][next][first][last][top][bottom][index][help] */
1312 {
1313         int currcons = fg_console;
1314         unsigned char c;
1315 
1316         if (!printable || currcons<0 || currcons>=NR_CONSOLES)
1317                 return;
1318         while ((c = *(b++)) != 0) {
1319                 if (c == 10 || c == 13 || need_wrap) {
1320                         if (c != 13)
1321                                 lf(currcons);
1322                         cr(currcons);
1323                         if (c == 10 || c == 13)
1324                                 continue;
1325                 }
1326                 *(unsigned short *) pos = (attr << 8) + c;
1327                 if (x == video_num_columns - 1) {
1328                         need_wrap = 1;
1329                         continue;
1330                 }
1331                 x++;
1332                 pos+=2;
1333         }
1334         set_cursor(currcons);
1335         if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
1336                 return;
1337         timer_active &= ~(1<<BLANK_TIMER);
1338         if (console_blanked) {
1339                 timer_table[BLANK_TIMER].expires = 0;
1340                 timer_active |= 1<<BLANK_TIMER;
1341         } else if (blankinterval) {
1342                 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1343                 timer_active |= 1<<BLANK_TIMER;
1344         }
1345 }
1346 
1347 /*
1348  *  long con_init(long);
1349  *
1350  * This routine initalizes console interrupts, and does nothing
1351  * else. If you want the screen to clear, call tty_write with
1352  * the appropriate escape-sequece.
1353  *
1354  * Reads the information preserved by setup.s to determine the current display
1355  * type and sets everything accordingly.
1356  */
1357 long con_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
1358 {
1359         char *display_desc = "????";
1360         int currcons = 0;
1361         long base;
1362         int orig_x = ORIG_X;
1363         int orig_y = ORIG_Y;
1364 
1365         vc_scrmembuf = (unsigned short *) kmem_start;
1366         video_num_columns = ORIG_VIDEO_COLS;
1367         video_size_row = video_num_columns * 2;
1368         video_num_lines = ORIG_VIDEO_LINES;
1369         video_page = ORIG_VIDEO_PAGE;
1370         screen_size = (video_num_lines * video_size_row);
1371         kmem_start += NR_CONSOLES * screen_size;
1372         timer_table[BLANK_TIMER].fn = blank_screen;
1373         timer_table[BLANK_TIMER].expires = 0;
1374         if (blankinterval) {
1375                 timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
1376                 timer_active |= 1<<BLANK_TIMER;
1377         }
1378         
1379         if (ORIG_VIDEO_MODE == 7)       /* Is this a monochrome display? */
1380         {
1381                 video_mem_base = 0xb0000;
1382                 video_port_reg = 0x3b4;
1383                 video_port_val = 0x3b5;
1384                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1385                 {
1386                         video_type = VIDEO_TYPE_EGAM;
1387                         video_mem_term = 0xb8000;
1388                         display_desc = "EGA+";
1389                 }
1390                 else
1391                 {
1392                         video_type = VIDEO_TYPE_MDA;
1393                         video_mem_term = 0xb2000;
1394                         display_desc = "*MDA";
1395                 }
1396         }
1397         else                            /* If not, it is color. */
1398         {
1399                 can_do_color = 1;
1400                 video_mem_base = 0xb8000;
1401                 video_port_reg  = 0x3d4;
1402                 video_port_val  = 0x3d5;
1403                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1404                 {
1405                         video_type = VIDEO_TYPE_EGAC;
1406                         video_mem_term = 0xc0000;
1407                         display_desc = "EGA+";
1408                 }
1409                 else
1410                 {
1411                         video_type = VIDEO_TYPE_CGA;
1412                         video_mem_term = 0xba000;
1413                         display_desc = "*CGA";
1414                 }
1415         }
1416         
1417         /* Initialize the variables used for scrolling (mostly EGA/VGA) */
1418 
1419         base = (long)vc_scrmembuf;
1420         for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
1421                 pos = origin = video_mem_start = base;
1422                 scr_end = video_mem_end = (base += screen_size);
1423                 vc_scrbuf[currcons] = (unsigned short *) origin;
1424                 vcmode          = KD_TEXT;
1425                 vtmode.mode     = VT_AUTO;
1426                 vtmode.waitv    = 0;
1427                 vtmode.relsig   = 0;
1428                 vtmode.acqsig   = 0;
1429                 vtmode.frsig    = 0;
1430                 vtpid           = -1;
1431                 vtnewvt         = -1;
1432                 clr_kbd(kbdraw);
1433                 def_color       = 0x07;   /* white */
1434                 ulcolor         = 0x0f;   /* bold white */
1435                 halfcolor       = 0x08;   /* grey */
1436                 reset_terminal(currcons, currcons);
1437         }
1438         currcons = fg_console = 0;
1439 
1440         video_mem_start = video_mem_base;
1441         video_mem_end = video_mem_term;
1442         origin = video_mem_start;
1443         scr_end = video_mem_start + video_num_lines * video_size_row;
1444         gotoxy(currcons,0,0);
1445         save_cur(currcons);
1446         gotoxy(currcons,orig_x,orig_y);
1447         update_screen(fg_console);
1448         printable = 1;
1449         printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
1450                 can_do_color?"colour":"mono",
1451                 display_desc,
1452                 video_num_columns,video_num_lines,
1453                 NR_CONSOLES);
1454         register_console(console_print);
1455         return kmem_start;
1456 }
1457 
1458 /*
1459  * kbdsave doesn't need to do anything: it's all handled automatically
1460  * with the new data structures..
1461  */
1462 void kbdsave(int new_console)
     /* [previous][next][first][last][top][bottom][index][help] */
1463 {
1464 }
1465 
1466 static void get_scrmem(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1467 {
1468         memcpy((void *)vc_scrbuf[currcons],(void *)origin, screen_size);
1469         video_mem_start = (unsigned long)vc_scrbuf[currcons];
1470         origin  = video_mem_start;
1471         scr_end = video_mem_end = video_mem_start+screen_size;
1472         pos = origin + y*video_size_row + (x<<1);
1473 }
1474 
1475 static void set_scrmem(int currcons)
     /* [previous][next][first][last][top][bottom][index][help] */
1476 {
1477 #ifdef CONFIG_HGA
1478   /* This works with XFree86 1.2, 1.3 and 2.0
1479      This code could be extended and made more generally useful if we could
1480      determine the actual video mode. It appears that this should be
1481      possible on a genuine Hercules card, but I (WM) haven't been able to
1482      read from any of the required registers on my clone card.
1483      */
1484         /* This code should work with Hercules and MDA cards. */
1485         if (video_type == VIDEO_TYPE_MDA)
1486           {
1487             if (vcmode == KD_TEXT)
1488               {
1489                 /* Ensure that the card is in text mode. */
1490                 int     i;
1491                 static char herc_txt_tbl[12] = {
1492                   0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
1493                 outb_p(0, 0x3bf);  /* Back to power-on defaults */
1494                 outb_p(0, 0x3b8);  /* Blank the screen, select page 0, etc */
1495                 for ( i = 0 ; i < 12 ; i++ )
1496                   {
1497                     outb_p(i, 0x3b4);
1498                     outb_p(herc_txt_tbl[i], 0x3b5);
1499                   }
1500               }
1501 #define HGA_BLINKER_ON 0x20
1502 #define HGA_SCREEN_ON  8
1503             /* Make sure that the hardware is not blanked */
1504             outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
1505           }
1506 #endif CONFIG_HGA
1507 
1508         video_mem_start = video_mem_base;
1509         video_mem_end = video_mem_term;
1510         origin  = video_mem_start;
1511         scr_end = video_mem_start + screen_size;
1512         pos = origin + y*video_size_row + (x<<1);
1513         memcpy((void *)video_mem_base, (void *)vc_scrbuf[fg_console], screen_size);
1514 }
1515 
1516 void blank_screen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1517 {
1518         if (console_blanked)
1519                 return;
1520         timer_table[BLANK_TIMER].fn = unblank_screen;
1521         get_scrmem(fg_console);
1522         hide_cursor(fg_console);
1523         console_blanked = 1;
1524         memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
1525 }
1526 
1527 void unblank_screen(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1528 {
1529         if (!console_blanked)
1530                 return;
1531         timer_table[BLANK_TIMER].fn = blank_screen;
1532         if (blankinterval) {
1533                 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1534                 timer_active |= 1<<BLANK_TIMER;
1535         }
1536         console_blanked = 0;
1537         set_scrmem(fg_console);
1538         set_origin(fg_console);
1539         set_cursor(fg_console);
1540 }
1541 
1542 void update_screen(int new_console)
     /* [previous][next][first][last][top][bottom][index][help] */
1543 {
1544         static int lock = 0;
1545 
1546         if (new_console == fg_console || lock)
1547                 return;
1548         lock = 1;
1549         kbdsave(new_console);
1550         get_scrmem(fg_console); 
1551         fg_console = new_console;
1552         set_scrmem(fg_console); 
1553         set_origin(fg_console);
1554         set_cursor(new_console);
1555         set_leds();
1556         compute_shiftstate();
1557         lock = 0;
1558 }
1559 
1560 int do_screendump(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1561 {
1562         char *sptr, *buf = (char *)arg;
1563         int currcons, l;
1564 
1565         if (!suser())
1566                 return -EPERM;
1567         l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
1568         if (l)
1569                 return l;
1570         currcons = get_fs_byte(buf+1);
1571         if ((currcons<0) || (currcons>NR_CONSOLES))
1572                 return -EIO;
1573         put_fs_byte((char)(video_num_lines),buf++);     
1574         put_fs_byte((char)(video_num_columns),buf++);
1575         currcons = (currcons ? currcons-1 : fg_console);
1576         sptr = (char *) origin;
1577         for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
1578                 put_fs_byte(*sptr++,buf++);     
1579         return(0);
1580 }
1581 
1582 /*
1583  * All we do is set the write and ioctl subroutines; later on maybe we'll
1584  * dynamically allocate the console screen memory.
1585  */
1586 int con_open(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
1587 {
1588         tty->write = con_write;
1589         tty->ioctl = vt_ioctl;
1590         if (tty->line > NR_CONSOLES)
1591                 return -ENODEV;
1592         return 0;
1593 }
1594 
1595 #ifdef CONFIG_SELECTION
1596 /* correction factor for when screen is hardware-scrolled */
1597 #define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0)
1598 
1599 /* set reverse video on characters s-e of console with selection. */
1600 static void highlight(const int currcons, const int s, const int e)
     /* [previous][next][first][last][top][bottom][index][help] */
1601 {
1602         unsigned char *p, *p1, *p2;
1603 
1604         p1 = (unsigned char *)origin - hwscroll_offset + s + 1;
1605         p2 = (unsigned char *)origin - hwscroll_offset + e + 1;
1606         if (p1 > p2)
1607         {
1608                 p = p1;
1609                 p1 = p2;
1610                 p2 = p;
1611         }
1612         for (p = p1; p <= p2; p += 2)
1613                 *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
1614 }
1615 
1616 /* is c in range [a-zA-Z0-9_]? */
1617 static inline int inword(const char c) { return (isalnum(c) || c == '_'); }
     /* [previous][next][first][last][top][bottom][index][help] */
1618 
1619 /* does screen address p correspond to character at LH/RH edge of screen? */
1620 static inline int atedge(const int p)
     /* [previous][next][first][last][top][bottom][index][help] */
1621 {
1622         return (!(p % video_size_row) || !((p + 2) % video_size_row));
1623 }
1624 
1625 /* constrain v such that l <= v <= u */
1626 static inline short limit(const int v, const int l, const int u)
     /* [previous][next][first][last][top][bottom][index][help] */
1627 {
1628         return (v < l) ? l : ((v > u) ? u : v);
1629 }
1630 
1631 /* set the current selection. Invoked by ioctl(). */
1632 int set_selection(const int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1633 {
1634         unsigned short *args, xs, ys, xe, ye;
1635         int currcons = fg_console;
1636         int sel_mode, new_sel_start, new_sel_end, spc;
1637         char *bp, *obp, *spos;
1638         int i, ps, pe;
1639         char *off = (char *)origin - hwscroll_offset;
1640 
1641         unblank_screen();
1642         args = (unsigned short *)(arg + 1);
1643         xs = get_fs_word(args++) - 1;
1644         ys = get_fs_word(args++) - 1;
1645         xe = get_fs_word(args++) - 1;
1646         ye = get_fs_word(args++) - 1;
1647         sel_mode = get_fs_word(args);
1648 
1649         xs = limit(xs, 0, video_num_columns - 1);
1650         ys = limit(ys, 0, video_num_lines - 1);
1651         xe = limit(xe, 0, video_num_columns - 1);
1652         ye = limit(ye, 0, video_num_lines - 1);
1653         ps = ys * video_size_row + (xs << 1);
1654         pe = ye * video_size_row + (xe << 1);
1655 
1656         if (ps > pe)    /* make sel_start <= sel_end */
1657         {
1658                 int tmp = ps;
1659                 ps = pe;
1660                 pe = tmp;
1661         }
1662 
1663         switch (sel_mode)
1664         {
1665                 case 0: /* character-by-character selection */
1666                 default:
1667                         new_sel_start = ps;
1668                         new_sel_end = pe;
1669                         break;
1670                 case 1: /* word-by-word selection */
1671                         spc = isspace(*(off + ps));
1672                         for (new_sel_start = ps; ; ps -= 2)
1673                         {
1674                                 if ((spc && !isspace(*(off + ps))) ||
1675                                     (!spc && !inword(*(off + ps))))
1676                                         break;
1677                                 new_sel_start = ps;
1678                                 if (!(ps % video_size_row))
1679                                         break;
1680                         }
1681                         spc = isspace(*(off + pe));
1682                         for (new_sel_end = pe; ; pe += 2)
1683                         {
1684                                 if ((spc && !isspace(*(off + pe))) ||
1685                                     (!spc && !inword(*(off + pe))))
1686                                         break;
1687                                 new_sel_end = pe;
1688                                 if (!((pe + 2) % video_size_row))
1689                                         break;
1690                         }
1691                         break;
1692                 case 2: /* line-by-line selection */
1693                         new_sel_start = ps - ps % video_size_row;
1694                         new_sel_end = pe + video_size_row
1695                                     - pe % video_size_row - 2;
1696                         break;
1697         }
1698         /* select to end of line if on trailing space */
1699         if (new_sel_end > new_sel_start &&
1700                 !atedge(new_sel_end) && isspace(*(off + new_sel_end)))
1701         {
1702                 for (pe = new_sel_end + 2; ; pe += 2)
1703                 {
1704                         if (!isspace(*(off + pe)) || atedge(pe))
1705                                 break;
1706                 }
1707                 if (isspace(*(off + pe)))
1708                         new_sel_end = pe;
1709         }
1710         if (sel_cons != currcons)
1711         {
1712                 clear_selection();
1713                 sel_cons = currcons;
1714         }
1715         if (sel_start == -1)    /* no current selection */
1716                 highlight(sel_cons, new_sel_start, new_sel_end);
1717         else if (new_sel_start == sel_start)
1718         {
1719                 if (new_sel_end == sel_end)     /* no action required */
1720                         return 0;
1721                 else if (new_sel_end > sel_end) /* extend to right */
1722                         highlight(sel_cons, sel_end + 2, new_sel_end);
1723                 else                            /* contract from right */
1724                         highlight(sel_cons, new_sel_end + 2, sel_end);
1725         }
1726         else if (new_sel_end == sel_end)
1727         {
1728                 if (new_sel_start < sel_start)  /* extend to left */
1729                         highlight(sel_cons, new_sel_start, sel_start - 2);
1730                 else                            /* contract from left */
1731                         highlight(sel_cons, sel_start, new_sel_start - 2);
1732         }
1733         else    /* some other case; start selection from scratch */
1734         {
1735                 clear_selection();
1736                 highlight(sel_cons, new_sel_start, new_sel_end);
1737         }
1738         sel_start = new_sel_start;
1739         sel_end = new_sel_end;
1740         obp = bp = sel_buffer;
1741         for (i = sel_start; i <= sel_end; i += 2)
1742         {
1743                 spos = (char *)off + i;
1744                 *bp++ = *spos;
1745                 if (!isspace(*spos))
1746                         obp = bp;
1747                 if (! ((i + 2) % video_size_row))
1748                 {
1749                         /* strip trailing blanks from line and add newline,
1750                            unless non-space at end of line. */
1751                         if (obp != bp)
1752                         {
1753                                 bp = obp;
1754                                 *bp++ = '\r';
1755                         }
1756                         obp = bp;
1757                 }
1758                 /* check for space, leaving room for next character, possible
1759                    newline, and null at end. */
1760                 if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
1761                         break;
1762         }
1763         *bp = '\0';
1764         return 0;
1765 }
1766 
1767 /* insert the contents of the selection buffer into the queue of the
1768    tty associated with the current console. Invoked by ioctl(). */
1769 int paste_selection(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
1770 {
1771         char *bp = sel_buffer;
1772 
1773         if (! *bp)
1774                 return 0;
1775         unblank_screen();
1776         while (*bp)
1777         {
1778                 put_tty_queue(*bp, &tty->read_q);
1779                 bp++;
1780         }
1781         TTY_READ_FLUSH(tty);
1782         return 0;
1783 }
1784 
1785 /* remove the current selection highlight, if any, from the console holding
1786    the selection. */
1787 static void clear_selection()
     /* [previous][next][first][last][top][bottom][index][help] */
1788 {
1789         if (sel_start != -1)
1790         {
1791                 highlight(sel_cons, sel_start, sel_end);
1792                 sel_start = -1;
1793         }
1794 }
1795 #endif /* CONFIG_SELECTION */

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