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

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