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