This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / char / vt.c
1 /*
2  *  linux/drivers/char/vt.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  * Removed console_lock, enabled interrupts across all console operations
74  * 13 March 2001, Andrew Morton
75  */
76
77 #include <linux/module.h>
78 #include <linux/types.h>
79 #include <linux/sched.h>
80 #include <linux/tty.h>
81 #include <linux/tty_flip.h>
82 #include <linux/kernel.h>
83 #include <linux/string.h>
84 #include <linux/errno.h>
85 #include <linux/kd.h>
86 #include <linux/slab.h>
87 #include <linux/major.h>
88 #include <linux/mm.h>
89 #include <linux/console.h>
90 #include <linux/init.h>
91 #include <linux/devfs_fs_kernel.h>
92 #include <linux/vt_kern.h>
93 #include <linux/selection.h>
94 #include <linux/tiocl.h>
95 #include <linux/kbd_kern.h>
96 #include <linux/consolemap.h>
97 #include <linux/timer.h>
98 #include <linux/interrupt.h>
99 #include <linux/config.h>
100 #include <linux/workqueue.h>
101 #include <linux/bootmem.h>
102 #include <linux/pm.h>
103 #include <linux/font.h>
104
105 #include <asm/io.h>
106 #include <asm/system.h>
107 #include <asm/uaccess.h>
108 #include <asm/bitops.h>
109
110 #include "console_macros.h"
111
112
113 const struct consw *conswitchp;
114
115 /* A bitmap for codes <32. A bit of 1 indicates that the code
116  * corresponding to that bit number invokes some special action
117  * (such as cursor movement) and should not be displayed as a
118  * glyph unless the disp_ctrl mode is explicitly enabled.
119  */
120 #define CTRL_ACTION 0x0d00ff81
121 #define CTRL_ALWAYS 0x0800f501  /* Cannot be overridden by disp_ctrl */
122
123 /*
124  * Here is the default bell parameters: 750HZ, 1/8th of a second
125  */
126 #define DEFAULT_BELL_PITCH      750
127 #define DEFAULT_BELL_DURATION   (HZ/8)
128
129 extern void vcs_make_devfs(struct tty_struct *tty);
130 extern void vcs_remove_devfs(struct tty_struct *tty);
131
132 extern void console_map_init(void);
133 #ifdef CONFIG_PROM_CONSOLE
134 extern void prom_con_init(void);
135 #endif
136 #ifdef CONFIG_MDA_CONSOLE
137 extern int mda_console_init(void);
138 #endif
139
140 struct vc vc_cons [MAX_NR_CONSOLES];
141
142 #ifndef VT_SINGLE_DRIVER
143 static const struct consw *con_driver_map[MAX_NR_CONSOLES];
144 #endif
145
146 static int con_open(struct tty_struct *, struct file *);
147 static void vc_init(unsigned int console, unsigned int rows,
148                     unsigned int cols, int do_clear);
149 static void gotoxy(int currcons, int new_x, int new_y);
150 static void save_cur(int currcons);
151 static void reset_terminal(int currcons, int do_clear);
152 static void con_flush_chars(struct tty_struct *tty);
153 static void set_vesa_blanking(char __user *p);
154 static void set_cursor(int currcons);
155 static void hide_cursor(int currcons);
156 static void console_callback(void *ignored);
157 static void blank_screen_t(unsigned long dummy);
158
159 static int printable;           /* Is console ready for printing? */
160
161 /*
162  * ignore_poke: don't unblank the screen when things are typed.  This is
163  * mainly for the privacy of braille terminal users.
164  */
165 static int ignore_poke;
166
167 int do_poke_blanked_console;
168 int console_blanked;
169
170 static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
171 static int blankinterval = 10*60*HZ;
172 static int vesa_off_interval;
173
174 static DECLARE_WORK(console_work, console_callback, NULL);
175
176 /*
177  * fg_console is the current virtual console,
178  * last_console is the last used one,
179  * want_console is the console we want to switch to,
180  * kmsg_redirect is the console for kernel messages,
181  */
182 int fg_console;
183 int last_console;
184 int want_console = -1;
185 int kmsg_redirect;
186
187 /*
188  * For each existing display, we have a pointer to console currently visible
189  * on that display, allowing consoles other than fg_console to be refreshed
190  * appropriately. Unless the low-level driver supplies its own display_fg
191  * variable, we use this one for the "master display".
192  */
193 static struct vc_data *master_display_fg;
194
195 /*
196  * Unfortunately, we need to delay tty echo when we're currently writing to the
197  * console since the code is (and always was) not re-entrant, so we schedule
198  * all flip requests to process context with schedule-task() and run it from
199  * console_callback().
200  */
201
202 /*
203  * For the same reason, we defer scrollback to the console callback.
204  */
205 static int scrollback_delta;
206
207 /*
208  * Hook so that the power management routines can (un)blank
209  * the console on our behalf.
210  */
211 int (*console_blank_hook)(int);
212
213 static struct timer_list console_timer;
214 static int blank_state;
215 static int blank_timer_expired;
216 enum {
217         blank_off = 0,
218         blank_normal_wait,
219         blank_vesa_wait,
220 };
221
222 /*
223  *      Low-Level Functions
224  */
225
226 #define IS_FG (currcons == fg_console)
227 #define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
228
229 #ifdef VT_BUF_VRAM_ONLY
230 #define DO_UPDATE 0
231 #else
232 #define DO_UPDATE IS_VISIBLE
233 #endif
234
235 static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
236 static struct pm_dev *pm_con;
237
238 static inline unsigned short *screenpos(int currcons, int offset, int viewed)
239 {
240         unsigned short *p;
241         
242         if (!viewed)
243                 p = (unsigned short *)(origin + offset);
244         else if (!sw->con_screen_pos)
245                 p = (unsigned short *)(visible_origin + offset);
246         else
247                 p = sw->con_screen_pos(vc_cons[currcons].d, offset);
248         return p;
249 }
250
251 static inline void scrolldelta(int lines)
252 {
253         scrollback_delta += lines;
254         schedule_console_callback();
255 }
256
257 void schedule_console_callback(void)
258 {
259         schedule_work(&console_work);
260 }
261
262 static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
263 {
264         unsigned short *d, *s;
265
266         if (t+nr >= b)
267                 nr = b - t - 1;
268         if (b > video_num_lines || t >= b || nr < 1)
269                 return;
270         if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
271                 return;
272         d = (unsigned short *) (origin+video_size_row*t);
273         s = (unsigned short *) (origin+video_size_row*(t+nr));
274         scr_memmovew(d, s, (b-t-nr) * video_size_row);
275         scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
276 }
277
278 static void
279 scrdown(int currcons, unsigned int t, unsigned int b, int nr)
280 {
281         unsigned short *s;
282         unsigned int step;
283
284         if (t+nr >= b)
285                 nr = b - t - 1;
286         if (b > video_num_lines || t >= b || nr < 1)
287                 return;
288         if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
289                 return;
290         s = (unsigned short *) (origin+video_size_row*t);
291         step = video_num_columns * nr;
292         scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
293         scr_memsetw(s, video_erase_char, 2*step);
294 }
295
296 static void do_update_region(int currcons, unsigned long start, int count)
297 {
298 #ifndef VT_BUF_VRAM_ONLY
299         unsigned int xx, yy, offset;
300         u16 *p;
301
302         p = (u16 *) start;
303         if (!sw->con_getxy) {
304                 offset = (start - origin) / 2;
305                 xx = offset % video_num_columns;
306                 yy = offset / video_num_columns;
307         } else {
308                 int nxx, nyy;
309                 start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
310                 xx = nxx; yy = nyy;
311         }
312         for(;;) {
313                 u16 attrib = scr_readw(p) & 0xff00;
314                 int startx = xx;
315                 u16 *q = p;
316                 while (xx < video_num_columns && count) {
317                         if (attrib != (scr_readw(p) & 0xff00)) {
318                                 if (p > q)
319                                         sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
320                                 startx = xx;
321                                 q = p;
322                                 attrib = scr_readw(p) & 0xff00;
323                         }
324                         p++;
325                         xx++;
326                         count--;
327                 }
328                 if (p > q)
329                         sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
330                 if (!count)
331                         break;
332                 xx = 0;
333                 yy++;
334                 if (sw->con_getxy) {
335                         p = (u16 *)start;
336                         start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
337                 }
338         }
339 #endif
340 }
341
342 void update_region(int currcons, unsigned long start, int count)
343 {
344         WARN_CONSOLE_UNLOCKED();
345
346         if (DO_UPDATE) {
347                 hide_cursor(currcons);
348                 do_update_region(currcons, start, count);
349                 set_cursor(currcons);
350         }
351 }
352
353 /* Structure of attributes is hardware-dependent */
354
355 static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
356 {
357         if (sw->con_build_attr)
358                 return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
359
360 #ifndef VT_BUF_VRAM_ONLY
361 /*
362  * ++roman: I completely changed the attribute format for monochrome
363  * mode (!can_do_color). The formerly used MDA (monochrome display
364  * adapter) format didn't allow the combination of certain effects.
365  * Now the attribute is just a bit vector:
366  *  Bit 0..1: intensity (0..2)
367  *  Bit 2   : underline
368  *  Bit 3   : reverse
369  *  Bit 7   : blink
370  */
371         {
372         u8 a = color;
373         if (!can_do_color)
374                 return _intensity |
375                        (_underline ? 4 : 0) |
376                        (_reverse ? 8 : 0) |
377                        (_blink ? 0x80 : 0);
378         if (_underline)
379                 a = (a & 0xf0) | ulcolor;
380         else if (_intensity == 0)
381                 a = (a & 0xf0) | halfcolor;
382         if (_reverse)
383                 a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
384         if (_blink)
385                 a ^= 0x80;
386         if (_intensity == 2)
387                 a ^= 0x08;
388         if (hi_font_mask == 0x100)
389                 a <<= 1;
390         return a;
391         }
392 #else
393         return 0;
394 #endif
395 }
396
397 static void update_attr(int currcons)
398 {
399         attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
400         video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
401 }
402
403 /* Note: inverting the screen twice should revert to the original state */
404
405 void invert_screen(int currcons, int offset, int count, int viewed)
406 {
407         unsigned short *p;
408
409         WARN_CONSOLE_UNLOCKED();
410
411         count /= 2;
412         p = screenpos(currcons, offset, viewed);
413         if (sw->con_invert_region)
414                 sw->con_invert_region(vc_cons[currcons].d, p, count);
415 #ifndef VT_BUF_VRAM_ONLY
416         else {
417                 u16 *q = p;
418                 int cnt = count;
419                 u16 a;
420
421                 if (!can_do_color) {
422                         while (cnt--) {
423                             a = scr_readw(q);
424                             a ^= 0x0800;
425                             scr_writew(a, q);
426                             q++;
427                         }
428                 } else if (hi_font_mask == 0x100) {
429                         while (cnt--) {
430                                 a = scr_readw(q);
431                                 a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
432                                 scr_writew(a, q);
433                                 q++;
434                         }
435                 } else {
436                         while (cnt--) {
437                                 a = scr_readw(q);
438                                 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
439                                 scr_writew(a, q);
440                                 q++;
441                         }
442                 }
443         }
444 #endif
445         if (DO_UPDATE)
446                 do_update_region(currcons, (unsigned long) p, count);
447 }
448
449 /* used by selection: complement pointer position */
450 void complement_pos(int currcons, int offset)
451 {
452         static unsigned short *p;
453         static unsigned short old;
454         static unsigned short oldx, oldy;
455
456         WARN_CONSOLE_UNLOCKED();
457
458         if (p) {
459                 scr_writew(old, p);
460                 if (DO_UPDATE)
461                         sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
462         }
463         if (offset == -1)
464                 p = NULL;
465         else {
466                 unsigned short new;
467                 p = screenpos(currcons, offset, 1);
468                 old = scr_readw(p);
469                 new = old ^ complement_mask;
470                 scr_writew(new, p);
471                 if (DO_UPDATE) {
472                         oldx = (offset >> 1) % video_num_columns;
473                         oldy = (offset >> 1) / video_num_columns;
474                         sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
475                 }
476         }
477 }
478
479 static void insert_char(int currcons, unsigned int nr)
480 {
481         unsigned short *p, *q = (unsigned short *) pos;
482
483         p = q + video_num_columns - nr - x;
484         while (--p >= q)
485                 scr_writew(scr_readw(p), p + nr);
486         scr_memsetw(q, video_erase_char, nr*2);
487         need_wrap = 0;
488         if (DO_UPDATE) {
489                 unsigned short oldattr = attr;
490                 sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
491                               video_num_columns-x-nr);
492                 attr = video_erase_char >> 8;
493                 while (nr--)
494                         sw->con_putc(vc_cons[currcons].d,
495                                      video_erase_char,y,x+nr);
496                 attr = oldattr;
497         }
498 }
499
500 static void delete_char(int currcons, unsigned int nr)
501 {
502         unsigned int i = x;
503         unsigned short *p = (unsigned short *) pos;
504
505         while (++i <= video_num_columns - nr) {
506                 scr_writew(scr_readw(p+nr), p);
507                 p++;
508         }
509         scr_memsetw(p, video_erase_char, nr*2);
510         need_wrap = 0;
511         if (DO_UPDATE) {
512                 unsigned short oldattr = attr;
513                 sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
514                               video_num_columns-x-nr);
515                 attr = video_erase_char >> 8;
516                 while (nr--)
517                         sw->con_putc(vc_cons[currcons].d,
518                                      video_erase_char, y,
519                                      video_num_columns-1-nr);
520                 attr = oldattr;
521         }
522 }
523
524 static int softcursor_original;
525
526 static void add_softcursor(int currcons)
527 {
528         int i = scr_readw((u16 *) pos);
529         u32 type = cursor_type;
530
531         if (! (type & 0x10)) return;
532         if (softcursor_original != -1) return;
533         softcursor_original = i;
534         i |= ((type >> 8) & 0xff00 );
535         i ^= ((type) & 0xff00 );
536         if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
537         if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
538         scr_writew(i, (u16 *) pos);
539         if (DO_UPDATE)
540                 sw->con_putc(vc_cons[currcons].d, i, y, x);
541 }
542
543 static void hide_softcursor(int currcons)
544 {
545         if (softcursor_original != -1) {
546                 scr_writew(softcursor_original,(u16 *) pos);
547                 if (DO_UPDATE)
548                         sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
549                 softcursor_original = -1;
550         }
551 }
552
553 static void hide_cursor(int currcons)
554 {
555         if (currcons == sel_cons)
556                 clear_selection();
557         sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
558         hide_softcursor(currcons);
559 }
560
561 static void set_cursor(int currcons)
562 {
563     if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
564         return;
565     if (deccm) {
566         if (currcons == sel_cons)
567                 clear_selection();
568         add_softcursor(currcons);
569         if ((cursor_type & 0x0f) != 1)
570             sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
571     } else
572         hide_cursor(currcons);
573 }
574
575 static void set_origin(int currcons)
576 {
577         WARN_CONSOLE_UNLOCKED();
578
579         if (!IS_VISIBLE ||
580             !sw->con_set_origin ||
581             !sw->con_set_origin(vc_cons[currcons].d))
582                 origin = (unsigned long) screenbuf;
583         visible_origin = origin;
584         scr_end = origin + screenbuf_size;
585         pos = origin + video_size_row*y + 2*x;
586 }
587
588 static inline void save_screen(int currcons)
589 {
590         WARN_CONSOLE_UNLOCKED();
591
592         if (sw->con_save_screen)
593                 sw->con_save_screen(vc_cons[currcons].d);
594 }
595
596 /*
597  *      Redrawing of screen
598  */
599
600 static void clear_buffer_attributes(int currcons)
601 {
602         unsigned short *p = (unsigned short *) origin;
603         int count = screenbuf_size/2;
604         int mask = hi_font_mask | 0xff;
605
606         for (; count > 0; count--, p++) {
607                 scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
608         }
609 }
610
611 void redraw_screen(int new_console, int is_switch)
612 {
613         int redraw = 1;
614         int currcons, old_console;
615
616         WARN_CONSOLE_UNLOCKED();
617
618         if (!vc_cons_allocated(new_console)) {
619                 /* strange ... */
620                 /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
621                 return;
622         }
623
624         if (is_switch) {
625                 currcons = fg_console;
626                 hide_cursor(currcons);
627                 if (fg_console != new_console) {
628                         struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
629                         old_console = (*display) ? (*display)->vc_num : fg_console;
630                         *display = vc_cons[new_console].d;
631                         fg_console = new_console;
632                         currcons = old_console;
633                         if (!IS_VISIBLE) {
634                                 save_screen(currcons);
635                                 set_origin(currcons);
636                         }
637                         currcons = new_console;
638                         if (old_console == new_console)
639                                 redraw = 0;
640                 }
641         } else {
642                 currcons = new_console;
643                 hide_cursor(currcons);
644         }
645
646         if (redraw) {
647                 int update;
648                 int old_was_color = vc_cons[currcons].d->vc_can_do_color;
649
650                 set_origin(currcons);
651                 update = sw->con_switch(vc_cons[currcons].d);
652                 set_palette(currcons);
653                 /*
654                  * If console changed from mono<->color, the best we can do
655                  * is to clear the buffer attributes. As it currently stands,
656                  * rebuilding new attributes from the old buffer is not doable
657                  * without overly complex code.
658                  */
659                 if (old_was_color != vc_cons[currcons].d->vc_can_do_color) {
660                         update_attr(currcons);
661                         clear_buffer_attributes(currcons);
662                 }
663                 if (update && vcmode != KD_GRAPHICS)
664                         do_update_region(currcons, origin, screenbuf_size/2);
665         }
666         set_cursor(currcons);
667         if (is_switch) {
668                 set_leds();
669                 compute_shiftstate();
670         }
671 }
672
673 /*
674  *      Allocation, freeing and resizing of VTs.
675  */
676
677 int vc_cons_allocated(unsigned int i)
678 {
679         return (i < MAX_NR_CONSOLES && vc_cons[i].d);
680 }
681
682 static void visual_init(int currcons, int init)
683 {
684     /* ++Geert: sw->con_init determines console size */
685     if (sw)
686         module_put(sw->owner);
687     sw = conswitchp;
688 #ifndef VT_SINGLE_DRIVER
689     if (con_driver_map[currcons])
690         sw = con_driver_map[currcons];
691 #endif
692     __module_get(sw->owner);
693     cons_num = currcons;
694     display_fg = &master_display_fg;
695     vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
696     vc_cons[currcons].d->vc_uni_pagedir = 0;
697     hi_font_mask = 0;
698     complement_mask = 0;
699     can_do_color = 0;
700     sw->con_init(vc_cons[currcons].d, init);
701     if (!complement_mask)
702         complement_mask = can_do_color ? 0x7700 : 0x0800;
703     s_complement_mask = complement_mask;
704     video_size_row = video_num_columns<<1;
705     screenbuf_size = video_num_lines*video_size_row;
706 }
707
708 int vc_allocate(unsigned int currcons)  /* return 0 on success */
709 {
710         WARN_CONSOLE_UNLOCKED();
711
712         if (currcons >= MAX_NR_CONSOLES)
713                 return -ENXIO;
714         if (!vc_cons[currcons].d) {
715             long p, q;
716
717             /* prevent users from taking too much memory */
718             if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
719               return -EPERM;
720
721             /* due to the granularity of kmalloc, we waste some memory here */
722             /* the alloc is done in two steps, to optimize the common situation
723                of a 25x80 console (structsize=216, screenbuf_size=4000) */
724             /* although the numbers above are not valid since long ago, the
725                point is still up-to-date and the comment still has its value
726                even if only as a historical artifact.  --mj, July 1998 */
727             p = (long) kmalloc(structsize, GFP_KERNEL);
728             if (!p)
729                 return -ENOMEM;
730             memset((void *)p, 0, structsize);
731             vc_cons[currcons].d = (struct vc_data *)p;
732             vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
733             visual_init(currcons, 1);
734             if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
735                 con_set_default_unimap(currcons);
736             q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
737             if (!q) {
738                 kfree((char *) p);
739                 vc_cons[currcons].d = NULL;
740                 vt_cons[currcons] = NULL;
741                 return -ENOMEM;
742             }
743             screenbuf = (unsigned short *) q;
744             kmalloced = 1;
745             vc_init(currcons, video_num_lines, video_num_columns, 1);
746
747             if (!pm_con) {
748                     pm_con = pm_register(PM_SYS_DEV,
749                                          PM_SYS_VGA,
750                                          pm_con_request);
751             }
752         }
753         return 0;
754 }
755
756 inline int resize_screen(int currcons, int width, int height)
757 {
758         /* Resizes the resolution of the display adapater */
759         int err = 0;
760
761         if (vcmode != KD_GRAPHICS && sw->con_resize)
762                 err = sw->con_resize(vc_cons[currcons].d, width, height);
763         return err;
764 }
765
766 /*
767  * Change # of rows and columns (0 means unchanged/the size of fg_console)
768  * [this is to be used together with some user program
769  * like resize that changes the hardware videomode]
770  */
771 #define VC_RESIZE_MAXCOL (32767)
772 #define VC_RESIZE_MAXROW (32767)
773 int vc_resize(int currcons, unsigned int cols, unsigned int lines)
774 {
775         unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
776         unsigned int old_cols, old_rows, old_row_size, old_screen_size;
777         unsigned int new_cols, new_rows, new_row_size, new_screen_size;
778         unsigned short *newscreen;
779
780         WARN_CONSOLE_UNLOCKED();
781
782         if (!vc_cons_allocated(currcons))
783                 return -ENXIO;
784
785         if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
786                 return -EINVAL;
787
788         new_cols = (cols ? cols : video_num_columns);
789         new_rows = (lines ? lines : video_num_lines);
790         new_row_size = new_cols << 1;
791         new_screen_size = new_row_size * new_rows;
792
793         if (new_cols == video_num_columns && new_rows == video_num_lines)
794                 return 0;
795
796         newscreen = (unsigned short *) kmalloc(new_screen_size, GFP_USER);
797         if (!newscreen)
798                 return -ENOMEM;
799
800         old_rows = video_num_lines;
801         old_cols = video_num_columns;
802         old_row_size = video_size_row;
803         old_screen_size = screenbuf_size;
804
805         err = resize_screen(currcons, new_cols, new_rows);
806         if (err) {
807                 kfree(newscreen);
808                 return err;
809         }
810
811         video_num_lines = new_rows;
812         video_num_columns = new_cols;
813         video_size_row = new_row_size;
814         screenbuf_size = new_screen_size;
815
816         rlth = min(old_row_size, new_row_size);
817         rrem = new_row_size - rlth;
818         old_origin = origin;
819         new_origin = (long) newscreen;
820         new_scr_end = new_origin + new_screen_size;
821         if (new_rows < old_rows)
822                 old_origin += (old_rows - new_rows) * old_row_size;
823
824         update_attr(currcons);
825
826         while (old_origin < scr_end) {
827                 scr_memcpyw((unsigned short *) new_origin, (unsigned short *) old_origin, rlth);
828                 if (rrem)
829                         scr_memsetw((void *)(new_origin + rlth), video_erase_char, rrem);
830                 old_origin += old_row_size;
831                 new_origin += new_row_size;
832         }
833         if (new_scr_end > new_origin)
834                 scr_memsetw((void *) new_origin, video_erase_char, new_scr_end - new_origin);
835         if (kmalloced)
836                 kfree(screenbuf);
837         screenbuf = newscreen;
838         kmalloced = 1;
839         screenbuf_size = new_screen_size;
840         set_origin(currcons);
841
842         /* do part of a reset_terminal() */
843         top = 0;
844         bottom = video_num_lines;
845         gotoxy(currcons, x, y);
846         save_cur(currcons);
847
848         if (vc_cons[currcons].d->vc_tty) {
849                 struct winsize ws, *cws = &vc_cons[currcons].d->vc_tty->winsize;
850
851                 memset(&ws, 0, sizeof(ws));
852                 ws.ws_row = video_num_lines;
853                 ws.ws_col = video_num_columns;
854                 ws.ws_ypixel = video_scan_lines;
855                 if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
856                     vc_cons[currcons].d->vc_tty->pgrp > 0)
857                         kill_pg(vc_cons[currcons].d->vc_tty->pgrp, SIGWINCH, 1);
858                 *cws = ws;
859         }
860
861         if (IS_VISIBLE)
862                 update_screen(currcons);
863         return err;
864 }
865
866
867 void vc_disallocate(unsigned int currcons)
868 {
869         WARN_CONSOLE_UNLOCKED();
870
871         if (vc_cons_allocated(currcons)) {
872             sw->con_deinit(vc_cons[currcons].d);
873             if (kmalloced)
874                 kfree(screenbuf);
875             if (currcons >= MIN_NR_CONSOLES)
876                 kfree(vc_cons[currcons].d);
877             vc_cons[currcons].d = NULL;
878         }
879 }
880
881 /*
882  *      VT102 emulator
883  */
884
885 #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
886 #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
887 #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
888
889 #define decarm          VC_REPEAT
890 #define decckm          VC_CKMODE
891 #define kbdapplic       VC_APPLIC
892 #define lnm             VC_CRLF
893
894 /*
895  * this is what the terminal answers to a ESC-Z or csi0c query.
896  */
897 #define VT100ID "\033[?1;2c"
898 #define VT102ID "\033[?6c"
899
900 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
901                                        8,12,10,14, 9,13,11,15 };
902
903 /* the default colour table, for VGA+ colour systems */
904 int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
905     0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
906 int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
907     0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
908 int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
909     0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
910
911 /*
912  * gotoxy() must verify all boundaries, because the arguments
913  * might also be negative. If the given position is out of
914  * bounds, the cursor is placed at the nearest margin.
915  */
916 static void gotoxy(int currcons, int new_x, int new_y)
917 {
918         int min_y, max_y;
919
920         if (new_x < 0)
921                 x = 0;
922         else
923                 if (new_x >= video_num_columns)
924                         x = video_num_columns - 1;
925                 else
926                         x = new_x;
927         if (decom) {
928                 min_y = top;
929                 max_y = bottom;
930         } else {
931                 min_y = 0;
932                 max_y = video_num_lines;
933         }
934         if (new_y < min_y)
935                 y = min_y;
936         else if (new_y >= max_y)
937                 y = max_y - 1;
938         else
939                 y = new_y;
940         pos = origin + y*video_size_row + (x<<1);
941         need_wrap = 0;
942 }
943
944 /* for absolute user moves, when decom is set */
945 static void gotoxay(int currcons, int new_x, int new_y)
946 {
947         gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
948 }
949
950 void scrollback(int lines)
951 {
952         int currcons = fg_console;
953
954         if (!lines)
955                 lines = video_num_lines/2;
956         scrolldelta(-lines);
957 }
958
959 void scrollfront(int lines)
960 {
961         int currcons = fg_console;
962
963         if (!lines)
964                 lines = video_num_lines/2;
965         scrolldelta(lines);
966 }
967
968 static void lf(int currcons)
969 {
970         /* don't scroll if above bottom of scrolling region, or
971          * if below scrolling region
972          */
973         if (y+1 == bottom)
974                 scrup(currcons,top,bottom,1);
975         else if (y < video_num_lines-1) {
976                 y++;
977                 pos += video_size_row;
978         }
979         need_wrap = 0;
980 }
981
982 static void ri(int currcons)
983 {
984         /* don't scroll if below top of scrolling region, or
985          * if above scrolling region
986          */
987         if (y == top)
988                 scrdown(currcons,top,bottom,1);
989         else if (y > 0) {
990                 y--;
991                 pos -= video_size_row;
992         }
993         need_wrap = 0;
994 }
995
996 static inline void cr(int currcons)
997 {
998         pos -= x<<1;
999         need_wrap = x = 0;
1000 }
1001
1002 static inline void bs(int currcons)
1003 {
1004         if (x) {
1005                 pos -= 2;
1006                 x--;
1007                 need_wrap = 0;
1008         }
1009 }
1010
1011 static inline void del(int currcons)
1012 {
1013         /* ignored */
1014 }
1015
1016 static void csi_J(int currcons, int vpar)
1017 {
1018         unsigned int count;
1019         unsigned short * start;
1020
1021         switch (vpar) {
1022                 case 0: /* erase from cursor to end of display */
1023                         count = (scr_end-pos)>>1;
1024                         start = (unsigned short *) pos;
1025                         if (DO_UPDATE) {
1026                                 /* do in two stages */
1027                                 sw->con_clear(vc_cons[currcons].d, y, x, 1,
1028                                               video_num_columns-x);
1029                                 sw->con_clear(vc_cons[currcons].d, y+1, 0,
1030                                               video_num_lines-y-1,
1031                                               video_num_columns);
1032                         }
1033                         break;
1034                 case 1: /* erase from start to cursor */
1035                         count = ((pos-origin)>>1)+1;
1036                         start = (unsigned short *) origin;
1037                         if (DO_UPDATE) {
1038                                 /* do in two stages */
1039                                 sw->con_clear(vc_cons[currcons].d, 0, 0, y,
1040                                               video_num_columns);
1041                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1042                                               x + 1);
1043                         }
1044                         break;
1045                 case 2: /* erase whole display */
1046                         count = video_num_columns * video_num_lines;
1047                         start = (unsigned short *) origin;
1048                         if (DO_UPDATE)
1049                                 sw->con_clear(vc_cons[currcons].d, 0, 0,
1050                                               video_num_lines,
1051                                               video_num_columns);
1052                         break;
1053                 default:
1054                         return;
1055         }
1056         scr_memsetw(start, video_erase_char, 2*count);
1057         need_wrap = 0;
1058 }
1059
1060 static void csi_K(int currcons, int vpar)
1061 {
1062         unsigned int count;
1063         unsigned short * start;
1064
1065         switch (vpar) {
1066                 case 0: /* erase from cursor to end of line */
1067                         count = video_num_columns-x;
1068                         start = (unsigned short *) pos;
1069                         if (DO_UPDATE)
1070                                 sw->con_clear(vc_cons[currcons].d, y, x, 1,
1071                                               video_num_columns-x);
1072                         break;
1073                 case 1: /* erase from start of line to cursor */
1074                         start = (unsigned short *) (pos - (x<<1));
1075                         count = x+1;
1076                         if (DO_UPDATE)
1077                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1078                                               x + 1);
1079                         break;
1080                 case 2: /* erase whole line */
1081                         start = (unsigned short *) (pos - (x<<1));
1082                         count = video_num_columns;
1083                         if (DO_UPDATE)
1084                                 sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1085                                               video_num_columns);
1086                         break;
1087                 default:
1088                         return;
1089         }
1090         scr_memsetw(start, video_erase_char, 2 * count);
1091         need_wrap = 0;
1092 }
1093
1094 static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
1095 {                                         /* not vt100? */
1096         int count;
1097
1098         if (!vpar)
1099                 vpar++;
1100         count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
1101
1102         scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
1103         if (DO_UPDATE)
1104                 sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
1105         need_wrap = 0;
1106 }
1107
1108 static void default_attr(int currcons)
1109 {
1110         intensity = 1;
1111         underline = 0;
1112         reverse = 0;
1113         blink = 0;
1114         color = def_color;
1115 }
1116
1117 /* console_sem is held */
1118 static void csi_m(int currcons)
1119 {
1120         int i;
1121
1122         for (i=0;i<=npar;i++)
1123                 switch (par[i]) {
1124                         case 0: /* all attributes off */
1125                                 default_attr(currcons);
1126                                 break;
1127                         case 1:
1128                                 intensity = 2;
1129                                 break;
1130                         case 2:
1131                                 intensity = 0;
1132                                 break;
1133                         case 4:
1134                                 underline = 1;
1135                                 break;
1136                         case 5:
1137                                 blink = 1;
1138                                 break;
1139                         case 7:
1140                                 reverse = 1;
1141                                 break;
1142                         case 10: /* ANSI X3.64-1979 (SCO-ish?)
1143                                   * Select primary font, don't display
1144                                   * control chars if defined, don't set
1145                                   * bit 8 on output.
1146                                   */
1147                                 translate = set_translate(charset == 0
1148                                                 ? G0_charset
1149                                                 : G1_charset,currcons);
1150                                 disp_ctrl = 0;
1151                                 toggle_meta = 0;
1152                                 break;
1153                         case 11: /* ANSI X3.64-1979 (SCO-ish?)
1154                                   * Select first alternate font, lets
1155                                   * chars < 32 be displayed as ROM chars.
1156                                   */
1157                                 translate = set_translate(IBMPC_MAP,currcons);
1158                                 disp_ctrl = 1;
1159                                 toggle_meta = 0;
1160                                 break;
1161                         case 12: /* ANSI X3.64-1979 (SCO-ish?)
1162                                   * Select second alternate font, toggle
1163                                   * high bit before displaying as ROM char.
1164                                   */
1165                                 translate = set_translate(IBMPC_MAP,currcons);
1166                                 disp_ctrl = 1;
1167                                 toggle_meta = 1;
1168                                 break;
1169                         case 21:
1170                         case 22:
1171                                 intensity = 1;
1172                                 break;
1173                         case 24:
1174                                 underline = 0;
1175                                 break;
1176                         case 25:
1177                                 blink = 0;
1178                                 break;
1179                         case 27:
1180                                 reverse = 0;
1181                                 break;
1182                         case 38: /* ANSI X3.64-1979 (SCO-ish?)
1183                                   * Enables underscore, white foreground
1184                                   * with white underscore (Linux - use
1185                                   * default foreground).
1186                                   */
1187                                 color = (def_color & 0x0f) | background;
1188                                 underline = 1;
1189                                 break;
1190                         case 39: /* ANSI X3.64-1979 (SCO-ish?)
1191                                   * Disable underline option.
1192                                   * Reset colour to default? It did this
1193                                   * before...
1194                                   */
1195                                 color = (def_color & 0x0f) | background;
1196                                 underline = 0;
1197                                 break;
1198                         case 49:
1199                                 color = (def_color & 0xf0) | foreground;
1200                                 break;
1201                         default:
1202                                 if (par[i] >= 30 && par[i] <= 37)
1203                                         color = color_table[par[i]-30]
1204                                                 | background;
1205                                 else if (par[i] >= 40 && par[i] <= 47)
1206                                         color = (color_table[par[i]-40]<<4)
1207                                                 | foreground;
1208                                 break;
1209                 }
1210         update_attr(currcons);
1211 }
1212
1213 static void respond_string(const char *p, struct tty_struct *tty)
1214 {
1215         while (*p) {
1216                 tty_insert_flip_char(tty, *p, 0);
1217                 p++;
1218         }
1219         con_schedule_flip(tty);
1220 }
1221
1222 static void cursor_report(int currcons, struct tty_struct *tty)
1223 {
1224         char buf[40];
1225
1226         sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
1227         respond_string(buf, tty);
1228 }
1229
1230 static inline void status_report(struct tty_struct *tty)
1231 {
1232         respond_string("\033[0n", tty); /* Terminal ok */
1233 }
1234
1235 static inline void respond_ID(struct tty_struct * tty)
1236 {
1237         respond_string(VT102ID, tty);
1238 }
1239
1240 void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
1241 {
1242         char buf[8];
1243
1244         sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1245                 (char)('!' + mry));
1246         respond_string(buf, tty);
1247 }
1248
1249 /* invoked via ioctl(TIOCLINUX) and through set_selection */
1250 int mouse_reporting(void)
1251 {
1252         int currcons = fg_console;
1253
1254         return report_mouse;
1255 }
1256
1257 /* console_sem is held */
1258 static void set_mode(int currcons, int on_off)
1259 {
1260         int i;
1261
1262         for (i=0; i<=npar; i++)
1263                 if (ques) switch(par[i]) {      /* DEC private modes set/reset */
1264                         case 1:                 /* Cursor keys send ^[Ox/^[[x */
1265                                 if (on_off)
1266                                         set_kbd(decckm);
1267                                 else
1268                                         clr_kbd(decckm);
1269                                 break;
1270                         case 3: /* 80/132 mode switch unimplemented */
1271                                 deccolm = on_off;
1272 #if 0
1273                                 (void) vc_resize(deccolm ? 132 : 80, video_num_lines);
1274                                 /* this alone does not suffice; some user mode
1275                                    utility has to change the hardware regs */
1276 #endif
1277                                 break;
1278                         case 5:                 /* Inverted screen on/off */
1279                                 if (decscnm != on_off) {
1280                                         decscnm = on_off;
1281                                         invert_screen(currcons, 0, screenbuf_size, 0);
1282                                         update_attr(currcons);
1283                                 }
1284                                 break;
1285                         case 6:                 /* Origin relative/absolute */
1286                                 decom = on_off;
1287                                 gotoxay(currcons,0,0);
1288                                 break;
1289                         case 7:                 /* Autowrap on/off */
1290                                 decawm = on_off;
1291                                 break;
1292                         case 8:                 /* Autorepeat on/off */
1293                                 if (on_off)
1294                                         set_kbd(decarm);
1295                                 else
1296                                         clr_kbd(decarm);
1297                                 break;
1298                         case 9:
1299                                 report_mouse = on_off ? 1 : 0;
1300                                 break;
1301                         case 25:                /* Cursor on/off */
1302                                 deccm = on_off;
1303                                 break;
1304                         case 1000:
1305                                 report_mouse = on_off ? 2 : 0;
1306                                 break;
1307                 } else switch(par[i]) {         /* ANSI modes set/reset */
1308                         case 3:                 /* Monitor (display ctrls) */
1309                                 disp_ctrl = on_off;
1310                                 break;
1311                         case 4:                 /* Insert Mode on/off */
1312                                 decim = on_off;
1313                                 break;
1314                         case 20:                /* Lf, Enter == CrLf/Lf */
1315                                 if (on_off)
1316                                         set_kbd(lnm);
1317                                 else
1318                                         clr_kbd(lnm);
1319                                 break;
1320                 }
1321 }
1322
1323 /* console_sem is held */
1324 static void setterm_command(int currcons)
1325 {
1326         switch(par[0]) {
1327                 case 1: /* set color for underline mode */
1328                         if (can_do_color && par[1] < 16) {
1329                                 ulcolor = color_table[par[1]];
1330                                 if (underline)
1331                                         update_attr(currcons);
1332                         }
1333                         break;
1334                 case 2: /* set color for half intensity mode */
1335                         if (can_do_color && par[1] < 16) {
1336                                 halfcolor = color_table[par[1]];
1337                                 if (intensity == 0)
1338                                         update_attr(currcons);
1339                         }
1340                         break;
1341                 case 8: /* store colors as defaults */
1342                         def_color = attr;
1343                         if (hi_font_mask == 0x100)
1344                                 def_color >>= 1;
1345                         default_attr(currcons);
1346                         update_attr(currcons);
1347                         break;
1348                 case 9: /* set blanking interval */
1349                         blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1350                         poke_blanked_console();
1351                         break;
1352                 case 10: /* set bell frequency in Hz */
1353                         if (npar >= 1)
1354                                 bell_pitch = par[1];
1355                         else
1356                                 bell_pitch = DEFAULT_BELL_PITCH;
1357                         break;
1358                 case 11: /* set bell duration in msec */
1359                         if (npar >= 1)
1360                                 bell_duration = (par[1] < 2000) ?
1361                                         par[1]*HZ/1000 : 0;
1362                         else
1363                                 bell_duration = DEFAULT_BELL_DURATION;
1364                         break;
1365                 case 12: /* bring specified console to the front */
1366                         if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
1367                                 set_console(par[1] - 1);
1368                         break;
1369                 case 13: /* unblank the screen */
1370                         poke_blanked_console();
1371                         break;
1372                 case 14: /* set vesa powerdown interval */
1373                         vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1374                         break;
1375                 case 15: /* activate the previous console */
1376                         set_console(last_console);
1377                         break;
1378         }
1379 }
1380
1381 /* console_sem is held */
1382 static void csi_at(int currcons, unsigned int nr)
1383 {
1384         if (nr > video_num_columns - x)
1385                 nr = video_num_columns - x;
1386         else if (!nr)
1387                 nr = 1;
1388         insert_char(currcons, nr);
1389 }
1390
1391 /* console_sem is held */
1392 static void csi_L(int currcons, unsigned int nr)
1393 {
1394         if (nr > video_num_lines - y)
1395                 nr = video_num_lines - y;
1396         else if (!nr)
1397                 nr = 1;
1398         scrdown(currcons,y,bottom,nr);
1399         need_wrap = 0;
1400 }
1401
1402 /* console_sem is held */
1403 static void csi_P(int currcons, unsigned int nr)
1404 {
1405         if (nr > video_num_columns - x)
1406                 nr = video_num_columns - x;
1407         else if (!nr)
1408                 nr = 1;
1409         delete_char(currcons, nr);
1410 }
1411
1412 /* console_sem is held */
1413 static void csi_M(int currcons, unsigned int nr)
1414 {
1415         if (nr > video_num_lines - y)
1416                 nr = video_num_lines - y;
1417         else if (!nr)
1418                 nr=1;
1419         scrup(currcons,y,bottom,nr);
1420         need_wrap = 0;
1421 }
1422
1423 /* console_sem is held (except via vc_init->reset_terminal */
1424 static void save_cur(int currcons)
1425 {
1426         saved_x         = x;
1427         saved_y         = y;
1428         s_intensity     = intensity;
1429         s_underline     = underline;
1430         s_blink         = blink;
1431         s_reverse       = reverse;
1432         s_charset       = charset;
1433         s_color         = color;
1434         saved_G0        = G0_charset;
1435         saved_G1        = G1_charset;
1436 }
1437
1438 /* console_sem is held */
1439 static void restore_cur(int currcons)
1440 {
1441         gotoxy(currcons,saved_x,saved_y);
1442         intensity       = s_intensity;
1443         underline       = s_underline;
1444         blink           = s_blink;
1445         reverse         = s_reverse;
1446         charset         = s_charset;
1447         color           = s_color;
1448         G0_charset      = saved_G0;
1449         G1_charset      = saved_G1;
1450         translate       = set_translate(charset ? G1_charset : G0_charset,currcons);
1451         update_attr(currcons);
1452         need_wrap = 0;
1453 }
1454
1455 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
1456         EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
1457         ESpalette };
1458
1459 /* console_sem is held (except via vc_init()) */
1460 static void reset_terminal(int currcons, int do_clear)
1461 {
1462         top             = 0;
1463         bottom          = video_num_lines;
1464         vc_state        = ESnormal;
1465         ques            = 0;
1466         translate       = set_translate(LAT1_MAP,currcons);
1467         G0_charset      = LAT1_MAP;
1468         G1_charset      = GRAF_MAP;
1469         charset         = 0;
1470         need_wrap       = 0;
1471         report_mouse    = 0;
1472         utf             = 0;
1473         utf_count       = 0;
1474
1475         disp_ctrl       = 0;
1476         toggle_meta     = 0;
1477
1478         decscnm         = 0;
1479         decom           = 0;
1480         decawm          = 1;
1481         deccm           = 1;
1482         decim           = 0;
1483
1484         set_kbd(decarm);
1485         clr_kbd(decckm);
1486         clr_kbd(kbdapplic);
1487         clr_kbd(lnm);
1488         kbd_table[currcons].lockstate = 0;
1489         kbd_table[currcons].slockstate = 0;
1490         kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1491         kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1492         /* do not do set_leds here because this causes an endless tasklet loop
1493            when the keyboard hasn't been initialized yet */
1494
1495         cursor_type = CUR_DEFAULT;
1496         complement_mask = s_complement_mask;
1497
1498         default_attr(currcons);
1499         update_attr(currcons);
1500
1501         tab_stop[0]     = 0x01010100;
1502         tab_stop[1]     =
1503         tab_stop[2]     =
1504         tab_stop[3]     =
1505         tab_stop[4]     = 0x01010101;
1506
1507         bell_pitch = DEFAULT_BELL_PITCH;
1508         bell_duration = DEFAULT_BELL_DURATION;
1509
1510         gotoxy(currcons,0,0);
1511         save_cur(currcons);
1512         if (do_clear)
1513             csi_J(currcons,2);
1514 }
1515
1516 /* console_sem is held */
1517 static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
1518 {
1519         /*
1520          *  Control characters can be used in the _middle_
1521          *  of an escape sequence.
1522          */
1523         switch (c) {
1524         case 0:
1525                 return;
1526         case 7:
1527                 if (bell_duration)
1528                         kd_mksound(bell_pitch, bell_duration);
1529                 return;
1530         case 8:
1531                 bs(currcons);
1532                 return;
1533         case 9:
1534                 pos -= (x << 1);
1535                 while (x < video_num_columns - 1) {
1536                         x++;
1537                         if (tab_stop[x >> 5] & (1 << (x & 31)))
1538                                 break;
1539                 }
1540                 pos += (x << 1);
1541                 return;
1542         case 10: case 11: case 12:
1543                 lf(currcons);
1544                 if (!is_kbd(lnm))
1545                         return;
1546         case 13:
1547                 cr(currcons);
1548                 return;
1549         case 14:
1550                 charset = 1;
1551                 translate = set_translate(G1_charset,currcons);
1552                 disp_ctrl = 1;
1553                 return;
1554         case 15:
1555                 charset = 0;
1556                 translate = set_translate(G0_charset,currcons);
1557                 disp_ctrl = 0;
1558                 return;
1559         case 24: case 26:
1560                 vc_state = ESnormal;
1561                 return;
1562         case 27:
1563                 vc_state = ESesc;
1564                 return;
1565         case 127:
1566                 del(currcons);
1567                 return;
1568         case 128+27:
1569                 vc_state = ESsquare;
1570                 return;
1571         }
1572         switch(vc_state) {
1573         case ESesc:
1574                 vc_state = ESnormal;
1575                 switch (c) {
1576                 case '[':
1577                         vc_state = ESsquare;
1578                         return;
1579                 case ']':
1580                         vc_state = ESnonstd;
1581                         return;
1582                 case '%':
1583                         vc_state = ESpercent;
1584                         return;
1585                 case 'E':
1586                         cr(currcons);
1587                         lf(currcons);
1588                         return;
1589                 case 'M':
1590                         ri(currcons);
1591                         return;
1592                 case 'D':
1593                         lf(currcons);
1594                         return;
1595                 case 'H':
1596                         tab_stop[x >> 5] |= (1 << (x & 31));
1597                         return;
1598                 case 'Z':
1599                         respond_ID(tty);
1600                         return;
1601                 case '7':
1602                         save_cur(currcons);
1603                         return;
1604                 case '8':
1605                         restore_cur(currcons);
1606                         return;
1607                 case '(':
1608                         vc_state = ESsetG0;
1609                         return;
1610                 case ')':
1611                         vc_state = ESsetG1;
1612                         return;
1613                 case '#':
1614                         vc_state = EShash;
1615                         return;
1616                 case 'c':
1617                         reset_terminal(currcons,1);
1618                         return;
1619                 case '>':  /* Numeric keypad */
1620                         clr_kbd(kbdapplic);
1621                         return;
1622                 case '=':  /* Appl. keypad */
1623                         set_kbd(kbdapplic);
1624                         return;
1625                 }
1626                 return;
1627         case ESnonstd:
1628                 if (c=='P') {   /* palette escape sequence */
1629                         for (npar=0; npar<NPAR; npar++)
1630                                 par[npar] = 0 ;
1631                         npar = 0 ;
1632                         vc_state = ESpalette;
1633                         return;
1634                 } else if (c=='R') {   /* reset palette */
1635                         reset_palette(currcons);
1636                         vc_state = ESnormal;
1637                 } else
1638                         vc_state = ESnormal;
1639                 return;
1640         case ESpalette:
1641                 if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
1642                         par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
1643                         if (npar==7) {
1644                                 int i = par[0]*3, j = 1;
1645                                 palette[i] = 16*par[j++];
1646                                 palette[i++] += par[j++];
1647                                 palette[i] = 16*par[j++];
1648                                 palette[i++] += par[j++];
1649                                 palette[i] = 16*par[j++];
1650                                 palette[i] += par[j];
1651                                 set_palette(currcons);
1652                                 vc_state = ESnormal;
1653                         }
1654                 } else
1655                         vc_state = ESnormal;
1656                 return;
1657         case ESsquare:
1658                 for(npar = 0 ; npar < NPAR ; npar++)
1659                         par[npar] = 0;
1660                 npar = 0;
1661                 vc_state = ESgetpars;
1662                 if (c == '[') { /* Function key */
1663                         vc_state=ESfunckey;
1664                         return;
1665                 }
1666                 ques = (c=='?');
1667                 if (ques)
1668                         return;
1669         case ESgetpars:
1670                 if (c==';' && npar<NPAR-1) {
1671                         npar++;
1672                         return;
1673                 } else if (c>='0' && c<='9') {
1674                         par[npar] *= 10;
1675                         par[npar] += c-'0';
1676                         return;
1677                 } else vc_state=ESgotpars;
1678         case ESgotpars:
1679                 vc_state = ESnormal;
1680                 switch(c) {
1681                 case 'h':
1682                         set_mode(currcons,1);
1683                         return;
1684                 case 'l':
1685                         set_mode(currcons,0);
1686                         return;
1687                 case 'c':
1688                         if (ques) {
1689                                 if (par[0])
1690                                         cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
1691                                 else
1692                                         cursor_type = CUR_DEFAULT;
1693                                 return;
1694                         }
1695                         break;
1696                 case 'm':
1697                         if (ques) {
1698                                 clear_selection();
1699                                 if (par[0])
1700                                         complement_mask = par[0]<<8 | par[1];
1701                                 else
1702                                         complement_mask = s_complement_mask;
1703                                 return;
1704                         }
1705                         break;
1706                 case 'n':
1707                         if (!ques) {
1708                                 if (par[0] == 5)
1709                                         status_report(tty);
1710                                 else if (par[0] == 6)
1711                                         cursor_report(currcons,tty);
1712                         }
1713                         return;
1714                 }
1715                 if (ques) {
1716                         ques = 0;
1717                         return;
1718                 }
1719                 switch(c) {
1720                 case 'G': case '`':
1721                         if (par[0]) par[0]--;
1722                         gotoxy(currcons,par[0],y);
1723                         return;
1724                 case 'A':
1725                         if (!par[0]) par[0]++;
1726                         gotoxy(currcons,x,y-par[0]);
1727                         return;
1728                 case 'B': case 'e':
1729                         if (!par[0]) par[0]++;
1730                         gotoxy(currcons,x,y+par[0]);
1731                         return;
1732                 case 'C': case 'a':
1733                         if (!par[0]) par[0]++;
1734                         gotoxy(currcons,x+par[0],y);
1735                         return;
1736                 case 'D':
1737                         if (!par[0]) par[0]++;
1738                         gotoxy(currcons,x-par[0],y);
1739                         return;
1740                 case 'E':
1741                         if (!par[0]) par[0]++;
1742                         gotoxy(currcons,0,y+par[0]);
1743                         return;
1744                 case 'F':
1745                         if (!par[0]) par[0]++;
1746                         gotoxy(currcons,0,y-par[0]);
1747                         return;
1748                 case 'd':
1749                         if (par[0]) par[0]--;
1750                         gotoxay(currcons,x,par[0]);
1751                         return;
1752                 case 'H': case 'f':
1753                         if (par[0]) par[0]--;
1754                         if (par[1]) par[1]--;
1755                         gotoxay(currcons,par[1],par[0]);
1756                         return;
1757                 case 'J':
1758                         csi_J(currcons,par[0]);
1759                         return;
1760                 case 'K':
1761                         csi_K(currcons,par[0]);
1762                         return;
1763                 case 'L':
1764                         csi_L(currcons,par[0]);
1765                         return;
1766                 case 'M':
1767                         csi_M(currcons,par[0]);
1768                         return;
1769                 case 'P':
1770                         csi_P(currcons,par[0]);
1771                         return;
1772                 case 'c':
1773                         if (!par[0])
1774                                 respond_ID(tty);
1775                         return;
1776                 case 'g':
1777                         if (!par[0])
1778                                 tab_stop[x >> 5] &= ~(1 << (x & 31));
1779                         else if (par[0] == 3) {
1780                                 tab_stop[0] =
1781                                         tab_stop[1] =
1782                                         tab_stop[2] =
1783                                         tab_stop[3] =
1784                                         tab_stop[4] = 0;
1785                         }
1786                         return;
1787                 case 'm':
1788                         csi_m(currcons);
1789                         return;
1790                 case 'q': /* DECLL - but only 3 leds */
1791                         /* map 0,1,2,3 to 0,1,2,4 */
1792                         if (par[0] < 4)
1793                                 setledstate(kbd_table + currcons,
1794                                             (par[0] < 3) ? par[0] : 4);
1795                         return;
1796                 case 'r':
1797                         if (!par[0])
1798                                 par[0]++;
1799                         if (!par[1])
1800                                 par[1] = video_num_lines;
1801                         /* Minimum allowed region is 2 lines */
1802                         if (par[0] < par[1] &&
1803                             par[1] <= video_num_lines) {
1804                                 top=par[0]-1;
1805                                 bottom=par[1];
1806                                 gotoxay(currcons,0,0);
1807                         }
1808                         return;
1809                 case 's':
1810                         save_cur(currcons);
1811                         return;
1812                 case 'u':
1813                         restore_cur(currcons);
1814                         return;
1815                 case 'X':
1816                         csi_X(currcons, par[0]);
1817                         return;
1818                 case '@':
1819                         csi_at(currcons,par[0]);
1820                         return;
1821                 case ']': /* setterm functions */
1822                         setterm_command(currcons);
1823                         return;
1824                 }
1825                 return;
1826         case ESpercent:
1827                 vc_state = ESnormal;
1828                 switch (c) {
1829                 case '@':  /* defined in ISO 2022 */
1830                         utf = 0;
1831                         return;
1832                 case 'G':  /* prelim official escape code */
1833                 case '8':  /* retained for compatibility */
1834                         utf = 1;
1835                         return;
1836                 }
1837                 return;
1838         case ESfunckey:
1839                 vc_state = ESnormal;
1840                 return;
1841         case EShash:
1842                 vc_state = ESnormal;
1843                 if (c == '8') {
1844                         /* DEC screen alignment test. kludge :-) */
1845                         video_erase_char =
1846                                 (video_erase_char & 0xff00) | 'E';
1847                         csi_J(currcons, 2);
1848                         video_erase_char =
1849                                 (video_erase_char & 0xff00) | ' ';
1850                         do_update_region(currcons, origin, screenbuf_size/2);
1851                 }
1852                 return;
1853         case ESsetG0:
1854                 if (c == '0')
1855                         G0_charset = GRAF_MAP;
1856                 else if (c == 'B')
1857                         G0_charset = LAT1_MAP;
1858                 else if (c == 'U')
1859                         G0_charset = IBMPC_MAP;
1860                 else if (c == 'K')
1861                         G0_charset = USER_MAP;
1862                 if (charset == 0)
1863                         translate = set_translate(G0_charset,currcons);
1864                 vc_state = ESnormal;
1865                 return;
1866         case ESsetG1:
1867                 if (c == '0')
1868                         G1_charset = GRAF_MAP;
1869                 else if (c == 'B')
1870                         G1_charset = LAT1_MAP;
1871                 else if (c == 'U')
1872                         G1_charset = IBMPC_MAP;
1873                 else if (c == 'K')
1874                         G1_charset = USER_MAP;
1875                 if (charset == 1)
1876                         translate = set_translate(G1_charset,currcons);
1877                 vc_state = ESnormal;
1878                 return;
1879         default:
1880                 vc_state = ESnormal;
1881         }
1882 }
1883
1884 /* This is a temporary buffer used to prepare a tty console write
1885  * so that we can easily avoid touching user space while holding the
1886  * console spinlock.  It is allocated in con_init and is shared by
1887  * this code and the vc_screen read/write tty calls.
1888  *
1889  * We have to allocate this statically in the kernel data section
1890  * since console_init (and thus con_init) are called before any
1891  * kernel memory allocation is available.
1892  */
1893 char con_buf[CON_BUF_SIZE];
1894 DECLARE_MUTEX(con_buf_sem);
1895
1896 /* acquires console_sem */
1897 static int do_con_write(struct tty_struct *tty, int from_user,
1898                         const unsigned char *buf, int count)
1899 {
1900 #ifdef VT_BUF_VRAM_ONLY
1901 #define FLUSH do { } while(0);
1902 #else
1903 #define FLUSH if (draw_x >= 0) { \
1904         sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
1905         draw_x = -1; \
1906         }
1907 #endif
1908
1909         int c, tc, ok, n = 0, draw_x = -1;
1910         unsigned int currcons;
1911         unsigned long draw_from = 0, draw_to = 0;
1912         struct vt_struct *vt;
1913         u16 himask, charmask;
1914         const unsigned char *orig_buf = NULL;
1915         int orig_count;
1916
1917         if (in_interrupt())
1918                 return count;
1919
1920         might_sleep();
1921
1922         acquire_console_sem();
1923         vt = tty->driver_data;
1924         if (vt == NULL) {
1925                 printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
1926                 release_console_sem();
1927                 return 0;
1928         }
1929
1930         currcons = vt->vc_num;
1931         if (!vc_cons_allocated(currcons)) {
1932             /* could this happen? */
1933             static int error = 0;
1934             if (!error) {
1935                 error = 1;
1936                 printk("con_write: tty %d not allocated\n", currcons+1);
1937             }
1938             release_console_sem();
1939             return 0;
1940         }
1941         release_console_sem();
1942
1943         orig_buf = buf;
1944         orig_count = count;
1945
1946         if (from_user) {
1947
1948                 down(&con_buf_sem);
1949
1950 again:
1951                 if (count > CON_BUF_SIZE)
1952                         count = CON_BUF_SIZE;
1953                 console_conditional_schedule();
1954                 if (copy_from_user(con_buf, buf, count)) {
1955                         n = 0; /* ?? are error codes legal here ?? */
1956                         goto out;
1957                 }
1958
1959                 buf = con_buf;
1960         }
1961
1962         /* At this point 'buf' is guaranteed to be a kernel buffer
1963          * and therefore no access to userspace (and therefore sleeping)
1964          * will be needed.  The con_buf_sem serializes all tty based
1965          * console rendering and vcs write/read operations.  We hold
1966          * the console spinlock during the entire write.
1967          */
1968
1969         acquire_console_sem();
1970
1971         vt = tty->driver_data;
1972         if (vt == NULL) {
1973                 printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n");
1974                 release_console_sem();
1975                 goto out;
1976         }
1977
1978         himask = hi_font_mask;
1979         charmask = himask ? 0x1ff : 0xff;
1980
1981         /* undraw cursor first */
1982         if (IS_FG)
1983                 hide_cursor(currcons);
1984
1985         while (!tty->stopped && count) {
1986                 int orig = *buf;
1987                 c = orig;
1988                 buf++;
1989                 n++;
1990                 count--;
1991
1992                 /* Do no translation at all in control states */
1993                 if (vc_state != ESnormal) {
1994                         tc = c;
1995                 } else if (utf) {
1996                     /* Combine UTF-8 into Unicode */
1997                     /* Incomplete characters silently ignored */
1998                     if(c > 0x7f) {
1999                         if (utf_count > 0 && (c & 0xc0) == 0x80) {
2000                                 utf_char = (utf_char << 6) | (c & 0x3f);
2001                                 utf_count--;
2002                                 if (utf_count == 0)
2003                                     tc = c = utf_char;
2004                                 else continue;
2005                         } else {
2006                                 if ((c & 0xe0) == 0xc0) {
2007                                     utf_count = 1;
2008                                     utf_char = (c & 0x1f);
2009                                 } else if ((c & 0xf0) == 0xe0) {
2010                                     utf_count = 2;
2011                                     utf_char = (c & 0x0f);
2012                                 } else if ((c & 0xf8) == 0xf0) {
2013                                     utf_count = 3;
2014                                     utf_char = (c & 0x07);
2015                                 } else if ((c & 0xfc) == 0xf8) {
2016                                     utf_count = 4;
2017                                     utf_char = (c & 0x03);
2018                                 } else if ((c & 0xfe) == 0xfc) {
2019                                     utf_count = 5;
2020                                     utf_char = (c & 0x01);
2021                                 } else
2022                                     utf_count = 0;
2023                                 continue;
2024                               }
2025                     } else {
2026                       tc = c;
2027                       utf_count = 0;
2028                     }
2029                 } else {        /* no utf */
2030                   tc = translate[toggle_meta ? (c|0x80) : c];
2031                 }
2032
2033                 /* If the original code was a control character we
2034                  * only allow a glyph to be displayed if the code is
2035                  * not normally used (such as for cursor movement) or
2036                  * if the disp_ctrl mode has been explicitly enabled.
2037                  * Certain characters (as given by the CTRL_ALWAYS
2038                  * bitmap) are always displayed as control characters,
2039                  * as the console would be pretty useless without
2040                  * them; to display an arbitrary font position use the
2041                  * direct-to-font zone in UTF-8 mode.
2042                  */
2043                 ok = tc && (c >= 32 ||
2044                             (!utf && !(((disp_ctrl ? CTRL_ALWAYS
2045                                          : CTRL_ACTION) >> c) & 1)))
2046                         && (c != 127 || disp_ctrl)
2047                         && (c != 128+27);
2048
2049                 if (vc_state == ESnormal && ok) {
2050                         /* Now try to find out how to display it */
2051                         tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
2052                         if ( tc == -4 ) {
2053                                 /* If we got -4 (not found) then see if we have
2054                                    defined a replacement character (U+FFFD) */
2055                                 tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
2056
2057                                 /* One reason for the -4 can be that we just
2058                                    did a clear_unimap();
2059                                    try at least to show something. */
2060                                 if (tc == -4)
2061                                      tc = c;
2062                         } else if ( tc == -3 ) {
2063                                 /* Bad hash table -- hope for the best */
2064                                 tc = c;
2065                         }
2066                         if (tc & ~charmask)
2067                                 continue; /* Conversion failed */
2068
2069                         if (need_wrap || decim)
2070                                 FLUSH
2071                         if (need_wrap) {
2072                                 cr(currcons);
2073                                 lf(currcons);
2074                         }
2075                         if (decim)
2076                                 insert_char(currcons, 1);
2077                         scr_writew(himask ?
2078                                      ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
2079                                      (attr << 8) + tc,
2080                                    (u16 *) pos);
2081                         if (DO_UPDATE && draw_x < 0) {
2082                                 draw_x = x;
2083                                 draw_from = pos;
2084                         }
2085                         if (x == video_num_columns - 1) {
2086                                 need_wrap = decawm;
2087                                 draw_to = pos+2;
2088                         } else {
2089                                 x++;
2090                                 draw_to = (pos+=2);
2091                         }
2092                         continue;
2093                 }
2094                 FLUSH
2095                 do_con_trol(tty, currcons, orig);
2096         }
2097         FLUSH
2098         console_conditional_schedule();
2099         release_console_sem();
2100
2101 out:
2102         if (from_user) {
2103                 /* If the user requested something larger than
2104                  * the CON_BUF_SIZE, and the tty is not stopped,
2105                  * keep going.
2106                  */
2107                 if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
2108                         orig_count -= CON_BUF_SIZE;
2109                         orig_buf += CON_BUF_SIZE;
2110                         count = orig_count;
2111                         buf = orig_buf;
2112                         goto again;
2113                 }
2114
2115                 up(&con_buf_sem);
2116         }
2117
2118         return n;
2119 #undef FLUSH
2120 }
2121
2122 /*
2123  * This is the console switching callback.
2124  *
2125  * Doing console switching in a process context allows
2126  * us to do the switches asynchronously (needed when we want
2127  * to switch due to a keyboard interrupt).  Synchronization
2128  * with other console code and prevention of re-entrancy is
2129  * ensured with console_sem.
2130  */
2131 static void console_callback(void *ignored)
2132 {
2133         acquire_console_sem();
2134
2135         if (want_console >= 0) {
2136                 if (want_console != fg_console &&
2137                     vc_cons_allocated(want_console)) {
2138                         hide_cursor(fg_console);
2139                         change_console(want_console);
2140                         /* we only changed when the console had already
2141                            been allocated - a new console is not created
2142                            in an interrupt routine */
2143                 }
2144                 want_console = -1;
2145         }
2146         if (do_poke_blanked_console) { /* do not unblank for a LED change */
2147                 do_poke_blanked_console = 0;
2148                 poke_blanked_console();
2149         }
2150         if (scrollback_delta) {
2151                 int currcons = fg_console;
2152                 clear_selection();
2153                 if (vcmode == KD_TEXT)
2154                         sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
2155                 scrollback_delta = 0;
2156         }
2157         if (blank_timer_expired) {
2158                 do_blank_screen(0);
2159                 blank_timer_expired = 0;
2160         }
2161
2162         release_console_sem();
2163 }
2164
2165 void set_console(int nr)
2166 {
2167         want_console = nr;
2168         schedule_console_callback();
2169 }
2170
2171 struct tty_driver *console_driver;
2172
2173 #ifdef CONFIG_VT_CONSOLE
2174
2175 /*
2176  *      Console on virtual terminal
2177  *
2178  * The console must be locked when we get here.
2179  */
2180
2181 void vt_console_print(struct console *co, const char *b, unsigned count)
2182 {
2183         int currcons = fg_console;
2184         unsigned char c;
2185         static unsigned long printing;
2186         const ushort *start;
2187         ushort cnt = 0;
2188         ushort myx;
2189
2190         /* console busy or not yet initialized */
2191         if (!printable || test_and_set_bit(0, &printing))
2192                 return;
2193
2194         pm_access(pm_con);
2195
2196         if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
2197                 currcons = kmsg_redirect - 1;
2198
2199         /* read `x' only after setting currcons properly (otherwise
2200            the `x' macro will read the x of the foreground console). */
2201         myx = x;
2202
2203         if (!vc_cons_allocated(currcons)) {
2204                 /* impossible */
2205                 /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
2206                 goto quit;
2207         }
2208
2209         if (vcmode != KD_TEXT)
2210                 goto quit;
2211
2212         /* undraw cursor first */
2213         if (IS_FG)
2214                 hide_cursor(currcons);
2215
2216         start = (ushort *)pos;
2217
2218         /* Contrived structure to try to emulate original need_wrap behaviour
2219          * Problems caused when we have need_wrap set on '\n' character */
2220         while (count--) {
2221                 c = *b++;
2222                 if (c == 10 || c == 13 || c == 8 || need_wrap) {
2223                         if (cnt > 0) {
2224                                 if (IS_VISIBLE)
2225                                         sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2226                                 x += cnt;
2227                                 if (need_wrap)
2228                                         x--;
2229                                 cnt = 0;
2230                         }
2231                         if (c == 8) {           /* backspace */
2232                                 bs(currcons);
2233                                 start = (ushort *)pos;
2234                                 myx = x;
2235                                 continue;
2236                         }
2237                         if (c != 13)
2238                                 lf(currcons);
2239                         cr(currcons);
2240                         start = (ushort *)pos;
2241                         myx = x;
2242                         if (c == 10 || c == 13)
2243                                 continue;
2244                 }
2245                 scr_writew((attr << 8) + c, (unsigned short *) pos);
2246                 cnt++;
2247                 if (myx == video_num_columns - 1) {
2248                         need_wrap = 1;
2249                         continue;
2250                 }
2251                 pos+=2;
2252                 myx++;
2253         }
2254         if (cnt > 0) {
2255                 if (IS_VISIBLE)
2256                         sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2257                 x += cnt;
2258                 if (x == video_num_columns) {
2259                         x--;
2260                         need_wrap = 1;
2261                 }
2262         }
2263         set_cursor(currcons);
2264
2265         if (!oops_in_progress)
2266                 poke_blanked_console();
2267
2268 quit:
2269         clear_bit(0, &printing);
2270 }
2271
2272 static struct tty_driver *vt_console_device(struct console *c, int *index)
2273 {
2274         *index = c->index ? c->index-1 : fg_console;
2275         return console_driver;
2276 }
2277
2278 struct console vt_console_driver = {
2279         .name           = "tty",
2280         .write          = vt_console_print,
2281         .device         = vt_console_device,
2282         .unblank        = unblank_screen,
2283         .flags          = CON_PRINTBUFFER,
2284         .index          = -1,
2285 };
2286 #endif
2287
2288 /*
2289  *      Handling of Linux-specific VC ioctls
2290  */
2291
2292 /*
2293  * Generally a bit racy with respect to console_sem().
2294  *
2295  * There are some functions which don't need it.
2296  *
2297  * There are some functions which can sleep for arbitrary periods
2298  * (paste_selection) but we don't need the lock there anyway.
2299  *
2300  * set_selection has locking, and definitely needs it
2301  */
2302
2303 int tioclinux(struct tty_struct *tty, unsigned long arg)
2304 {
2305         char type, data;
2306         char __user *p = (char __user *)arg;
2307         int lines;
2308         int ret;
2309
2310         if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE)
2311                 return -EINVAL;
2312         if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
2313                 return -EPERM;
2314         if (get_user(type, p))
2315                 return -EFAULT;
2316         ret = 0;
2317         switch (type)
2318         {
2319                 case TIOCL_SETSEL:
2320                         acquire_console_sem();
2321                         ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
2322                         release_console_sem();
2323                         break;
2324                 case TIOCL_PASTESEL:
2325                         ret = paste_selection(tty);
2326                         break;
2327                 case TIOCL_UNBLANKSCREEN:
2328                         unblank_screen();
2329                         break;
2330                 case TIOCL_SELLOADLUT:
2331                         ret = sel_loadlut(p);
2332                         break;
2333                 case TIOCL_GETSHIFTSTATE:
2334                         
2335         /*
2336          * Make it possible to react to Shift+Mousebutton.
2337          * Note that 'shift_state' is an undocumented
2338          * kernel-internal variable; programs not closely
2339          * related to the kernel should not use this.
2340          */
2341                         data = shift_state;
2342                         ret = __put_user(data, p);
2343                         break;
2344                 case TIOCL_GETMOUSEREPORTING:
2345                         data = mouse_reporting();
2346                         ret = __put_user(data, p);
2347                         break;
2348                 case TIOCL_SETVESABLANK:
2349                         set_vesa_blanking(p);
2350                         break;
2351                 case TIOCL_SETKMSGREDIRECT:
2352                         if (!capable(CAP_SYS_ADMIN)) {
2353                                 ret = -EPERM;
2354                         } else {
2355                                 if (get_user(data, p+1))
2356                                         ret = -EFAULT;
2357                                 else
2358                                         kmsg_redirect = data;
2359                         }
2360                         break;
2361                 case TIOCL_GETFGCONSOLE:
2362                         ret = fg_console;
2363                         break;
2364                 case TIOCL_SCROLLCONSOLE:
2365                         if (get_user(lines, (s32 __user *)(p+4))) {
2366                                 ret = -EFAULT;
2367                         } else {
2368                                 scrollfront(lines);
2369                                 ret = 0;
2370                         }
2371                         break;
2372                 case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
2373                         ignore_poke = 1;
2374                         do_blank_screen(0);
2375                         break;
2376                 case TIOCL_BLANKEDSCREEN:
2377                         ret = console_blanked;
2378                         break;
2379                 default:
2380                         ret = -EINVAL;
2381                         break;
2382         }
2383         return ret;
2384 }
2385
2386 /*
2387  * /dev/ttyN handling
2388  */
2389
2390 static int con_write(struct tty_struct *tty, int from_user,
2391                      const unsigned char *buf, int count)
2392 {
2393         int     retval;
2394
2395         pm_access(pm_con);
2396         retval = do_con_write(tty, from_user, buf, count);
2397         con_flush_chars(tty);
2398
2399         return retval;
2400 }
2401
2402 static void con_put_char(struct tty_struct *tty, unsigned char ch)
2403 {
2404         if (in_interrupt())
2405                 return; /* n_r3964 calls put_char() from interrupt context */
2406         pm_access(pm_con);
2407         do_con_write(tty, 0, &ch, 1);
2408 }
2409
2410 static int con_write_room(struct tty_struct *tty)
2411 {
2412         if (tty->stopped)
2413                 return 0;
2414         return 4096;            /* No limit, really; we're not buffering */
2415 }
2416
2417 static int con_chars_in_buffer(struct tty_struct *tty)
2418 {
2419         return 0;               /* we're not buffering */
2420 }
2421
2422 /*
2423  * con_throttle and con_unthrottle are only used for
2424  * paste_selection(), which has to stuff in a large number of
2425  * characters...
2426  */
2427 static void con_throttle(struct tty_struct *tty)
2428 {
2429 }
2430
2431 static void con_unthrottle(struct tty_struct *tty)
2432 {
2433         struct vt_struct *vt = tty->driver_data;
2434
2435         wake_up_interruptible(&vt->paste_wait);
2436 }
2437
2438 /*
2439  * Turn the Scroll-Lock LED on when the tty is stopped
2440  */
2441 static void con_stop(struct tty_struct *tty)
2442 {
2443         int console_num;
2444         if (!tty)
2445                 return;
2446         console_num = tty->index;
2447         if (!vc_cons_allocated(console_num))
2448                 return;
2449         set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2450         set_leds();
2451 }
2452
2453 /*
2454  * Turn the Scroll-Lock LED off when the console is started
2455  */
2456 static void con_start(struct tty_struct *tty)
2457 {
2458         int console_num;
2459         if (!tty)
2460                 return;
2461         console_num = tty->index;
2462         if (!vc_cons_allocated(console_num))
2463                 return;
2464         clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2465         set_leds();
2466 }
2467
2468 static void con_flush_chars(struct tty_struct *tty)
2469 {
2470         struct vt_struct *vt;
2471
2472         if (in_interrupt())     /* from flush_to_ldisc */
2473                 return;
2474
2475         pm_access(pm_con);
2476         
2477         /* if we race with con_close(), vt may be null */
2478         acquire_console_sem();
2479         vt = tty->driver_data;
2480         if (vt)
2481                 set_cursor(vt->vc_num);
2482         release_console_sem();
2483 }
2484
2485 /*
2486  * Allocate the console screen memory.
2487  */
2488 static int con_open(struct tty_struct *tty, struct file *filp)
2489 {
2490         unsigned int currcons = tty->index;
2491         int ret = 0;
2492
2493         acquire_console_sem();
2494         if (tty->count == 1) {
2495                 ret = vc_allocate(currcons);
2496                 if (ret == 0) {
2497                         vt_cons[currcons]->vc_num = currcons;
2498                         tty->driver_data = vt_cons[currcons];
2499                         vc_cons[currcons].d->vc_tty = tty;
2500
2501                         if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2502                                 tty->winsize.ws_row = video_num_lines;
2503                                 tty->winsize.ws_col = video_num_columns;
2504                         }
2505                         release_console_sem();
2506                         vcs_make_devfs(tty);
2507                         return ret;
2508                 }
2509         }
2510         release_console_sem();
2511         return ret;
2512 }
2513
2514 /*
2515  * We take tty_sem in here to prevent another thread from coming in via init_dev
2516  * and taking a ref against the tty while we're in the process of forgetting
2517  * about it and cleaning things up.
2518  *
2519  * This is because vcs_remove_devfs() can sleep and will drop the BKL.
2520  */
2521 static void con_close(struct tty_struct *tty, struct file *filp)
2522 {
2523         down(&tty_sem);
2524         acquire_console_sem();
2525         if (tty && tty->count == 1) {
2526                 struct vt_struct *vt;
2527
2528                 vt = tty->driver_data;
2529                 if (vt)
2530                         vc_cons[vt->vc_num].d->vc_tty = NULL;
2531                 tty->driver_data = NULL;
2532                 release_console_sem();
2533                 vcs_remove_devfs(tty);
2534                 up(&tty_sem);
2535                 /*
2536                  * tty_sem is released, but we still hold BKL, so there is
2537                  * still exclusion against init_dev()
2538                  */
2539                 return;
2540         }
2541         release_console_sem();
2542         up(&tty_sem);
2543 }
2544
2545 static void vc_init(unsigned int currcons, unsigned int rows,
2546                         unsigned int cols, int do_clear)
2547 {
2548         int j, k ;
2549
2550         video_num_columns = cols;
2551         video_num_lines = rows;
2552         video_size_row = cols<<1;
2553         screenbuf_size = video_num_lines * video_size_row;
2554
2555         set_origin(currcons);
2556         pos = origin;
2557         reset_vc(currcons);
2558         for (j=k=0; j<16; j++) {
2559                 vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
2560                 vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
2561                 vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
2562         }
2563         def_color       = 0x07;   /* white */
2564         ulcolor         = 0x0f;   /* bold white */
2565         halfcolor       = 0x08;   /* grey */
2566         init_waitqueue_head(&vt_cons[currcons]->paste_wait);
2567         reset_terminal(currcons, do_clear);
2568 }
2569
2570 /*
2571  * This routine initializes console interrupts, and does nothing
2572  * else. If you want the screen to clear, call tty_write with
2573  * the appropriate escape-sequence.
2574  */
2575
2576 static int __init con_init(void)
2577 {
2578         const char *display_desc = NULL;
2579         unsigned int currcons = 0;
2580
2581         acquire_console_sem();
2582
2583         if (conswitchp)
2584                 display_desc = conswitchp->con_startup();
2585         if (!display_desc) {
2586                 fg_console = 0;
2587                 release_console_sem();
2588                 return 0;
2589         }
2590
2591         init_timer(&console_timer);
2592         console_timer.function = blank_screen_t;
2593         if (blankinterval) {
2594                 blank_state = blank_normal_wait;
2595                 mod_timer(&console_timer, jiffies + blankinterval);
2596         }
2597
2598         /*
2599          * kmalloc is not running yet - we use the bootmem allocator.
2600          */
2601         for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2602                 vc_cons[currcons].d = (struct vc_data *)
2603                                 alloc_bootmem(sizeof(struct vc_data));
2604                 vt_cons[currcons] = (struct vt_struct *)
2605                                 alloc_bootmem(sizeof(struct vt_struct));
2606                 visual_init(currcons, 1);
2607                 screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
2608                 kmalloced = 0;
2609                 vc_init(currcons, video_num_lines, video_num_columns, 
2610                         currcons || !sw->con_save_screen);
2611         }
2612         currcons = fg_console = 0;
2613         master_display_fg = vc_cons[currcons].d;
2614         set_origin(currcons);
2615         save_screen(currcons);
2616         gotoxy(currcons,x,y);
2617         csi_J(currcons, 0);
2618         update_screen(fg_console);
2619         printk("Console: %s %s %dx%d",
2620                 can_do_color ? "colour" : "mono",
2621                 display_desc, video_num_columns, video_num_lines);
2622         printable = 1;
2623         printk("\n");
2624
2625         release_console_sem();
2626
2627 #ifdef CONFIG_VT_CONSOLE
2628         register_console(&vt_console_driver);
2629 #endif
2630         return 0;
2631 }
2632 console_initcall(con_init);
2633
2634 static struct tty_operations con_ops = {
2635         .open = con_open,
2636         .close = con_close,
2637         .write = con_write,
2638         .write_room = con_write_room,
2639         .put_char = con_put_char,
2640         .flush_chars = con_flush_chars,
2641         .chars_in_buffer = con_chars_in_buffer,
2642         .ioctl = vt_ioctl,
2643         .stop = con_stop,
2644         .start = con_start,
2645         .throttle = con_throttle,
2646         .unthrottle = con_unthrottle,
2647 };
2648
2649 int __init vty_init(void)
2650 {
2651         vcs_init();
2652
2653         console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
2654         if (!console_driver)
2655                 panic("Couldn't allocate console driver\n");
2656         console_driver->owner = THIS_MODULE;
2657         console_driver->devfs_name = "vc/";
2658         console_driver->name = "tty";
2659         console_driver->name_base = 1;
2660         console_driver->major = TTY_MAJOR;
2661         console_driver->minor_start = 1;
2662         console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
2663         console_driver->init_termios = tty_std_termios;
2664         console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2665         tty_set_operations(console_driver, &con_ops);
2666         if (tty_register_driver(console_driver))
2667                 panic("Couldn't register console driver\n");
2668
2669         kbd_init();
2670         console_map_init();
2671 #ifdef CONFIG_PROM_CONSOLE
2672         prom_con_init();
2673 #endif
2674 #ifdef CONFIG_MDA_CONSOLE
2675         mda_console_init();
2676 #endif
2677         return 0;
2678 }
2679
2680 #ifndef VT_SINGLE_DRIVER
2681
2682 /*
2683  *      If we support more console drivers, this function is used
2684  *      when a driver wants to take over some existing consoles
2685  *      and become default driver for newly opened ones.
2686  */
2687
2688 int take_over_console(const struct consw *csw, int first, int last, int deflt)
2689 {
2690         int i, j = -1;
2691         const char *desc;
2692         struct module *owner;
2693
2694         owner = csw->owner;
2695         if (!try_module_get(owner))
2696                 return -ENODEV;
2697
2698         acquire_console_sem();
2699
2700         desc = csw->con_startup();
2701         if (!desc) {
2702                 release_console_sem();
2703                 module_put(owner);
2704                 return -ENODEV;
2705         }
2706         if (deflt) {
2707                 if (conswitchp)
2708                         module_put(conswitchp->owner);
2709                 __module_get(owner);
2710                 conswitchp = csw;
2711         }
2712
2713         for (i = first; i <= last; i++) {
2714                 int old_was_color;
2715                 int currcons = i;
2716
2717                 if (con_driver_map[i])
2718                         module_put(con_driver_map[i]->owner);
2719                 __module_get(owner);
2720                 con_driver_map[i] = csw;
2721
2722                 if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
2723                         continue;
2724
2725                 j = i;
2726                 if (IS_VISIBLE)
2727                         save_screen(i);
2728                 old_was_color = vc_cons[i].d->vc_can_do_color;
2729                 vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
2730                 origin = (unsigned long) screenbuf;
2731                 visible_origin = origin;
2732                 scr_end = origin + screenbuf_size;
2733                 pos = origin + video_size_row*y + 2*x;
2734                 visual_init(i, 0);
2735                 update_attr(i);
2736
2737                 /* If the console changed between mono <-> color, then
2738                  * the attributes in the screenbuf will be wrong.  The
2739                  * following resets all attributes to something sane.
2740                  */
2741                 if (old_was_color != vc_cons[i].d->vc_can_do_color)
2742                         clear_buffer_attributes(i);
2743
2744                 if (IS_VISIBLE)
2745                         update_screen(i);
2746         }
2747         printk("Console: switching ");
2748         if (!deflt)
2749                 printk("consoles %d-%d ", first+1, last+1);
2750         if (j >= 0)
2751                 printk("to %s %s %dx%d\n",
2752                        vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
2753                        desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
2754         else
2755                 printk("to %s\n", desc);
2756
2757         release_console_sem();
2758
2759         module_put(owner);
2760         return 0;
2761 }
2762
2763 void give_up_console(const struct consw *csw)
2764 {
2765         int i;
2766
2767         for(i = 0; i < MAX_NR_CONSOLES; i++)
2768                 if (con_driver_map[i] == csw) {
2769                         module_put(csw->owner);
2770                         con_driver_map[i] = NULL;
2771                 }
2772 }
2773
2774 #endif
2775
2776 /*
2777  *      Screen blanking
2778  */
2779
2780 static void set_vesa_blanking(char __user *p)
2781 {
2782     unsigned int mode;
2783     get_user(mode, p + 1);
2784     vesa_blank_mode = (mode < 4) ? mode : 0;
2785 }
2786
2787 /*
2788  * This is called by a timer handler
2789  */
2790 static void vesa_powerdown(void)
2791 {
2792     struct vc_data *c = vc_cons[fg_console].d;
2793     /*
2794      *  Power down if currently suspended (1 or 2),
2795      *  suspend if currently blanked (0),
2796      *  else do nothing (i.e. already powered down (3)).
2797      *  Called only if powerdown features are allowed.
2798      */
2799     switch (vesa_blank_mode) {
2800     case VESA_NO_BLANKING:
2801             c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1, 0);
2802             break;
2803     case VESA_VSYNC_SUSPEND:
2804     case VESA_HSYNC_SUSPEND:
2805             c->vc_sw->con_blank(c, VESA_POWERDOWN+1, 0);
2806             break;
2807     }
2808 }
2809
2810 void do_blank_screen(int entering_gfx)
2811 {
2812         int currcons = fg_console;
2813         int i;
2814
2815         WARN_CONSOLE_UNLOCKED();
2816
2817         if (console_blanked) {
2818                 if (blank_state == blank_vesa_wait) {
2819                         blank_state = blank_off;
2820                         vesa_powerdown();
2821
2822                 }
2823                 return;
2824         }
2825         if (blank_state != blank_normal_wait)
2826                 return;
2827         blank_state = blank_off;
2828
2829         /* entering graphics mode? */
2830         if (entering_gfx) {
2831                 hide_cursor(currcons);
2832                 save_screen(currcons);
2833                 sw->con_blank(vc_cons[currcons].d, -1, 1);
2834                 console_blanked = fg_console + 1;
2835                 set_origin(currcons);
2836                 return;
2837         }
2838
2839         /* don't blank graphics */
2840         if (vcmode != KD_TEXT) {
2841                 console_blanked = fg_console + 1;
2842                 return;
2843         }
2844
2845         hide_cursor(currcons);
2846         del_timer_sync(&console_timer);
2847         blank_timer_expired = 0;
2848
2849         save_screen(currcons);
2850         /* In case we need to reset origin, blanking hook returns 1 */
2851         i = sw->con_blank(vc_cons[currcons].d, 1, 0);
2852         console_blanked = fg_console + 1;
2853         if (i)
2854                 set_origin(currcons);
2855
2856         if (console_blank_hook && console_blank_hook(1))
2857                 return;
2858
2859         if (vesa_off_interval) {
2860                 blank_state = blank_vesa_wait,
2861                 mod_timer(&console_timer, jiffies + vesa_off_interval);
2862         }
2863
2864         if (vesa_blank_mode)
2865                 sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1, 0);
2866 }
2867
2868
2869 /*
2870  * Called by timer as well as from vt_console_driver
2871  */
2872 void do_unblank_screen(int leaving_gfx)
2873 {
2874         int currcons;
2875
2876         WARN_CONSOLE_UNLOCKED();
2877
2878         ignore_poke = 0;
2879         if (!console_blanked)
2880                 return;
2881         if (!vc_cons_allocated(fg_console)) {
2882                 /* impossible */
2883                 printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2884                 return;
2885         }
2886         currcons = fg_console;
2887         if (vcmode != KD_TEXT)
2888                 return; /* but leave console_blanked != 0 */
2889
2890         if (blankinterval) {
2891                 mod_timer(&console_timer, jiffies + blankinterval);
2892                 blank_state = blank_normal_wait;
2893         }
2894
2895         console_blanked = 0;
2896         if (sw->con_blank(vc_cons[currcons].d, 0, leaving_gfx))
2897                 /* Low-level driver cannot restore -> do it ourselves */
2898                 update_screen(fg_console);
2899         if (console_blank_hook)
2900                 console_blank_hook(0);
2901         set_palette(currcons);
2902         set_cursor(fg_console);
2903 }
2904
2905 /*
2906  * This is called by the outside world to cause a forced unblank, mostly for
2907  * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
2908  * call it with 1 as an argument and so force a mode restore... that may kill
2909  * X or at least garbage the screen but would also make the Oops visible...
2910  */
2911 void unblank_screen(void)
2912 {
2913         do_unblank_screen(0);
2914 }
2915
2916 /*
2917  * We defer the timer blanking to work queue so it can take the console semaphore
2918  * (console operations can still happen at irq time, but only from printk which
2919  * has the console semaphore. Not perfect yet, but better than no locking
2920  */
2921 static void blank_screen_t(unsigned long dummy)
2922 {
2923         blank_timer_expired = 1;
2924         schedule_work(&console_work);
2925 }
2926
2927 void poke_blanked_console(void)
2928 {
2929         WARN_CONSOLE_UNLOCKED();
2930
2931         /* This isn't perfectly race free, but a race here would be mostly harmless,
2932          * at worse, we'll do a spurrious blank and it's unlikely
2933          */
2934         del_timer(&console_timer);
2935         blank_timer_expired = 0;
2936
2937         if (ignore_poke || !vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
2938                 return;
2939         if (console_blanked)
2940                 unblank_screen();
2941         else if (blankinterval) {
2942                 mod_timer(&console_timer, jiffies + blankinterval);
2943                 blank_state = blank_normal_wait;
2944         }
2945 }
2946
2947 /*
2948  *      Palettes
2949  */
2950
2951 void set_palette(int currcons)
2952 {
2953         WARN_CONSOLE_UNLOCKED();
2954
2955         if (vcmode != KD_GRAPHICS)
2956                 sw->con_set_palette(vc_cons[currcons].d, color_table);
2957 }
2958
2959 static int set_get_cmap(unsigned char __user *arg, int set)
2960 {
2961     int i, j, k;
2962
2963     WARN_CONSOLE_UNLOCKED();
2964
2965     for (i = 0; i < 16; i++)
2966         if (set) {
2967             get_user(default_red[i], arg++);
2968             get_user(default_grn[i], arg++);
2969             get_user(default_blu[i], arg++);
2970         } else {
2971             put_user(default_red[i], arg++);
2972             put_user(default_grn[i], arg++);
2973             put_user(default_blu[i], arg++);
2974         }
2975     if (set) {
2976         for (i = 0; i < MAX_NR_CONSOLES; i++)
2977             if (vc_cons_allocated(i)) {
2978                 for (j = k = 0; j < 16; j++) {
2979                     vc_cons[i].d->vc_palette[k++] = default_red[j];
2980                     vc_cons[i].d->vc_palette[k++] = default_grn[j];
2981                     vc_cons[i].d->vc_palette[k++] = default_blu[j];
2982                 }
2983                 set_palette(i);
2984             }
2985     }
2986     return 0;
2987 }
2988
2989 /*
2990  * Load palette into the DAC registers. arg points to a colour
2991  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
2992  */
2993
2994 int con_set_cmap(unsigned char __user *arg)
2995 {
2996         int rc;
2997
2998         acquire_console_sem();
2999         rc = set_get_cmap (arg,1);
3000         release_console_sem();
3001
3002         return rc;
3003 }
3004
3005 int con_get_cmap(unsigned char __user *arg)
3006 {
3007         int rc;
3008
3009         acquire_console_sem();
3010         rc = set_get_cmap (arg,0);
3011         release_console_sem();
3012
3013         return rc;
3014 }
3015
3016 void reset_palette(int currcons)
3017 {
3018         int j, k;
3019         for (j=k=0; j<16; j++) {
3020                 palette[k++] = default_red[j];
3021                 palette[k++] = default_grn[j];
3022                 palette[k++] = default_blu[j];
3023         }
3024         set_palette(currcons);
3025 }
3026
3027 /*
3028  *  Font switching
3029  *
3030  *  Currently we only support fonts up to 32 pixels wide, at a maximum height
3031  *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
3032  *  depending on width) reserved for each character which is kinda wasty, but 
3033  *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
3034  *  is upto the actual low-level console-driver convert data into its favorite
3035  *  format (maybe we should add a `fontoffset' field to the `display'
3036  *  structure so we won't have to convert the fontdata all the time.
3037  *  /Jes
3038  */
3039
3040 #define max_font_size 65536
3041
3042 int con_font_get(int currcons, struct console_font_op *op)
3043 {
3044         struct console_font font;
3045         int rc = -EINVAL;
3046         int c;
3047
3048         if (vt_cons[currcons]->vc_mode != KD_TEXT)
3049                 return -EINVAL;
3050
3051         if (op->data) {
3052                 font.data = kmalloc(max_font_size, GFP_KERNEL);
3053                 if (!font.data)
3054                         return -ENOMEM;
3055         } else
3056                 font.data = NULL;
3057
3058         acquire_console_sem();
3059         if (sw->con_font_get)
3060                 rc = sw->con_font_get(vc_cons[currcons].d, &font);
3061         else
3062                 rc = -ENOSYS;
3063         release_console_sem();
3064
3065         if (rc)
3066                 goto out;
3067
3068         c = (font.width+7)/8 * 32 * font.charcount;
3069         
3070         if (op->data && font.charcount > op->charcount)
3071                 rc = -ENOSPC;
3072         if (!(op->flags & KD_FONT_FLAG_OLD)) {
3073                 if (font.width > op->width || font.height > op->height) 
3074                         rc = -ENOSPC;
3075         } else {
3076                 if (font.width != 8)
3077                         rc = -EIO;
3078                 else if ((op->height && font.height > op->height) ||
3079                          font.height > 32)
3080                         rc = -ENOSPC;
3081         }
3082         if (rc)
3083                 goto out;
3084
3085         if (op->data && copy_to_user(op->data, font.data, c))
3086                 rc = -EFAULT;
3087
3088 out:
3089         kfree(font.data);
3090         return rc;
3091 }
3092
3093 int con_font_set(int currcons, struct console_font_op *op)
3094 {
3095         struct console_font font;
3096         int rc = -EINVAL;
3097         int size;
3098
3099         if (vt_cons[currcons]->vc_mode != KD_TEXT)
3100                 return -EINVAL;
3101         if (!op->data)
3102                 return -EINVAL;
3103         if (op->charcount > 512)
3104                 return -EINVAL;
3105         if (!op->height) {              /* Need to guess font height [compat] */
3106                 int h, i;
3107                 u8 __user *charmap = op->data;
3108                 u8 tmp;
3109                 
3110                 /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
3111                    so that we can get rid of this soon */
3112                 if (!(op->flags & KD_FONT_FLAG_OLD))
3113                         return -EINVAL;
3114                 for (h = 32; h > 0; h--)
3115                         for (i = 0; i < op->charcount; i++) {
3116                                 if (get_user(tmp, &charmap[32*i+h-1]))
3117                                         return -EFAULT;
3118                                 if (tmp)
3119                                         goto nonzero;
3120                         }
3121                 return -EINVAL;
3122         nonzero:
3123                 op->height = h;
3124         }
3125         if (op->width <= 0 || op->width > 32 || op->height > 32)
3126                 return -EINVAL;
3127         size = (op->width+7)/8 * 32 * op->charcount;
3128         if (size > max_font_size)
3129                 return -ENOSPC;
3130         font.charcount = op->charcount;
3131         font.height = op->height;
3132         font.width = op->width;
3133         font.data = kmalloc(size, GFP_KERNEL);
3134         if (!font.data)
3135                 return -ENOMEM;
3136         if (copy_from_user(font.data, op->data, size)) {
3137                 kfree(font.data);
3138                 return -EFAULT;
3139         }
3140         acquire_console_sem();
3141         if (sw->con_font_set)
3142                 rc = sw->con_font_set(vc_cons[currcons].d, &font, op->flags);
3143         else
3144                 rc = -ENOSYS;
3145         release_console_sem();
3146         kfree(font.data);
3147         return rc;
3148 }
3149
3150 int con_font_default(int currcons, struct console_font_op *op)
3151 {
3152         struct console_font font = {.width = op->width, .height = op->height};
3153         char name[MAX_FONT_NAME];
3154         char *s = name;
3155         int rc;
3156
3157         if (vt_cons[currcons]->vc_mode != KD_TEXT)
3158                 return -EINVAL;
3159
3160         if (!op->data)
3161                 s = NULL;
3162         else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
3163                 return -EFAULT;
3164         else
3165                 name[MAX_FONT_NAME - 1] = 0;
3166
3167         acquire_console_sem();
3168         if (sw->con_font_default)
3169                 rc = sw->con_font_default(vc_cons[currcons].d, &font, s);
3170         else
3171                 rc = -ENOSYS;
3172         release_console_sem();
3173         if (!rc) {
3174                 op->width = font.width;
3175                 op->height = font.height;
3176         }
3177         return rc;
3178 }
3179
3180 int con_font_copy(int currcons, struct console_font_op *op)
3181 {
3182         int con = op->height;
3183         struct vc_data *vc;
3184         int rc;
3185
3186         if (vt_cons[currcons]->vc_mode != KD_TEXT)
3187                 return -EINVAL;
3188
3189         acquire_console_sem();
3190         vc = vc_cons[currcons].d;
3191         if (!sw->con_font_copy)
3192                 rc = -ENOSYS;
3193         else if (con < 0 || !vc_cons_allocated(con))
3194                 rc = -ENOTTY;
3195         else if (con == vc->vc_num)     /* nothing to do */
3196                 rc = 0;
3197         else
3198                 rc = sw->con_font_copy(vc, con);
3199         release_console_sem();
3200         return rc;
3201 }
3202
3203 int con_font_op(int currcons, struct console_font_op *op)
3204 {
3205         switch (op->op) {
3206         case KD_FONT_OP_SET:
3207                 return con_font_set(currcons, op);
3208         case KD_FONT_OP_GET:
3209                 return con_font_get(currcons, op);
3210         case KD_FONT_OP_SET_DEFAULT:
3211                 return con_font_default(currcons, op);
3212         case KD_FONT_OP_COPY:
3213                 return con_font_copy(currcons, op);
3214         }
3215         return -ENOSYS;
3216 }
3217
3218 /*
3219  *      Interface exported to selection and vcs.
3220  */
3221
3222 /* used by selection */
3223 u16 screen_glyph(int currcons, int offset)
3224 {
3225         u16 w = scr_readw(screenpos(currcons, offset, 1));
3226         u16 c = w & 0xff;
3227
3228         if (w & hi_font_mask)
3229                 c |= 0x100;
3230         return c;
3231 }
3232
3233 /* used by vcs - note the word offset */
3234 unsigned short *screen_pos(int currcons, int w_offset, int viewed)
3235 {
3236         return screenpos(currcons, 2 * w_offset, viewed);
3237 }
3238
3239 void getconsxy(int currcons, unsigned char *p)
3240 {
3241         p[0] = x;
3242         p[1] = y;
3243 }
3244
3245 void putconsxy(int currcons, unsigned char *p)
3246 {
3247         gotoxy(currcons, p[0], p[1]);
3248         set_cursor(currcons);
3249 }
3250
3251 u16 vcs_scr_readw(int currcons, const u16 *org)
3252 {
3253         if ((unsigned long)org == pos && softcursor_original != -1)
3254                 return softcursor_original;
3255         return scr_readw(org);
3256 }
3257
3258 void vcs_scr_writew(int currcons, u16 val, u16 *org)
3259 {
3260         scr_writew(val, org);
3261         if ((unsigned long)org == pos) {
3262                 softcursor_original = -1;
3263                 add_softcursor(currcons);
3264         }
3265 }
3266
3267 static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
3268 {
3269         switch (rqst)
3270         {
3271         case PM_RESUME:
3272                 acquire_console_sem();
3273                 unblank_screen();
3274                 release_console_sem();
3275                 break;
3276         case PM_SUSPEND:
3277                 acquire_console_sem();
3278                 do_blank_screen(0);
3279                 release_console_sem();
3280                 break;
3281         }
3282         return 0;
3283 }
3284
3285 /*
3286  *      Visible symbols for modules
3287  */
3288
3289 EXPORT_SYMBOL(color_table);
3290 EXPORT_SYMBOL(default_red);
3291 EXPORT_SYMBOL(default_grn);
3292 EXPORT_SYMBOL(default_blu);
3293 EXPORT_SYMBOL(update_region);
3294 EXPORT_SYMBOL(redraw_screen);
3295 EXPORT_SYMBOL(vc_resize);
3296 EXPORT_SYMBOL(fg_console);
3297 EXPORT_SYMBOL(console_blank_hook);
3298 EXPORT_SYMBOL(console_blanked);
3299 EXPORT_SYMBOL(vt_cons);
3300 EXPORT_SYMBOL(vc_cons);
3301 #ifndef VT_SINGLE_DRIVER
3302 EXPORT_SYMBOL(take_over_console);
3303 EXPORT_SYMBOL(give_up_console);
3304 #endif