v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / char / console.c
1 /*
2  *  linux/drivers/char/console.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 /*
8  * Hopefully this will be a rather complete VT102 implementation.
9  *
10  * Beeping thanks to John T Kohl.
11  *
12  * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
13  *   Chars, and VT100 enhancements by Peter MacDonald.
14  *
15  * Copy and paste function by Andrew Haylett,
16  *   some enhancements by Alessandro Rubini.
17  *
18  * Code to check for different video-cards mostly by Galen Hunt,
19  * <g-hunt@ee.utah.edu>
20  *
21  * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
22  * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
23  *
24  * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
25  * Resizing of consoles, aeb, 940926
26  *
27  * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
28  * <poe@daimi.aau.dk>
29  *
30  * User-defined bell sound, new setterm control sequences and printk
31  * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
32  *
33  * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
34  *
35  * Merge with the abstract console driver by Geert Uytterhoeven
36  * <geert@linux-m68k.org>, Jan 1997.
37  *
38  *   Original m68k console driver modifications by
39  *
40  *     - Arno Griffioen <arno@usn.nl>
41  *     - David Carter <carter@cs.bris.ac.uk>
42  * 
43  *   Note that the abstract console driver allows all consoles to be of
44  *   potentially different sizes, so the following variables depend on the
45  *   current console (currcons):
46  *
47  *     - video_num_columns
48  *     - video_num_lines
49  *     - video_size_row
50  *     - can_do_color
51  *
52  *   The abstract console driver provides a generic interface for a text
53  *   console. It supports VGA text mode, frame buffer based graphical consoles
54  *   and special graphics processors that are only accessible through some
55  *   registers (e.g. a TMS340x0 GSP).
56  *
57  *   The interface to the hardware is specified using a special structure
58  *   (struct consw) which contains function pointers to console operations
59  *   (see <linux/console.h> for more information).
60  *
61  * Support for changeable cursor shape
62  * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
63  *
64  * Ported to i386 and con_scrolldelta fixed
65  * by Emmanuel Marty <core@ggi-project.org>, April 1998
66  *
67  * Resurrected character buffers in videoram plus lots of other trickery
68  * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
69  *
70  * Removed old-style timers, introduced console_timer, made timer
71  * deletion SMP-safe.  17Jun00, Andrew Morton <andrewm@uow.edu.au>
72  */
73
74 #include <linux/module.h>
75 #include <linux/sched.h>
76 #include <linux/tty.h>
77 #include <linux/tty_flip.h>
78 #include <linux/kernel.h>
79 #include <linux/string.h>
80 #include <linux/errno.h>
81 #include <linux/kd.h>
82 #include <linux/slab.h>
83 #include <linux/major.h>
84 #include <linux/mm.h>
85 #include <linux/console.h>
86 #include <linux/init.h>
87 #include <linux/devfs_fs_kernel.h>
88 #include <linux/vt_kern.h>
89 #include <linux/selection.h>
90 #include <linux/console_struct.h>
91 #include <linux/kbd_kern.h>
92 #include <linux/consolemap.h>
93 #include <linux/timer.h>
94 #include <linux/interrupt.h>
95 #include <linux/config.h>
96 #include <linux/version.h>
97 #include <linux/tqueue.h>
98 #include <linux/bootmem.h>
99 #include <linux/pm.h>
100
101 #include <asm/io.h>
102 #include <asm/system.h>
103 #include <asm/uaccess.h>
104 #include <asm/bitops.h>
105
106 #include "console_macros.h"
107
108
109 const struct consw *conswitchp;
110
111 /* A bitmap for codes <32. A bit of 1 indicates that the code
112  * corresponding to that bit number invokes some special action
113  * (such as cursor movement) and should not be displayed as a
114  * glyph unless the disp_ctrl mode is explicitly enabled.
115  */
116 #define CTRL_ACTION 0x0d00ff81
117 #define CTRL_ALWAYS 0x0800f501  /* Cannot be overridden by disp_ctrl */
118
119 /*
120  * Here is the default bell parameters: 750HZ, 1/8th of a second
121  */
122 #define DEFAULT_BELL_PITCH      750
123 #define DEFAULT_BELL_DURATION   (HZ/8)
124
125 extern void vcs_make_devfs (unsigned int index, int unregister);
126
127 #ifndef MIN
128 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
129 #endif
130
131 static struct tty_struct *console_table[MAX_NR_CONSOLES];
132 static struct termios *console_termios[MAX_NR_CONSOLES];
133 static struct termios *console_termios_locked[MAX_NR_CONSOLES];
134 struct vc vc_cons [MAX_NR_CONSOLES];
135
136 #ifndef VT_SINGLE_DRIVER
137 static const struct consw *con_driver_map[MAX_NR_CONSOLES];
138 #endif
139
140 static int con_open(struct tty_struct *, struct file *);
141 static void vc_init(unsigned int console, unsigned int rows,
142                     unsigned int cols, int do_clear);
143 static void blank_screen(unsigned long dummy);
144 static void gotoxy(int currcons, int new_x, int new_y);
145 static void save_cur(int currcons);
146 static void reset_terminal(int currcons, int do_clear);
147 static void con_flush_chars(struct tty_struct *tty);
148 static void set_vesa_blanking(unsigned long arg);
149 static void set_cursor(int currcons);
150 static void hide_cursor(int currcons);
151 static void unblank_screen_t(unsigned long dummy);
152
153 static int printable;           /* Is console ready for printing? */
154
155 int do_poke_blanked_console;
156 int console_blanked;
157
158 static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
159 static int blankinterval = 10*60*HZ;
160 static int vesa_off_interval;
161
162 /*
163  * fg_console is the current virtual console,
164  * last_console is the last used one,
165  * want_console is the console we want to switch to,
166  * kmsg_redirect is the console for kernel messages,
167  */
168 int fg_console;
169 int last_console;
170 int want_console = -1;
171 int kmsg_redirect;
172
173 /*
174  * For each existing display, we have a pointer to console currently visible
175  * on that display, allowing consoles other than fg_console to be refreshed
176  * appropriately. Unless the low-level driver supplies its own display_fg
177  * variable, we use this one for the "master display".
178  */
179 static struct vc_data *master_display_fg;
180
181 /*
182  * Unfortunately, we need to delay tty echo when we're currently writing to the
183  * console since the code is (and always was) not re-entrant, so we insert
184  * all filp requests to con_task_queue instead of tq_timer and run it from
185  * the console_tasklet.  The console_tasklet is protected by the IRQ
186  * protected console_lock.
187  */
188 DECLARE_TASK_QUEUE(con_task_queue);
189
190 /*
191  * For the same reason, we defer scrollback to the console tasklet.
192  */
193 static int scrollback_delta;
194
195 /*
196  * Hook so that the power management routines can (un)blank
197  * the console on our behalf.
198  */
199 int (*console_blank_hook)(int);
200
201 static struct timer_list console_timer;
202
203 /*
204  *      Low-Level Functions
205  */
206
207 #define IS_FG (currcons == fg_console)
208 #define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
209
210 #ifdef VT_BUF_VRAM_ONLY
211 #define DO_UPDATE 0
212 #else
213 #define DO_UPDATE IS_VISIBLE
214 #endif
215
216 static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
217 static struct pm_dev *pm_con;
218
219 static inline unsigned short *screenpos(int currcons, int offset, int viewed)
220 {
221         unsigned short *p;
222         
223         if (!viewed)
224                 p = (unsigned short *)(origin + offset);
225         else if (!sw->con_screen_pos)
226                 p = (unsigned short *)(visible_origin + offset);
227         else
228                 p = sw->con_screen_pos(vc_cons[currcons].d, offset);
229         return p;
230 }
231
232 static inline void scrolldelta(int lines)
233 {
234         scrollback_delta += lines;
235         tasklet_schedule(&console_tasklet);
236 }
237
238 static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
239 {
240         unsigned short *d, *s;
241
242         if (t+nr >= b)
243                 nr = b - t - 1;
244         if (b > video_num_lines || t >= b || nr < 1)
245                 return;
246         if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
247                 return;
248         d = (unsigned short *) (origin+video_size_row*t);
249         s = (unsigned short *) (origin+video_size_row*(t+nr));
250         scr_memcpyw(d, s, (b-t-nr) * video_size_row);
251         scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
252 }
253
254 static void
255 scrdown(int currcons, unsigned int t, unsigned int b, int nr)
256 {
257         unsigned short *s;
258         unsigned int step;
259
260         if (t+nr >= b)
261                 nr = b - t - 1;
262         if (b > video_num_lines || t >= b || nr < 1)
263                 return;
264         if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
265                 return;
266         s = (unsigned short *) (origin+video_size_row*t);
267         step = video_num_columns * nr;
268         scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
269         scr_memsetw(s, video_erase_char, 2*step);
270 }
271
272 static void do_update_region(int currcons, unsigned long start, int count)
273 {
274 #ifndef VT_BUF_VRAM_ONLY
275         unsigned int xx, yy, offset;
276         u16 *p;
277
278         p = (u16 *) start;
279         if (!sw->con_getxy) {
280                 offset = (start - origin) / 2;
281                 xx = offset % video_num_columns;
282                 yy = offset / video_num_columns;
283         } else {
284                 int nxx, nyy;
285                 start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
286                 xx = nxx; yy = nyy;
287         }
288         for(;;) {
289                 u16 attrib = scr_readw(p) & 0xff00;
290                 int startx = xx;
291                 u16 *q = p;
292                 while (xx < video_num_columns && count) {
293                         if (attrib != (scr_readw(p) & 0xff00)) {
294                                 if (p > q)
295                                         sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
296                                 startx = xx;
297                                 q = p;
298                                 attrib = scr_readw(p) & 0xff00;
299                         }
300                         p++;
301                         xx++;
302                         count--;
303                 }
304                 if (p > q)
305                         sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
306                 if (!count)
307                         break;
308                 xx = 0;
309                 yy++;
310                 if (sw->con_getxy) {
311                         p = (u16 *)start;
312                         start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
313                 }
314         }
315 #endif
316 }
317
318 void update_region(int currcons, unsigned long start, int count)
319 {
320         if (DO_UPDATE) {
321                 hide_cursor(currcons);
322                 do_update_region(currcons, start, count);
323                 set_cursor(currcons);
324         }
325 }
326
327 /* Structure of attributes is hardware-dependent */
328
329 static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
330 {
331         if (sw->con_build_attr)
332                 return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
333
334 #ifndef VT_BUF_VRAM_ONLY
335 /*
336  * ++roman: I completely changed the attribute format for monochrome
337  * mode (!can_do_color). The formerly used MDA (monochrome display
338  * adapter) format didn't allow the combination of certain effects.
339  * Now the attribute is just a bit vector:
340  *  Bit 0..1: intensity (0..2)
341  *  Bit 2   : underline
342  *  Bit 3   : reverse
343  *  Bit 7   : blink
344  */
345         {
346         u8 a = color;
347         if (!can_do_color)
348                 return _intensity |
349                        (_underline ? 4 : 0) |
350                        (_reverse ? 8 : 0) |
351                        (_blink ? 0x80 : 0);
352         if (_underline)
353                 a = (a & 0xf0) | ulcolor;
354         else if (_intensity == 0)
355                 a = (a & 0xf0) | halfcolor;
356         if (_reverse)
357                 a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
358         if (_blink)
359                 a ^= 0x80;
360         if (_intensity == 2)
361                 a ^= 0x08;
362         if (hi_font_mask == 0x100)
363                 a <<= 1;
364         return a;
365         }
366 #else
367         return 0;
368 #endif
369 }
370
371 static void update_attr(int currcons)
372 {
373         attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
374         video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
375 }
376
377 /* Note: inverting the screen twice should revert to the original state */
378
379 void invert_screen(int currcons, int offset, int count, int viewed)
380 {
381         unsigned short *p;
382
383         count /= 2;
384         p = screenpos(currcons, offset, viewed);
385         if (sw->con_invert_region)
386                 sw->con_invert_region(vc_cons[currcons].d, p, count);
387 #ifndef VT_BUF_VRAM_ONLY
388         else {
389                 u16 *q = p;
390                 int cnt = count;
391
392                 if (!can_do_color) {
393                         while (cnt--) *q++ ^= 0x0800;
394                 } else if (hi_font_mask == 0x100) {
395                         while (cnt--) {
396                                 u16 a = *q;
397                                 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
398                                 *q++ = a;
399                         }
400                 } else {
401                         while (cnt--) {
402                                 u16 a = *q;
403                                 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
404                                 *q++ = a;
405                         }
406                 }
407         }
408 #endif
409         if (DO_UPDATE)
410                 do_update_region(currcons, (unsigned long) p, count);
411 }
412
413 /* used by selection: complement pointer position */
414 void complement_pos(int currcons, int offset)
415 {
416         static unsigned short *p;
417         static unsigned short old;
418         static unsigned short oldx, oldy;
419
420         if (p) {
421                 scr_writew(old, p);
422                 if (DO_UPDATE)
423                         sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
424         }
425         if (offset == -1)
426                 p = NULL;
427         else {
428                 unsigned short new;
429                 p = screenpos(currcons, offset, 1);
430                 old = scr_readw(p);
431                 new = old ^ complement_mask;
432                 scr_writew(new, p);
433                 if (DO_UPDATE) {
434                         oldx = (offset >> 1) % video_num_columns;
435                         oldy = (offset >> 1) / video_num_columns;
436                         sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
437                 }
438         }
439 }
440
441 static void insert_char(int currcons, unsigned int nr)
442 {
443         unsigned short *p, *q = (unsigned short *) pos;
444
445         p = q + video_num_columns - nr - x;
446         while (--p >= q)
447                 scr_writew(scr_readw(p), p + nr);
448         scr_memsetw(q, video_erase_char, nr*2);
449         need_wrap = 0;
450         if (DO_UPDATE) {
451                 unsigned short oldattr = attr;
452                 sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
453                               video_num_columns-x-nr);
454                 attr = video_erase_char >> 8;
455                 while (nr--)
456                         sw->con_putc(vc_cons[currcons].d,
457                                      video_erase_char,y,x+nr);
458                 attr = oldattr;
459         }
460 }
461
462 static void delete_char(int currcons, unsigned int nr)
463 {
464         unsigned int i = x;
465         unsigned short *p = (unsigned short *) pos;
466
467         while (++i <= video_num_columns - nr) {
468                 scr_writew(scr_readw(p+nr), p);
469                 p++;
470         }
471         scr_memsetw(p, video_erase_char, nr*2);
472         need_wrap = 0;
473         if (DO_UPDATE) {
474                 unsigned short oldattr = attr;
475                 sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
476                               video_num_columns-x-nr);
477                 attr = video_erase_char >> 8;
478                 while (nr--)
479                         sw->con_putc(vc_cons[currcons].d,
480                                      video_erase_char, y,
481                                      video_num_columns-1-nr);
482                 attr = oldattr;
483         }
484 }
485
486 static int softcursor_original;
487
488 static void add_softcursor(int currcons)
489 {
490         int i = scr_readw((u16 *) pos);
491         u32 type = cursor_type;
492
493         if (! (type & 0x10)) return;
494         if (softcursor_original != -1) return;
495         softcursor_original = i;
496         i |= ((type >> 8) & 0xff00 );
497         i ^= ((type) & 0xff00 );
498         if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
499         if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
500         scr_writew(i, (u16 *) pos);
501         if (DO_UPDATE)
502                 sw->con_putc(vc_cons[currcons].d, i, y, x);
503 }
504
505 static void hide_cursor(int currcons)
506 {
507         if (currcons == sel_cons)
508                 clear_selection();
509         if (softcursor_original != -1) {
510                 scr_writew(softcursor_original,(u16 *) pos);
511                 if (DO_UPDATE)
512                         sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
513                 softcursor_original = -1;
514         }
515         sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
516 }
517
518 static void set_cursor(int currcons)
519 {
520     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
521         return;
522     if (deccm) {
523         if (currcons == sel_cons)
524                 clear_selection();
525         add_softcursor(currcons);
526         if ((cursor_type & 0x0f) != 1)
527             sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
528     } else
529         hide_cursor(currcons);
530 }
531
532 static void set_origin(int currcons)
533 {
534         if (!IS_VISIBLE ||
535             !sw->con_set_origin ||
536             !sw->con_set_origin(vc_cons[currcons].d))
537                 origin = (unsigned long) screenbuf;
538         visible_origin = origin;
539         scr_end = origin + screenbuf_size;
540         pos = origin + video_size_row*y + 2*x;
541 }
542
543 static inline void save_screen(int currcons)
544 {
545         if (sw->con_save_screen)
546                 sw->con_save_screen(vc_cons[currcons].d);
547 }
548
549 /*
550  *      Redrawing of screen
551  */
552
553 void redraw_screen(int new_console, int is_switch)
554 {
555         int redraw = 1;
556         int currcons, old_console;
557
558         if (!vc_cons_allocated(new_console)) {
559                 /* strange ... */
560                 /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
561                 return;
562         }
563
564         if (is_switch) {
565                 currcons = fg_console;
566                 hide_cursor(currcons);
567                 if (fg_console != new_console) {
568                         struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
569                         old_console = (*display) ? (*display)->vc_num : fg_console;
570                         *display = vc_cons[new_console].d;
571                         fg_console = new_console;
572                         currcons = old_console;
573                         if (!IS_VISIBLE) {
574                                 save_screen(currcons);
575                                 set_origin(currcons);
576                         }
577                         currcons = new_console;
578                         if (old_console == new_console)
579                                 redraw = 0;
580                 }
581         } else {
582                 currcons = new_console;
583                 hide_cursor(currcons);
584         }
585
586         if (redraw) {
587                 int update;
588                 set_origin(currcons);
589                 update = sw->con_switch(vc_cons[currcons].d);
590                 set_palette(currcons);
591                 if (update && vcmode != KD_GRAPHICS)
592                         do_update_region(currcons, origin, screenbuf_size/2);
593         }
594         set_cursor(currcons);
595         if (is_switch) {
596                 set_leds();
597                 compute_shiftstate();
598         }
599 }
600
601 /*
602  *      Allocation, freeing and resizing of VTs.
603  */
604
605 int vc_cons_allocated(unsigned int i)
606 {
607         return (i < MAX_NR_CONSOLES && vc_cons[i].d);
608 }
609
610 static void visual_init(int currcons, int init)
611 {
612     /* ++Geert: sw->con_init determines console size */
613     sw = conswitchp;
614 #ifndef VT_SINGLE_DRIVER
615     if (con_driver_map[currcons])
616         sw = con_driver_map[currcons];
617 #endif
618     cons_num = currcons;
619     display_fg = &master_display_fg;
620     vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
621     vc_cons[currcons].d->vc_uni_pagedir = 0;
622     hi_font_mask = 0;
623     complement_mask = 0;
624     can_do_color = 0;
625     sw->con_init(vc_cons[currcons].d, init);
626     if (!complement_mask)
627         complement_mask = can_do_color ? 0x7700 : 0x0800;
628     s_complement_mask = complement_mask;
629     video_size_row = video_num_columns<<1;
630     screenbuf_size = video_num_lines*video_size_row;
631 }
632
633 int vc_allocate(unsigned int currcons)  /* return 0 on success */
634 {
635         if (currcons >= MAX_NR_CONSOLES)
636                 return -ENXIO;
637         if (!vc_cons[currcons].d) {
638             long p, q;
639
640             /* prevent users from taking too much memory */
641             if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
642               return -EPERM;
643
644             /* due to the granularity of kmalloc, we waste some memory here */
645             /* the alloc is done in two steps, to optimize the common situation
646                of a 25x80 console (structsize=216, screenbuf_size=4000) */
647             /* although the numbers above are not valid since long ago, the
648                point is still up-to-date and the comment still has its value
649                even if only as a historical artifact.  --mj, July 1998 */
650             p = (long) kmalloc(structsize, GFP_KERNEL);
651             if (!p)
652                 return -ENOMEM;
653             vc_cons[currcons].d = (struct vc_data *)p;
654             vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
655             visual_init(currcons, 1);
656             if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
657                 con_set_default_unimap(currcons);
658             q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
659             if (!q) {
660                 kfree((char *) p);
661                 vc_cons[currcons].d = NULL;
662                 vt_cons[currcons] = NULL;
663                 return -ENOMEM;
664             }
665             screenbuf = (unsigned short *) q;
666             kmalloced = 1;
667             vc_init(currcons, video_num_lines, video_num_columns, 1);
668
669             if (!pm_con) {
670                     pm_con = pm_register(PM_SYS_DEV,
671                                          PM_SYS_VGA,
672                                          pm_con_request);
673             }
674         }
675         return 0;
676 }
677
678 /*
679  * Change # of rows and columns (0 means unchanged/the size of fg_console)
680  * [this is to be used together with some user program
681  * like resize that changes the hardware videomode]
682  */
683 int vc_resize(unsigned int lines, unsigned int cols,
684               unsigned int first, unsigned int last)
685 {
686         unsigned int cc, ll, ss, sr, todo = 0;
687         unsigned int currcons = fg_console, i;
688         unsigned short *newscreens[MAX_NR_CONSOLES];
689
690         cc = (cols ? cols : video_num_columns);
691         ll = (lines ? lines : video_num_lines);
692         sr = cc << 1;
693         ss = sr * ll;
694
695         for (currcons = first; currcons <= last; currcons++) {
696                 if (!vc_cons_allocated(currcons) ||
697                     (cc == video_num_columns && ll == video_num_lines))
698                         newscreens[currcons] = NULL;
699                 else {
700                         unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
701                         if (!p) {
702                                 for (i = first; i < currcons; i++)
703                                         if (newscreens[i])
704                                                 kfree(newscreens[i]);
705                                 return -ENOMEM;
706                         }
707                         newscreens[currcons] = p;
708                         todo++;
709                 }
710         }
711         if (!todo)
712                 return 0;
713
714         for (currcons = first; currcons <= last; currcons++) {
715                 unsigned int occ, oll, oss, osr;
716                 unsigned long ol, nl, nlend, rlth, rrem;
717                 if (!newscreens[currcons] || !vc_cons_allocated(currcons))
718                         continue;
719
720                 oll = video_num_lines;
721                 occ = video_num_columns;
722                 osr = video_size_row;
723                 oss = screenbuf_size;
724
725                 video_num_lines = ll;
726                 video_num_columns = cc;
727                 video_size_row = sr;
728                 screenbuf_size = ss;
729
730                 rlth = MIN(osr, sr);
731                 rrem = sr - rlth;
732                 ol = origin;
733                 nl = (long) newscreens[currcons];
734                 nlend = nl + ss;
735                 if (ll < oll)
736                         ol += (oll - ll) * osr;
737
738                 update_attr(currcons);
739
740                 while (ol < scr_end) {
741                         scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
742                         if (rrem)
743                                 scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
744                         ol += osr;
745                         nl += sr;
746                 }
747                 if (nlend > nl)
748                         scr_memsetw((void *) nl, video_erase_char, nlend - nl);
749                 if (kmalloced)
750                         kfree(screenbuf);
751                 screenbuf = newscreens[currcons];
752                 kmalloced = 1;
753                 screenbuf_size = ss;
754                 set_origin(currcons);
755
756                 /* do part of a reset_terminal() */
757                 top = 0;
758                 bottom = video_num_lines;
759                 gotoxy(currcons, x, y);
760                 save_cur(currcons);
761
762                 if (console_table[currcons]) {
763                         struct winsize ws, *cws = &console_table[currcons]->winsize;
764                         memset(&ws, 0, sizeof(ws));
765                         ws.ws_row = video_num_lines;
766                         ws.ws_col = video_num_columns;
767                         if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
768                             console_table[currcons]->pgrp > 0)
769                                 kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
770                         *cws = ws;
771                 }
772
773                 if (IS_VISIBLE)
774                         update_screen(currcons);
775         }
776
777         return 0;
778 }
779
780
781 void vc_disallocate(unsigned int currcons)
782 {
783         if (vc_cons_allocated(currcons)) {
784             sw->con_deinit(vc_cons[currcons].d);
785             if (kmalloced)
786                 kfree(screenbuf);
787             if (currcons >= MIN_NR_CONSOLES)
788                 kfree(vc_cons[currcons].d);
789             vc_cons[currcons].d = NULL;
790         }
791 }
792
793 /*
794  *      VT102 emulator
795  */
796
797 #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
798 #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
799 #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
800
801 #define decarm          VC_REPEAT
802 #define decckm          VC_CKMODE
803 #define kbdapplic       VC_APPLIC
804 #define lnm             VC_CRLF
805
806 /*
807  * this is what the terminal answers to a ESC-Z or csi0c query.
808  */
809 #define VT100ID "\033[?1;2c"
810 #define VT102ID "\033[?6c"
811
812 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
813                                        8,12,10,14, 9,13,11,15 };
814
815 /* the default colour table, for VGA+ colour systems */
816 int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
817     0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
818 int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
819     0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
820 int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
821     0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
822
823 /*
824  * gotoxy() must verify all boundaries, because the arguments
825  * might also be negative. If the given position is out of
826  * bounds, the cursor is placed at the nearest margin.
827  */
828 static void gotoxy(int currcons, int new_x, int new_y)
829 {
830         int min_y, max_y;
831
832         if (new_x < 0)
833                 x = 0;
834         else
835                 if (new_x >= video_num_columns)
836                         x = video_num_columns - 1;
837                 else
838                         x = new_x;
839         if (decom) {
840                 min_y = top;
841                 max_y = bottom;
842         } else {
843                 min_y = 0;
844                 max_y = video_num_lines;
845         }
846         if (new_y < min_y)
847                 y = min_y;
848         else if (new_y >= max_y)
849                 y = max_y - 1;
850         else
851                 y = new_y;
852         pos = origin + y*video_size_row + (x<<1);
853         need_wrap = 0;
854 }
855
856 /* for absolute user moves, when decom is set */
857 static void gotoxay(int currcons, int new_x, int new_y)
858 {
859         gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
860 }
861
862 void scrollback(int lines)
863 {
864         int currcons = fg_console;
865
866         if (!lines)
867                 lines = video_num_lines/2;
868         scrolldelta(-lines);
869 }
870
871 void scrollfront(int lines)
872 {
873         int currcons = fg_console;
874
875         if (!lines)
876                 lines = video_num_lines/2;
877         scrolldelta(lines);
878 }
879
880 static void lf(int currcons)
881 {
882         /* don't scroll if above bottom of scrolling region, or
883          * if below scrolling region
884          */
885         if (y+1 == bottom)
886                 scrup(currcons,top,bottom,1);
887         else if (y < video_num_lines-1) {
888                 y++;
889                 pos += video_size_row;
890         }
891         need_wrap = 0;
892 }
893
894 static void ri(int currcons)
895 {
896         /* don't scroll if below top of scrolling region, or
897          * if above scrolling region
898          */
899         if (y == top)
900                 scrdown(currcons,top,bottom,1);
901         else if (y > 0) {
902                 y--;
903                 pos -= video_size_row;
904         }
905         need_wrap = 0;
906 }
907
908 static inline void cr(int currcons)
909 {
910         pos -= x<<1;
911         need_wrap = x = 0;
912 }
913
914 static inline void bs(int currcons)
915 {
916         if (x) {
917                 pos -= 2;
918                 x--;
919                 need_wrap = 0;
920         }
921 }
922
923 static inline void del(int currcons)
924 {
925         /* ignored */
926 }
927
928 static void csi_J(int currcons, int vpar)
929 {
930         unsigned int count;
931         unsigned short * start;
932
933         switch (vpar) {
934                 case 0: /* erase from cursor to end of display */
935                         count = (scr_end-pos)>>1;
936                         start = (unsigned short *) pos;
937                         if (DO_UPDATE) {
938                                 /* do in two stages */
939                                 sw->con_clear(vc_cons[currcons].d, y, x, 1,
940                                               video_num_columns-x);
941                                 sw->con_clear(vc_cons[currcons].d, y+1, 0,
942                                               video_num_lines-y-1,
943                                               video_num_columns);
944                         }
945                         break;
946                 case 1: /* erase from start to cursor */
947                         count = ((pos-origin)>>1)+1;
948                         start = (unsigned short *) origin;
949                         if (DO_UPDATE) {
950                                 /* do in two stages */
951                                 sw->con_clear(vc_cons[currcons].d, 0, 0, y,
952                                               video_num_columns);
953                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
954                                               x + 1);
955                         }
956                         break;
957                 case 2: /* erase whole display */
958                         count = video_num_columns * video_num_lines;
959                         start = (unsigned short *) origin;
960                         if (DO_UPDATE)
961                                 sw->con_clear(vc_cons[currcons].d, 0, 0,
962                                               video_num_lines,
963                                               video_num_columns);
964                         break;
965                 default:
966                         return;
967         }
968         scr_memsetw(start, video_erase_char, 2*count);
969         need_wrap = 0;
970 }
971
972 static void csi_K(int currcons, int vpar)
973 {
974         unsigned int count;
975         unsigned short * start;
976
977         switch (vpar) {
978                 case 0: /* erase from cursor to end of line */
979                         count = video_num_columns-x;
980                         start = (unsigned short *) pos;
981                         if (DO_UPDATE)
982                                 sw->con_clear(vc_cons[currcons].d, y, x, 1,
983                                               video_num_columns-x);
984                         break;
985                 case 1: /* erase from start of line to cursor */
986                         start = (unsigned short *) (pos - (x<<1));
987                         count = x+1;
988                         if (DO_UPDATE)
989                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
990                                               x + 1);
991                         break;
992                 case 2: /* erase whole line */
993                         start = (unsigned short *) (pos - (x<<1));
994                         count = video_num_columns;
995                         if (DO_UPDATE)
996                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
997                                               video_num_columns);
998                         break;
999                 default:
1000                         return;
1001         }
1002         scr_memsetw(start, video_erase_char, 2 * count);
1003         need_wrap = 0;
1004 }
1005
1006 static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
1007 {                                         /* not vt100? */
1008         int count;
1009
1010         if (!vpar)
1011                 vpar++;
1012         count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
1013
1014         scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
1015         if (DO_UPDATE)
1016                 sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
1017         need_wrap = 0;
1018 }
1019
1020 static void default_attr(int currcons)
1021 {
1022         intensity = 1;
1023         underline = 0;
1024         reverse = 0;
1025         blink = 0;
1026         color = def_color;
1027 }
1028
1029 static void csi_m(int currcons)
1030 {
1031         int i;
1032
1033         for (i=0;i<=npar;i++)
1034                 switch (par[i]) {
1035                         case 0: /* all attributes off */
1036                                 default_attr(currcons);
1037                                 break;
1038                         case 1:
1039                                 intensity = 2;
1040                                 break;
1041                         case 2:
1042                                 intensity = 0;
1043                                 break;
1044                         case 4:
1045                                 underline = 1;
1046                                 break;
1047                         case 5:
1048                                 blink = 1;
1049                                 break;
1050                         case 7:
1051                                 reverse = 1;
1052                                 break;
1053                         case 10: /* ANSI X3.64-1979 (SCO-ish?)
1054                                   * Select primary font, don't display
1055                                   * control chars if defined, don't set
1056                                   * bit 8 on output.
1057                                   */
1058                                 translate = set_translate(charset == 0
1059                                                 ? G0_charset
1060                                                 : G1_charset,currcons);
1061                                 disp_ctrl = 0;
1062                                 toggle_meta = 0;
1063                                 break;
1064                         case 11: /* ANSI X3.64-1979 (SCO-ish?)
1065                                   * Select first alternate font, lets
1066                                   * chars < 32 be displayed as ROM chars.
1067                                   */
1068                                 translate = set_translate(IBMPC_MAP,currcons);
1069                                 disp_ctrl = 1;
1070                                 toggle_meta = 0;
1071                                 break;
1072                         case 12: /* ANSI X3.64-1979 (SCO-ish?)
1073                                   * Select second alternate font, toggle
1074                                   * high bit before displaying as ROM char.
1075                                   */
1076                                 translate = set_translate(IBMPC_MAP,currcons);
1077                                 disp_ctrl = 1;
1078                                 toggle_meta = 1;
1079                                 break;
1080                         case 21:
1081                         case 22:
1082                                 intensity = 1;
1083                                 break;
1084                         case 24:
1085                                 underline = 0;
1086                                 break;
1087                         case 25:
1088                                 blink = 0;
1089                                 break;
1090                         case 27:
1091                                 reverse = 0;
1092                                 break;
1093                         case 38: /* ANSI X3.64-1979 (SCO-ish?)
1094                                   * Enables underscore, white foreground
1095                                   * with white underscore (Linux - use
1096                                   * default foreground).
1097                                   */
1098                                 color = (def_color & 0x0f) | background;
1099                                 underline = 1;
1100                                 break;
1101                         case 39: /* ANSI X3.64-1979 (SCO-ish?)
1102                                   * Disable underline option.
1103                                   * Reset colour to default? It did this
1104                                   * before...
1105                                   */
1106                                 color = (def_color & 0x0f) | background;
1107                                 underline = 0;
1108                                 break;
1109                         case 49:
1110                                 color = (def_color & 0xf0) | foreground;
1111                                 break;
1112                         default:
1113                                 if (par[i] >= 30 && par[i] <= 37)
1114                                         color = color_table[par[i]-30]
1115                                                 | background;
1116                                 else if (par[i] >= 40 && par[i] <= 47)
1117                                         color = (color_table[par[i]-40]<<4)
1118                                                 | foreground;
1119                                 break;
1120                 }
1121         update_attr(currcons);
1122 }
1123
1124 static void respond_string(const char * p, struct tty_struct * tty)
1125 {
1126         while (*p) {
1127                 tty_insert_flip_char(tty, *p, 0);
1128                 p++;
1129         }
1130         con_schedule_flip(tty);
1131 }
1132
1133 static void cursor_report(int currcons, struct tty_struct * tty)
1134 {
1135         char buf[40];
1136
1137         sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
1138         respond_string(buf, tty);
1139 }
1140
1141 static inline void status_report(struct tty_struct * tty)
1142 {
1143         respond_string("\033[0n", tty); /* Terminal ok */
1144 }
1145
1146 static inline void respond_ID(struct tty_struct * tty)
1147 {
1148         respond_string(VT102ID, tty);
1149 }
1150
1151 void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
1152 {
1153         char buf[8];
1154
1155         sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1156                 (char)('!' + mry));
1157         respond_string(buf, tty);
1158 }
1159
1160 /* invoked via ioctl(TIOCLINUX) and through set_selection */
1161 int mouse_reporting(void)
1162 {
1163         int currcons = fg_console;
1164
1165         return report_mouse;
1166 }
1167
1168 static void set_mode(int currcons, int on_off)
1169 {
1170         int i;
1171
1172         for (i=0; i<=npar; i++)
1173                 if (ques) switch(par[i]) {      /* DEC private modes set/reset */
1174                         case 1:                 /* Cursor keys send ^[Ox/^[[x */
1175                                 if (on_off)
1176                                         set_kbd(decckm);
1177                                 else
1178                                         clr_kbd(decckm);
1179                                 break;
1180                         case 3: /* 80/132 mode switch unimplemented */
1181                                 deccolm = on_off;
1182 #if 0
1183                                 (void) vc_resize(video_num_lines, deccolm ? 132 : 80);
1184                                 /* this alone does not suffice; some user mode
1185                                    utility has to change the hardware regs */
1186 #endif
1187                                 break;
1188                         case 5:                 /* Inverted screen on/off */
1189                                 if (decscnm != on_off) {
1190                                         decscnm = on_off;
1191                                         invert_screen(currcons, 0, screenbuf_size, 0);
1192                                         update_attr(currcons);
1193                                 }
1194                                 break;
1195                         case 6:                 /* Origin relative/absolute */
1196                                 decom = on_off;
1197                                 gotoxay(currcons,0,0);
1198                                 break;
1199                         case 7:                 /* Autowrap on/off */
1200                                 decawm = on_off;
1201                                 break;
1202                         case 8:                 /* Autorepeat on/off */
1203                                 if (on_off)
1204                                         set_kbd(decarm);
1205                                 else
1206                                         clr_kbd(decarm);
1207                                 break;
1208                         case 9:
1209                                 report_mouse = on_off ? 1 : 0;
1210                                 break;
1211                         case 25:                /* Cursor on/off */
1212                                 deccm = on_off;
1213                                 break;
1214                         case 1000:
1215                                 report_mouse = on_off ? 2 : 0;
1216                                 break;
1217                 } else switch(par[i]) {         /* ANSI modes set/reset */
1218                         case 3:                 /* Monitor (display ctrls) */
1219                                 disp_ctrl = on_off;
1220                                 break;
1221                         case 4:                 /* Insert Mode on/off */
1222                                 decim = on_off;
1223                                 break;
1224                         case 20:                /* Lf, Enter == CrLf/Lf */
1225                                 if (on_off)
1226                                         set_kbd(lnm);
1227                                 else
1228                                         clr_kbd(lnm);
1229                                 break;
1230                 }
1231 }
1232
1233 static void setterm_command(int currcons)
1234 {
1235         switch(par[0]) {
1236                 case 1: /* set color for underline mode */
1237                         if (can_do_color && par[1] < 16) {
1238                                 ulcolor = color_table[par[1]];
1239                                 if (underline)
1240                                         update_attr(currcons);
1241                         }
1242                         break;
1243                 case 2: /* set color for half intensity mode */
1244                         if (can_do_color && par[1] < 16) {
1245                                 halfcolor = color_table[par[1]];
1246                                 if (intensity == 0)
1247                                         update_attr(currcons);
1248                         }
1249                         break;
1250                 case 8: /* store colors as defaults */
1251                         def_color = attr;
1252                         if (hi_font_mask == 0x100)
1253                                 def_color >>= 1;
1254                         default_attr(currcons);
1255                         update_attr(currcons);
1256                         break;
1257                 case 9: /* set blanking interval */
1258                         blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1259                         poke_blanked_console();
1260                         break;
1261                 case 10: /* set bell frequency in Hz */
1262                         if (npar >= 1)
1263                                 bell_pitch = par[1];
1264                         else
1265                                 bell_pitch = DEFAULT_BELL_PITCH;
1266                         break;
1267                 case 11: /* set bell duration in msec */
1268                         if (npar >= 1)
1269                                 bell_duration = (par[1] < 2000) ?
1270                                         par[1]*HZ/1000 : 0;
1271                         else
1272                                 bell_duration = DEFAULT_BELL_DURATION;
1273                         break;
1274                 case 12: /* bring specified console to the front */
1275                         if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
1276                                 set_console(par[1] - 1);
1277                         break;
1278                 case 13: /* unblank the screen */
1279                         poke_blanked_console();
1280                         break;
1281                 case 14: /* set vesa powerdown interval */
1282                         vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1283                         break;
1284         }
1285 }
1286
1287 static void insert_line(int currcons, unsigned int nr)
1288 {
1289         scrdown(currcons,y,bottom,nr);
1290         need_wrap = 0;
1291 }
1292
1293
1294 static void delete_line(int currcons, unsigned int nr)
1295 {
1296         scrup(currcons,y,bottom,nr);
1297         need_wrap = 0;
1298 }
1299
1300 static void csi_at(int currcons, unsigned int nr)
1301 {
1302         if (nr > video_num_columns - x)
1303                 nr = video_num_columns - x;
1304         else if (!nr)
1305                 nr = 1;
1306         insert_char(currcons, nr);
1307 }
1308
1309 static void csi_L(int currcons, unsigned int nr)
1310 {
1311         if (nr > video_num_lines - y)
1312                 nr = video_num_lines - y;
1313         else if (!nr)
1314                 nr = 1;
1315         insert_line(currcons, nr);
1316 }
1317
1318 static void csi_P(int currcons, unsigned int nr)
1319 {
1320         if (nr > video_num_columns - x)
1321                 nr = video_num_columns - x;
1322         else if (!nr)
1323                 nr = 1;
1324         delete_char(currcons, nr);
1325 }
1326
1327 static void csi_M(int currcons, unsigned int nr)
1328 {
1329         if (nr > video_num_lines - y)
1330                 nr = video_num_lines - y;
1331         else if (!nr)
1332                 nr=1;
1333         delete_line(currcons, nr);
1334 }
1335
1336 static void save_cur(int currcons)
1337 {
1338         saved_x         = x;
1339         saved_y         = y;
1340         s_intensity     = intensity;
1341         s_underline     = underline;
1342         s_blink         = blink;
1343         s_reverse       = reverse;
1344         s_charset       = charset;
1345         s_color         = color;
1346         saved_G0        = G0_charset;
1347         saved_G1        = G1_charset;
1348 }
1349
1350 static void restore_cur(int currcons)
1351 {
1352         gotoxy(currcons,saved_x,saved_y);
1353         intensity       = s_intensity;
1354         underline       = s_underline;
1355         blink           = s_blink;
1356         reverse         = s_reverse;
1357         charset         = s_charset;
1358         color           = s_color;
1359         G0_charset      = saved_G0;
1360         G1_charset      = saved_G1;
1361         translate       = set_translate(charset ? G1_charset : G0_charset,currcons);
1362         update_attr(currcons);
1363         need_wrap = 0;
1364 }
1365
1366 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
1367         EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
1368         ESpalette };
1369
1370 static void reset_terminal(int currcons, int do_clear)
1371 {
1372         top             = 0;
1373         bottom          = video_num_lines;
1374         vc_state        = ESnormal;
1375         ques            = 0;
1376         translate       = set_translate(LAT1_MAP,currcons);
1377         G0_charset      = LAT1_MAP;
1378         G1_charset      = GRAF_MAP;
1379         charset         = 0;
1380         need_wrap       = 0;
1381         report_mouse    = 0;
1382         utf             = 0;
1383         utf_count       = 0;
1384
1385         disp_ctrl       = 0;
1386         toggle_meta     = 0;
1387
1388         decscnm         = 0;
1389         decom           = 0;
1390         decawm          = 1;
1391         deccm           = 1;
1392         decim           = 0;
1393
1394         set_kbd(decarm);
1395         clr_kbd(decckm);
1396         clr_kbd(kbdapplic);
1397         clr_kbd(lnm);
1398         kbd_table[currcons].lockstate = 0;
1399         kbd_table[currcons].slockstate = 0;
1400         kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1401         kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1402         set_leds();
1403
1404         cursor_type = CUR_DEFAULT;
1405         complement_mask = s_complement_mask;
1406
1407         default_attr(currcons);
1408         update_attr(currcons);
1409
1410         tab_stop[0]     = 0x01010100;
1411         tab_stop[1]     =
1412         tab_stop[2]     =
1413         tab_stop[3]     =
1414         tab_stop[4]     = 0x01010101;
1415
1416         bell_pitch = DEFAULT_BELL_PITCH;
1417         bell_duration = DEFAULT_BELL_DURATION;
1418
1419         gotoxy(currcons,0,0);
1420         save_cur(currcons);
1421         if (do_clear)
1422             csi_J(currcons,2);
1423 }
1424
1425 static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
1426 {
1427         /*
1428          *  Control characters can be used in the _middle_
1429          *  of an escape sequence.
1430          */
1431         switch (c) {
1432         case 0:
1433                 return;
1434         case 7:
1435                 if (bell_duration)
1436                         kd_mksound(bell_pitch, bell_duration);
1437                 return;
1438         case 8:
1439                 bs(currcons);
1440                 return;
1441         case 9:
1442                 pos -= (x << 1);
1443                 while (x < video_num_columns - 1) {
1444                         x++;
1445                         if (tab_stop[x >> 5] & (1 << (x & 31)))
1446                                 break;
1447                 }
1448                 pos += (x << 1);
1449                 return;
1450         case 10: case 11: case 12:
1451                 lf(currcons);
1452                 if (!is_kbd(lnm))
1453                         return;
1454         case 13:
1455                 cr(currcons);
1456                 return;
1457         case 14:
1458                 charset = 1;
1459                 translate = set_translate(G1_charset,currcons);
1460                 disp_ctrl = 1;
1461                 return;
1462         case 15:
1463                 charset = 0;
1464                 translate = set_translate(G0_charset,currcons);
1465                 disp_ctrl = 0;
1466                 return;
1467         case 24: case 26:
1468                 vc_state = ESnormal;
1469                 return;
1470         case 27:
1471                 vc_state = ESesc;
1472                 return;
1473         case 127:
1474                 del(currcons);
1475                 return;
1476         case 128+27:
1477                 vc_state = ESsquare;
1478                 return;
1479         }
1480         switch(vc_state) {
1481         case ESesc:
1482                 vc_state = ESnormal;
1483                 switch (c) {
1484                 case '[':
1485                         vc_state = ESsquare;
1486                         return;
1487                 case ']':
1488                         vc_state = ESnonstd;
1489                         return;
1490                 case '%':
1491                         vc_state = ESpercent;
1492                         return;
1493                 case 'E':
1494                         cr(currcons);
1495                         lf(currcons);
1496                         return;
1497                 case 'M':
1498                         ri(currcons);
1499                         return;
1500                 case 'D':
1501                         lf(currcons);
1502                         return;
1503                 case 'H':
1504                         tab_stop[x >> 5] |= (1 << (x & 31));
1505                         return;
1506                 case 'Z':
1507                         respond_ID(tty);
1508                         return;
1509                 case '7':
1510                         save_cur(currcons);
1511                         return;
1512                 case '8':
1513                         restore_cur(currcons);
1514                         return;
1515                 case '(':
1516                         vc_state = ESsetG0;
1517                         return;
1518                 case ')':
1519                         vc_state = ESsetG1;
1520                         return;
1521                 case '#':
1522                         vc_state = EShash;
1523                         return;
1524                 case 'c':
1525                         reset_terminal(currcons,1);
1526                         return;
1527                 case '>':  /* Numeric keypad */
1528                         clr_kbd(kbdapplic);
1529                         return;
1530                 case '=':  /* Appl. keypad */
1531                         set_kbd(kbdapplic);
1532                         return;
1533                 }
1534                 return;
1535         case ESnonstd:
1536                 if (c=='P') {   /* palette escape sequence */
1537                         for (npar=0; npar<NPAR; npar++)
1538                                 par[npar] = 0 ;
1539                         npar = 0 ;
1540                         vc_state = ESpalette;
1541                         return;
1542                 } else if (c=='R') {   /* reset palette */
1543                         reset_palette(currcons);
1544                         vc_state = ESnormal;
1545                 } else
1546                         vc_state = ESnormal;
1547                 return;
1548         case ESpalette:
1549                 if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
1550                         par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
1551                         if (npar==7) {
1552                                 int i = par[0]*3, j = 1;
1553                                 palette[i] = 16*par[j++];
1554                                 palette[i++] += par[j++];
1555                                 palette[i] = 16*par[j++];
1556                                 palette[i++] += par[j++];
1557                                 palette[i] = 16*par[j++];
1558                                 palette[i] += par[j];
1559                                 set_palette(currcons);
1560                                 vc_state = ESnormal;
1561                         }
1562                 } else
1563                         vc_state = ESnormal;
1564                 return;
1565         case ESsquare:
1566                 for(npar = 0 ; npar < NPAR ; npar++)
1567                         par[npar] = 0;
1568                 npar = 0;
1569                 vc_state = ESgetpars;
1570                 if (c == '[') { /* Function key */
1571                         vc_state=ESfunckey;
1572                         return;
1573                 }
1574                 ques = (c=='?');
1575                 if (ques)
1576                         return;
1577         case ESgetpars:
1578                 if (c==';' && npar<NPAR-1) {
1579                         npar++;
1580                         return;
1581                 } else if (c>='0' && c<='9') {
1582                         par[npar] *= 10;
1583                         par[npar] += c-'0';
1584                         return;
1585                 } else vc_state=ESgotpars;
1586         case ESgotpars:
1587                 vc_state = ESnormal;
1588                 switch(c) {
1589                 case 'h':
1590                         set_mode(currcons,1);
1591                         return;
1592                 case 'l':
1593                         set_mode(currcons,0);
1594                         return;
1595                 case 'c':
1596                         if (ques) {
1597                                 if (par[0])
1598                                         cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
1599                                 else
1600                                         cursor_type = CUR_DEFAULT;
1601                                 return;
1602                         }
1603                         break;
1604                 case 'm':
1605                         if (ques) {
1606                                 clear_selection();
1607                                 if (par[0])
1608                                         complement_mask = par[0]<<8 | par[1];
1609                                 else
1610                                         complement_mask = s_complement_mask;
1611                                 return;
1612                         }
1613                         break;
1614                 case 'n':
1615                         if (!ques) {
1616                                 if (par[0] == 5)
1617                                         status_report(tty);
1618                                 else if (par[0] == 6)
1619                                         cursor_report(currcons,tty);
1620                         }
1621                         return;
1622                 }
1623                 if (ques) {
1624                         ques = 0;
1625                         return;
1626                 }
1627                 switch(c) {
1628                 case 'G': case '`':
1629                         if (par[0]) par[0]--;
1630                         gotoxy(currcons,par[0],y);
1631                         return;
1632                 case 'A':
1633                         if (!par[0]) par[0]++;
1634                         gotoxy(currcons,x,y-par[0]);
1635                         return;
1636                 case 'B': case 'e':
1637                         if (!par[0]) par[0]++;
1638                         gotoxy(currcons,x,y+par[0]);
1639                         return;
1640                 case 'C': case 'a':
1641                         if (!par[0]) par[0]++;
1642                         gotoxy(currcons,x+par[0],y);
1643                         return;
1644                 case 'D':
1645                         if (!par[0]) par[0]++;
1646                         gotoxy(currcons,x-par[0],y);
1647                         return;
1648                 case 'E':
1649                         if (!par[0]) par[0]++;
1650                         gotoxy(currcons,0,y+par[0]);
1651                         return;
1652                 case 'F':
1653                         if (!par[0]) par[0]++;
1654                         gotoxy(currcons,0,y-par[0]);
1655                         return;
1656                 case 'd':
1657                         if (par[0]) par[0]--;
1658                         gotoxay(currcons,x,par[0]);
1659                         return;
1660                 case 'H': case 'f':
1661                         if (par[0]) par[0]--;
1662                         if (par[1]) par[1]--;
1663                         gotoxay(currcons,par[1],par[0]);
1664                         return;
1665                 case 'J':
1666                         csi_J(currcons,par[0]);
1667                         return;
1668                 case 'K':
1669                         csi_K(currcons,par[0]);
1670                         return;
1671                 case 'L':
1672                         csi_L(currcons,par[0]);
1673                         return;
1674                 case 'M':
1675                         csi_M(currcons,par[0]);
1676                         return;
1677                 case 'P':
1678                         csi_P(currcons,par[0]);
1679                         return;
1680                 case 'c':
1681                         if (!par[0])
1682                                 respond_ID(tty);
1683                         return;
1684                 case 'g':
1685                         if (!par[0])
1686                                 tab_stop[x >> 5] &= ~(1 << (x & 31));
1687                         else if (par[0] == 3) {
1688                                 tab_stop[0] =
1689                                         tab_stop[1] =
1690                                         tab_stop[2] =
1691                                         tab_stop[3] =
1692                                         tab_stop[4] = 0;
1693                         }
1694                         return;
1695                 case 'm':
1696                         csi_m(currcons);
1697                         return;
1698                 case 'q': /* DECLL - but only 3 leds */
1699                         /* map 0,1,2,3 to 0,1,2,4 */
1700                         if (par[0] < 4)
1701                                 setledstate(kbd_table + currcons,
1702                                             (par[0] < 3) ? par[0] : 4);
1703                         return;
1704                 case 'r':
1705                         if (!par[0])
1706                                 par[0]++;
1707                         if (!par[1])
1708                                 par[1] = video_num_lines;
1709                         /* Minimum allowed region is 2 lines */
1710                         if (par[0] < par[1] &&
1711                             par[1] <= video_num_lines) {
1712                                 top=par[0]-1;
1713                                 bottom=par[1];
1714                                 gotoxay(currcons,0,0);
1715                         }
1716                         return;
1717                 case 's':
1718                         save_cur(currcons);
1719                         return;
1720                 case 'u':
1721                         restore_cur(currcons);
1722                         return;
1723                 case 'X':
1724                         csi_X(currcons, par[0]);
1725                         return;
1726                 case '@':
1727                         csi_at(currcons,par[0]);
1728                         return;
1729                 case ']': /* setterm functions */
1730                         setterm_command(currcons);
1731                         return;
1732                 }
1733                 return;
1734         case ESpercent:
1735                 vc_state = ESnormal;
1736                 switch (c) {
1737                 case '@':  /* defined in ISO 2022 */
1738                         utf = 0;
1739                         return;
1740                 case 'G':  /* prelim official escape code */
1741                 case '8':  /* retained for compatibility */
1742                         utf = 1;
1743                         return;
1744                 }
1745                 return;
1746         case ESfunckey:
1747                 vc_state = ESnormal;
1748                 return;
1749         case EShash:
1750                 vc_state = ESnormal;
1751                 if (c == '8') {
1752                         /* DEC screen alignment test. kludge :-) */
1753                         video_erase_char =
1754                                 (video_erase_char & 0xff00) | 'E';
1755                         csi_J(currcons, 2);
1756                         video_erase_char =
1757                                 (video_erase_char & 0xff00) | ' ';
1758                         do_update_region(currcons, origin, screenbuf_size/2);
1759                 }
1760                 return;
1761         case ESsetG0:
1762                 if (c == '0')
1763                         G0_charset = GRAF_MAP;
1764                 else if (c == 'B')
1765                         G0_charset = LAT1_MAP;
1766                 else if (c == 'U')
1767                         G0_charset = IBMPC_MAP;
1768                 else if (c == 'K')
1769                         G0_charset = USER_MAP;
1770                 if (charset == 0)
1771                         translate = set_translate(G0_charset,currcons);
1772                 vc_state = ESnormal;
1773                 return;
1774         case ESsetG1:
1775                 if (c == '0')
1776                         G1_charset = GRAF_MAP;
1777                 else if (c == 'B')
1778                         G1_charset = LAT1_MAP;
1779                 else if (c == 'U')
1780                         G1_charset = IBMPC_MAP;
1781                 else if (c == 'K')
1782                         G1_charset = USER_MAP;
1783                 if (charset == 1)
1784                         translate = set_translate(G1_charset,currcons);
1785                 vc_state = ESnormal;
1786                 return;
1787         default:
1788                 vc_state = ESnormal;
1789         }
1790 }
1791
1792 /* This is a temporary buffer used to prepare a tty console write
1793  * so that we can easily avoid touching user space while holding the
1794  * console spinlock.  It is allocated in con_init and is shared by
1795  * this code and the vc_screen read/write tty calls.
1796  *
1797  * We have to allocate this statically in the kernel data section
1798  * since console_init (and thus con_init) are called before any
1799  * kernel memory allocation is available.
1800  */
1801 char con_buf[PAGE_SIZE];
1802 #define CON_BUF_SIZE    PAGE_SIZE
1803 DECLARE_MUTEX(con_buf_sem);
1804
1805 static int do_con_write(struct tty_struct * tty, int from_user,
1806                         const unsigned char *buf, int count)
1807 {
1808 #ifdef VT_BUF_VRAM_ONLY
1809 #define FLUSH do { } while(0);
1810 #else
1811 #define FLUSH if (draw_x >= 0) { \
1812         sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
1813         draw_x = -1; \
1814         }
1815 #endif
1816
1817         int c, tc, ok, n = 0, draw_x = -1;
1818         unsigned int currcons;
1819         unsigned long draw_from = 0, draw_to = 0;
1820         struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1821         u16 himask, charmask;
1822         const unsigned char *orig_buf = NULL;
1823         int orig_count;
1824
1825         currcons = vt->vc_num;
1826         if (!vc_cons_allocated(currcons)) {
1827             /* could this happen? */
1828             static int error = 0;
1829             if (!error) {
1830                 error = 1;
1831                 printk("con_write: tty %d not allocated\n", currcons+1);
1832             }
1833             return 0;
1834         }
1835
1836         orig_buf = buf;
1837         orig_count = count;
1838
1839         if (from_user) {
1840                 down(&con_buf_sem);
1841
1842 again:
1843                 if (count > CON_BUF_SIZE)
1844                         count = CON_BUF_SIZE;
1845                 if (copy_from_user(con_buf, buf, count)) {
1846                         n = 0; /* ?? are error codes legal here ?? */
1847                         goto out;
1848                 }
1849
1850                 buf = con_buf;
1851         }
1852
1853         /* At this point 'buf' is guarenteed to be a kernel buffer
1854          * and therefore no access to userspace (and therefore sleeping)
1855          * will be needed.  The con_buf_sem serializes all tty based
1856          * console rendering and vcs write/read operations.  We hold
1857          * the console spinlock during the entire write.
1858          */
1859
1860         spin_lock_irq(&console_lock);
1861
1862         himask = hi_font_mask;
1863         charmask = himask ? 0x1ff : 0xff;
1864
1865         /* undraw cursor first */
1866         if (IS_FG)
1867                 hide_cursor(currcons);
1868
1869         while (!tty->stopped && count) {
1870                 c = *buf;
1871                 buf++;
1872                 n++;
1873                 count--;
1874
1875                 if (utf) {
1876                     /* Combine UTF-8 into Unicode */
1877                     /* Incomplete characters silently ignored */
1878                     if(c > 0x7f) {
1879                         if (utf_count > 0 && (c & 0xc0) == 0x80) {
1880                                 utf_char = (utf_char << 6) | (c & 0x3f);
1881                                 utf_count--;
1882                                 if (utf_count == 0)
1883                                     tc = c = utf_char;
1884                                 else continue;
1885                         } else {
1886                                 if ((c & 0xe0) == 0xc0) {
1887                                     utf_count = 1;
1888                                     utf_char = (c & 0x1f);
1889                                 } else if ((c & 0xf0) == 0xe0) {
1890                                     utf_count = 2;
1891                                     utf_char = (c & 0x0f);
1892                                 } else if ((c & 0xf8) == 0xf0) {
1893                                     utf_count = 3;
1894                                     utf_char = (c & 0x07);
1895                                 } else if ((c & 0xfc) == 0xf8) {
1896                                     utf_count = 4;
1897                                     utf_char = (c & 0x03);
1898                                 } else if ((c & 0xfe) == 0xfc) {
1899                                     utf_count = 5;
1900                                     utf_char = (c & 0x01);
1901                                 } else
1902                                     utf_count = 0;
1903                                 continue;
1904                               }
1905                     } else {
1906                       tc = c;
1907                       utf_count = 0;
1908                     }
1909                 } else {        /* no utf */
1910                   tc = translate[toggle_meta ? (c|0x80) : c];
1911                 }
1912
1913                 /* If the original code was a control character we
1914                  * only allow a glyph to be displayed if the code is
1915                  * not normally used (such as for cursor movement) or
1916                  * if the disp_ctrl mode has been explicitly enabled.
1917                  * Certain characters (as given by the CTRL_ALWAYS
1918                  * bitmap) are always displayed as control characters,
1919                  * as the console would be pretty useless without
1920                  * them; to display an arbitrary font position use the
1921                  * direct-to-font zone in UTF-8 mode.
1922                  */
1923                 ok = tc && (c >= 32 ||
1924                             (!utf && !(((disp_ctrl ? CTRL_ALWAYS
1925                                          : CTRL_ACTION) >> c) & 1)))
1926                         && (c != 127 || disp_ctrl)
1927                         && (c != 128+27);
1928
1929                 if (vc_state == ESnormal && ok) {
1930                         /* Now try to find out how to display it */
1931                         tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
1932                         if ( tc == -4 ) {
1933                                 /* If we got -4 (not found) then see if we have
1934                                    defined a replacement character (U+FFFD) */
1935                                 tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
1936
1937                                 /* One reason for the -4 can be that we just
1938                                    did a clear_unimap();
1939                                    try at least to show something. */
1940                                 if (tc == -4)
1941                                      tc = c;
1942                         } else if ( tc == -3 ) {
1943                                 /* Bad hash table -- hope for the best */
1944                                 tc = c;
1945                         }
1946                         if (tc & ~charmask)
1947                                 continue; /* Conversion failed */
1948
1949                         if (need_wrap || decim)
1950                                 FLUSH
1951                         if (need_wrap) {
1952                                 cr(currcons);
1953                                 lf(currcons);
1954                         }
1955                         if (decim)
1956                                 insert_char(currcons, 1);
1957                         scr_writew(himask ?
1958                                      ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
1959                                      (attr << 8) + tc,
1960                                    (u16 *) pos);
1961                         if (DO_UPDATE && draw_x < 0) {
1962                                 draw_x = x;
1963                                 draw_from = pos;
1964                         }
1965                         if (x == video_num_columns - 1) {
1966                                 need_wrap = decawm;
1967                                 draw_to = pos+2;
1968                         } else {
1969                                 x++;
1970                                 draw_to = (pos+=2);
1971                         }
1972                         continue;
1973                 }
1974                 FLUSH
1975                 do_con_trol(tty, currcons, c);
1976         }
1977         FLUSH
1978         spin_unlock_irq(&console_lock);
1979
1980 out:
1981         if (from_user) {
1982                 /* If the user requested something larger than
1983                  * the CON_BUF_SIZE, and the tty is not stopped,
1984                  * keep going.
1985                  */
1986                 if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
1987                         orig_count -= CON_BUF_SIZE;
1988                         orig_buf += CON_BUF_SIZE;
1989                         count = orig_count;
1990                         buf = orig_buf;
1991                         goto again;
1992                 }
1993
1994                 up(&con_buf_sem);
1995         }
1996
1997         return n;
1998 #undef FLUSH
1999 }
2000
2001 /*
2002  * This is the console switching tasklet.
2003  *
2004  * Doing console switching in a tasklet allows
2005  * us to do the switches asynchronously (needed when we want
2006  * to switch due to a keyboard interrupt).  Synchronization
2007  * with other console code and prevention of re-entrancy is
2008  * ensured with console_lock.
2009  */
2010 static void console_softint(unsigned long ignored)
2011 {
2012         /* Runs the task queue outside of the console lock.  These
2013          * callbacks can come back into the console code and thus
2014          * will perform their own locking.
2015          */
2016         run_task_queue(&con_task_queue);
2017
2018         spin_lock_irq(&console_lock);
2019
2020         if (want_console >= 0) {
2021                 if (want_console != fg_console && vc_cons_allocated(want_console)) {
2022                         hide_cursor(fg_console);
2023                         change_console(want_console);
2024                         /* we only changed when the console had already
2025                            been allocated - a new console is not created
2026                            in an interrupt routine */
2027                 }
2028                 want_console = -1;
2029         }
2030         if (do_poke_blanked_console) { /* do not unblank for a LED change */
2031                 do_poke_blanked_console = 0;
2032                 poke_blanked_console();
2033         }
2034         if (scrollback_delta) {
2035                 int currcons = fg_console;
2036                 clear_selection();
2037                 if (vcmode == KD_TEXT)
2038                         sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
2039                 scrollback_delta = 0;
2040         }
2041
2042         spin_unlock_irq(&console_lock);
2043 }
2044
2045 #ifdef CONFIG_VT_CONSOLE
2046
2047 /*
2048  *      Console on virtual terminal
2049  *
2050  * The console_lock must be held when we get here.
2051  */
2052
2053 void vt_console_print(struct console *co, const char * b, unsigned count)
2054 {
2055         int currcons = fg_console;
2056         unsigned char c;
2057         static unsigned long printing;
2058         const ushort *start;
2059         ushort cnt = 0;
2060         ushort myx;
2061
2062         /* console busy or not yet initialized */
2063         if (!printable || test_and_set_bit(0, &printing))
2064                 return;
2065
2066         pm_access(pm_con);
2067
2068         if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
2069                 currcons = kmsg_redirect - 1;
2070
2071         /* read `x' only after setting currecons properly (otherwise
2072            the `x' macro will read the x of the foreground console). */
2073         myx = x;
2074
2075         if (!vc_cons_allocated(currcons)) {
2076                 /* impossible */
2077                 /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
2078                 goto quit;
2079         }
2080
2081         if (vcmode != KD_TEXT)
2082                 goto quit;
2083
2084         /* undraw cursor first */
2085         if (IS_FG)
2086                 hide_cursor(currcons);
2087
2088         start = (ushort *)pos;
2089
2090         /* Contrived structure to try to emulate original need_wrap behaviour
2091          * Problems caused when we have need_wrap set on '\n' character */
2092         while (count--) {
2093                 c = *b++;
2094                 if (c == 10 || c == 13 || c == 8 || need_wrap) {
2095                         if (cnt > 0) {
2096                                 if (IS_VISIBLE)
2097                                         sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2098                                 x += cnt;
2099                                 if (need_wrap)
2100                                         x--;
2101                                 cnt = 0;
2102                         }
2103                         if (c == 8) {           /* backspace */
2104                                 bs(currcons);
2105                                 start = (ushort *)pos;
2106                                 myx = x;
2107                                 continue;
2108                         }
2109                         if (c != 13)
2110                                 lf(currcons);
2111                         cr(currcons);
2112                         start = (ushort *)pos;
2113                         myx = x;
2114                         if (c == 10 || c == 13)
2115                                 continue;
2116                 }
2117                 scr_writew((attr << 8) + c, (unsigned short *) pos);
2118                 cnt++;
2119                 if (myx == video_num_columns - 1) {
2120                         need_wrap = 1;
2121                         continue;
2122                 }
2123                 pos+=2;
2124                 myx++;
2125         }
2126         if (cnt > 0) {
2127                 if (IS_VISIBLE)
2128                         sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2129                 x += cnt;
2130                 if (x == video_num_columns) {
2131                         x--;
2132                         need_wrap = 1;
2133                 }
2134         }
2135         set_cursor(currcons);
2136
2137 quit:
2138         clear_bit(0, &printing);
2139 }
2140
2141 static kdev_t vt_console_device(struct console *c)
2142 {
2143         return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
2144 }
2145
2146 struct console vt_console_driver = {
2147         name:           "tty",
2148         write:          vt_console_print,
2149         device:         vt_console_device,
2150         wait_key:       keyboard_wait_for_keypress,
2151         unblank:        unblank_screen,
2152         flags:          CON_PRINTBUFFER,
2153         index:          -1,
2154 };
2155 #endif
2156
2157 /*
2158  *      Handling of Linux-specific VC ioctls
2159  */
2160
2161 int tioclinux(struct tty_struct *tty, unsigned long arg)
2162 {
2163         char type, data;
2164
2165         if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
2166                 return -EINVAL;
2167         if (current->tty != tty && !suser())
2168                 return -EPERM;
2169         if (get_user(type, (char *)arg))
2170                 return -EFAULT;
2171         switch (type)
2172         {
2173                 case 2:
2174                         return set_selection(arg, tty, 1);
2175                 case 3:
2176                         return paste_selection(tty);
2177                 case 4:
2178                         unblank_screen();
2179                         return 0;
2180                 case 5:
2181                         return sel_loadlut(arg);
2182                 case 6:
2183                         
2184         /*
2185          * Make it possible to react to Shift+Mousebutton.
2186          * Note that 'shift_state' is an undocumented
2187          * kernel-internal variable; programs not closely
2188          * related to the kernel should not use this.
2189          */
2190                         data = shift_state;
2191                         return __put_user(data, (char *) arg);
2192                 case 7:
2193                         data = mouse_reporting();
2194                         return __put_user(data, (char *) arg);
2195                 case 10:
2196                         set_vesa_blanking(arg);
2197                         return 0;
2198                 case 11:        /* set kmsg redirect */
2199                         if (!suser())
2200                                 return -EPERM;
2201                         if (get_user(data, (char *)arg+1))
2202                                         return -EFAULT;
2203                         kmsg_redirect = data;
2204                         return 0;
2205                 case 12:        /* get fg_console */
2206                         return fg_console;
2207         }
2208         return -EINVAL;
2209 }
2210
2211 /*
2212  *      /dev/ttyN handling
2213  */
2214
2215 static int con_write(struct tty_struct * tty, int from_user,
2216                      const unsigned char *buf, int count)
2217 {
2218         int     retval;
2219
2220         pm_access(pm_con);
2221         retval = do_con_write(tty, from_user, buf, count);
2222         con_flush_chars(tty);
2223
2224         return retval;
2225 }
2226
2227 static void con_put_char(struct tty_struct *tty, unsigned char ch)
2228 {
2229         pm_access(pm_con);
2230         do_con_write(tty, 0, &ch, 1);
2231 }
2232
2233 static int con_write_room(struct tty_struct *tty)
2234 {
2235         if (tty->stopped)
2236                 return 0;
2237         return 4096;            /* No limit, really; we're not buffering */
2238 }
2239
2240 static int con_chars_in_buffer(struct tty_struct *tty)
2241 {
2242         return 0;               /* we're not buffering */
2243 }
2244
2245 /*
2246  * con_throttle and con_unthrottle are only used for
2247  * paste_selection(), which has to stuff in a large number of
2248  * characters...
2249  */
2250 static void con_throttle(struct tty_struct *tty)
2251 {
2252 }
2253
2254 static void con_unthrottle(struct tty_struct *tty)
2255 {
2256         struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
2257
2258         wake_up_interruptible(&vt->paste_wait);
2259 }
2260
2261 /*
2262  * Turn the Scroll-Lock LED on when the tty is stopped
2263  */
2264 static void con_stop(struct tty_struct *tty)
2265 {
2266         int console_num;
2267         if (!tty)
2268                 return;
2269         console_num = MINOR(tty->device) - (tty->driver.minor_start);
2270         if (!vc_cons_allocated(console_num))
2271                 return;
2272         set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2273         set_leds();
2274 }
2275
2276 /*
2277  * Turn the Scroll-Lock LED off when the console is started
2278  */
2279 static void con_start(struct tty_struct *tty)
2280 {
2281         int console_num;
2282         if (!tty)
2283                 return;
2284         console_num = MINOR(tty->device) - (tty->driver.minor_start);
2285         if (!vc_cons_allocated(console_num))
2286                 return;
2287         clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2288         set_leds();
2289 }
2290
2291 static void con_flush_chars(struct tty_struct *tty)
2292 {
2293         unsigned long flags;
2294         struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
2295
2296         pm_access(pm_con);
2297         spin_lock_irqsave(&console_lock, flags);
2298         set_cursor(vt->vc_num);
2299         spin_unlock_irqrestore(&console_lock, flags);
2300 }
2301
2302 /*
2303  * Allocate the console screen memory.
2304  */
2305 static int con_open(struct tty_struct *tty, struct file * filp)
2306 {
2307         unsigned int    currcons;
2308         int i;
2309
2310         currcons = MINOR(tty->device) - tty->driver.minor_start;
2311
2312         i = vc_allocate(currcons);
2313         if (i)
2314                 return i;
2315
2316         vt_cons[currcons]->vc_num = currcons;
2317         tty->driver_data = vt_cons[currcons];
2318
2319         if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2320                 tty->winsize.ws_row = video_num_lines;
2321                 tty->winsize.ws_col = video_num_columns;
2322         }
2323         if (tty->count == 1)
2324                 vcs_make_devfs (currcons, 0);
2325         return 0;
2326 }
2327
2328 static void con_close(struct tty_struct *tty, struct file * filp)
2329 {
2330         if (!tty)
2331                 return;
2332         if (tty->count != 1) return;
2333         vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
2334         tty->driver_data = 0;
2335 }
2336
2337 static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
2338 {
2339         int j, k ;
2340
2341         video_num_columns = cols;
2342         video_num_lines = rows;
2343         video_size_row = cols<<1;
2344         screenbuf_size = video_num_lines * video_size_row;
2345
2346         set_origin(currcons);
2347         pos = origin;
2348         reset_vc(currcons);
2349         for (j=k=0; j<16; j++) {
2350                 vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
2351                 vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
2352                 vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
2353         }
2354         def_color       = 0x07;   /* white */
2355         ulcolor         = 0x0f;   /* bold white */
2356         halfcolor       = 0x08;   /* grey */
2357         init_waitqueue_head(&vt_cons[currcons]->paste_wait);
2358         reset_terminal(currcons, do_clear);
2359 }
2360
2361 /*
2362  * This routine initializes console interrupts, and does nothing
2363  * else. If you want the screen to clear, call tty_write with
2364  * the appropriate escape-sequence.
2365  */
2366
2367 struct tty_driver console_driver;
2368 static int console_refcount;
2369
2370 DECLARE_TASKLET_DISABLED(console_tasklet, console_softint, 0);
2371
2372 void __init con_init(void)
2373 {
2374         const char *display_desc = NULL;
2375         unsigned int currcons = 0;
2376
2377         if (conswitchp)
2378                 display_desc = conswitchp->con_startup();
2379         if (!display_desc) {
2380                 fg_console = 0;
2381                 return;
2382         }
2383
2384         memset(&console_driver, 0, sizeof(struct tty_driver));
2385         console_driver.magic = TTY_DRIVER_MAGIC;
2386         console_driver.name = "vc/%d";
2387         console_driver.name_base = 1;
2388         console_driver.major = TTY_MAJOR;
2389         console_driver.minor_start = 1;
2390         console_driver.num = MAX_NR_CONSOLES;
2391         console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
2392         console_driver.init_termios = tty_std_termios;
2393         console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2394         /* Tell tty_register_driver() to skip consoles because they are
2395          * registered before kmalloc() is ready. We'll patch them in later. 
2396          * See comments at console_init(); see also con_init_devfs(). 
2397          */
2398         console_driver.flags |= TTY_DRIVER_NO_DEVFS;
2399         console_driver.refcount = &console_refcount;
2400         console_driver.table = console_table;
2401         console_driver.termios = console_termios;
2402         console_driver.termios_locked = console_termios_locked;
2403
2404         console_driver.open = con_open;
2405         console_driver.close = con_close;
2406         console_driver.write = con_write;
2407         console_driver.write_room = con_write_room;
2408         console_driver.put_char = con_put_char;
2409         console_driver.flush_chars = con_flush_chars;
2410         console_driver.chars_in_buffer = con_chars_in_buffer;
2411         console_driver.ioctl = vt_ioctl;
2412         console_driver.stop = con_stop;
2413         console_driver.start = con_start;
2414         console_driver.throttle = con_throttle;
2415         console_driver.unthrottle = con_unthrottle;
2416
2417         if (tty_register_driver(&console_driver))
2418                 panic("Couldn't register console driver\n");
2419
2420         init_timer(&console_timer);
2421         console_timer.function = blank_screen;
2422         if (blankinterval) {
2423                 mod_timer(&console_timer, jiffies + blankinterval);
2424         }
2425
2426         /*
2427          * kmalloc is not running yet - we use the bootmem allocator.
2428          */
2429         for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2430                 vc_cons[currcons].d = (struct vc_data *)
2431                                 alloc_bootmem(sizeof(struct vc_data));
2432                 vt_cons[currcons] = (struct vt_struct *)
2433                                 alloc_bootmem(sizeof(struct vt_struct));
2434                 visual_init(currcons, 1);
2435                 screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
2436                 kmalloced = 0;
2437                 vc_init(currcons, video_num_lines, video_num_columns, 
2438                         currcons || !sw->con_save_screen);
2439         }
2440         currcons = fg_console = 0;
2441         master_display_fg = vc_cons[currcons].d;
2442         set_origin(currcons);
2443         save_screen(currcons);
2444         gotoxy(currcons,x,y);
2445         csi_J(currcons, 0);
2446         update_screen(fg_console);
2447         printk("Console: %s %s %dx%d",
2448                 can_do_color ? "colour" : "mono",
2449                 display_desc, video_num_columns, video_num_lines);
2450         printable = 1;
2451         printk("\n");
2452
2453 #ifdef CONFIG_VT_CONSOLE
2454         register_console(&vt_console_driver);
2455 #endif
2456
2457         tasklet_enable(&console_tasklet);
2458         tasklet_schedule(&console_tasklet);
2459 }
2460
2461 #ifndef VT_SINGLE_DRIVER
2462
2463 static void clear_buffer_attributes(int currcons)
2464 {
2465         unsigned short *p = (unsigned short *) origin;
2466         int count = screenbuf_size/2;
2467         int mask = hi_font_mask | 0xff;
2468
2469         for (; count > 0; count--, p++) {
2470                 scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
2471         }
2472 }
2473
2474 /*
2475  *      If we support more console drivers, this function is used
2476  *      when a driver wants to take over some existing consoles
2477  *      and become default driver for newly opened ones.
2478  */
2479
2480 void take_over_console(const struct consw *csw, int first, int last, int deflt)
2481 {
2482         int i, j = -1;
2483         const char *desc;
2484
2485         desc = csw->con_startup();
2486         if (!desc) return;
2487         if (deflt)
2488                 conswitchp = csw;
2489
2490         for (i = first; i <= last; i++) {
2491                 int old_was_color;
2492                 int currcons = i;
2493
2494                 con_driver_map[i] = csw;
2495
2496                 if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
2497                         continue;
2498
2499                 j = i;
2500                 if (IS_VISIBLE)
2501                         save_screen(i);
2502                 old_was_color = vc_cons[i].d->vc_can_do_color;
2503                 vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
2504                 visual_init(i, 0);
2505                 update_attr(i);
2506
2507                 /* If the console changed between mono <-> color, then
2508                  * the attributes in the screenbuf will be wrong.  The
2509                  * following resets all attributes to something sane.
2510                  */
2511                 if (old_was_color != vc_cons[i].d->vc_can_do_color)
2512                         clear_buffer_attributes(i);
2513
2514                 if (IS_VISIBLE)
2515                         update_screen(i);
2516         }
2517         printk("Console: switching ");
2518         if (!deflt)
2519                 printk("consoles %d-%d ", first+1, last+1);
2520         if (j >= 0)
2521                 printk("to %s %s %dx%d\n",
2522                        vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
2523                        desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
2524         else
2525                 printk("to %s\n", desc);
2526 }
2527
2528 void give_up_console(const struct consw *csw)
2529 {
2530         int i;
2531
2532         for(i = 0; i < MAX_NR_CONSOLES; i++)
2533                 if (con_driver_map[i] == csw)
2534                         con_driver_map[i] = NULL;
2535 }
2536
2537 #endif
2538
2539 /*
2540  *      Screen blanking
2541  */
2542
2543 static void set_vesa_blanking(unsigned long arg)
2544 {
2545     char *argp = (char *)arg + 1;
2546     unsigned int mode;
2547     get_user(mode, argp);
2548     vesa_blank_mode = (mode < 4) ? mode : 0;
2549 }
2550
2551 /* We can't register the console with devfs during con_init(), because it
2552  * is called before kmalloc() works.  This function is called later to
2553  * do the registration.
2554  */
2555 void __init con_init_devfs (void)
2556 {
2557         int i;
2558
2559         for (i = 0; i < console_driver.num; i++)
2560                 tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY,
2561                                     console_driver.minor_start + i);
2562 }
2563
2564 static void vesa_powerdown(void)
2565 {
2566     struct vc_data *c = vc_cons[fg_console].d;
2567     /*
2568      *  Power down if currently suspended (1 or 2),
2569      *  suspend if currently blanked (0),
2570      *  else do nothing (i.e. already powered down (3)).
2571      *  Called only if powerdown features are allowed.
2572      */
2573     switch (vesa_blank_mode) {
2574         case VESA_NO_BLANKING:
2575             c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1);
2576             break;
2577         case VESA_VSYNC_SUSPEND:
2578         case VESA_HSYNC_SUSPEND:
2579             c->vc_sw->con_blank(c, VESA_POWERDOWN+1);
2580             break;
2581     }
2582 }
2583
2584 static void vesa_powerdown_screen(unsigned long dummy)
2585 {
2586         console_timer.function = unblank_screen_t;      /* I don't have a clue why this is necessary */
2587
2588         vesa_powerdown();
2589 }
2590
2591 static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
2592 {
2593         int currcons = fg_console;
2594         int i;
2595
2596         if (console_blanked)
2597                 return;
2598
2599         /* entering graphics mode? */
2600         if (entering_gfx) {
2601                 hide_cursor(currcons);
2602                 save_screen(currcons);
2603                 sw->con_blank(vc_cons[currcons].d, -1);
2604                 console_blanked = fg_console + 1;
2605                 set_origin(currcons);
2606                 return;
2607         }
2608
2609         /* don't blank graphics */
2610         if (vcmode != KD_TEXT) {
2611                 console_blanked = fg_console + 1;
2612                 return;
2613         }
2614
2615         hide_cursor(currcons);
2616         if (!from_timer_handler)
2617                 del_timer_sync(&console_timer);
2618         if (vesa_off_interval) {
2619                 console_timer.function = vesa_powerdown_screen;
2620                 mod_timer(&console_timer, jiffies + vesa_off_interval);
2621         } else {
2622                 if (!from_timer_handler)
2623                         del_timer_sync(&console_timer);
2624                 console_timer.function = unblank_screen_t;
2625         }
2626
2627         save_screen(currcons);
2628         /* In case we need to reset origin, blanking hook returns 1 */
2629         i = sw->con_blank(vc_cons[currcons].d, 1);
2630         console_blanked = fg_console + 1;
2631         if (i)
2632                 set_origin(currcons);
2633
2634         if (console_blank_hook && console_blank_hook(1))
2635                 return;
2636         if (vesa_blank_mode)
2637                 sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
2638 }
2639
2640 void do_blank_screen(int entering_gfx)
2641 {
2642         timer_do_blank_screen(entering_gfx, 0);
2643 }
2644
2645 static void unblank_screen_t(unsigned long dummy)
2646 {
2647         unblank_screen();
2648 }
2649
2650 void unblank_screen(void)
2651 {
2652         int currcons;
2653
2654         if (!console_blanked)
2655                 return;
2656         if (!vc_cons_allocated(fg_console)) {
2657                 /* impossible */
2658                 printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2659                 return;
2660         }
2661         currcons = fg_console;
2662         if (vcmode != KD_TEXT)
2663                 return; /* but leave console_blanked != 0 */
2664
2665         console_timer.function = blank_screen;
2666         if (blankinterval) {
2667                 mod_timer(&console_timer, jiffies + blankinterval);
2668         }
2669
2670         console_blanked = 0;
2671         if (console_blank_hook)
2672                 console_blank_hook(0);
2673         set_palette(currcons);
2674         if (sw->con_blank(vc_cons[currcons].d, 0))
2675                 /* Low-level driver cannot restore -> do it ourselves */
2676                 update_screen(fg_console);
2677         set_cursor(fg_console);
2678 }
2679
2680 static void blank_screen(unsigned long dummy)
2681 {
2682         timer_do_blank_screen(0, 1);