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