root/drivers/char/console.c

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

DEFINITIONS

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

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

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