Import 2.1.33
[davej-history.git] / drivers / char / console.c
blob763d3c71b3bc61daed74f68f769528e76c6ba647
1 /*
2 * linux/drivers/char/console.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6 /*
7 * console.c
9 * This module exports the console io functions:
11 * 'void do_keyboard_interrupt(void)'
13 * 'int vc_allocate(unsigned int console)'
14 * 'int vc_cons_allocated(unsigned int console)'
15 * 'int vc_resize(unsigned long lines, unsigned long cols)'
16 * 'void vc_disallocate(unsigned int currcons)'
18 * 'unsigned long con_init(unsigned long)'
19 * 'int con_open(struct tty_struct *tty, struct file * filp)'
20 * 'void con_write(struct tty_struct * tty)'
21 * 'void vt_console_print(const char * b)'
22 * 'void update_screen(int new_console)'
24 * 'void do_blank_screen(int)'
25 * 'void do_unblank_screen(void)'
26 * 'void poke_blanked_console(void)'
28 * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)'
29 * 'void complement_pos(int currcons, int offset)'
30 * 'void invert_screen(int currcons, int offset, int count, int shift)'
32 * 'void scrollback(int lines)'
33 * 'void scrollfront(int lines)'
35 * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
36 * 'int mouse_reporting(void)'
38 * Hopefully this will be a rather complete VT102 implementation.
40 * Beeping thanks to John T Kohl.
42 * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
43 * Chars, and VT100 enhancements by Peter MacDonald.
45 * Copy and paste function by Andrew Haylett,
46 * some enhancements by Alessandro Rubini.
48 * Code to check for different video-cards mostly by Galen Hunt,
49 * <g-hunt@ee.utah.edu>
51 * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
52 * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
54 * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
55 * Resizing of consoles, aeb, 940926
57 * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
58 * <poe@daimi.aau.dk>
60 * User-defined bell sound, new setterm control sequences and printk
61 * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
63 * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
66 #define BLANK 0x0020
68 /* A bitmap for codes <32. A bit of 1 indicates that the code
69 * corresponding to that bit number invokes some special action
70 * (such as cursor movement) and should not be displayed as a
71 * glyph unless the disp_ctrl mode is explicitly enabled.
73 #define CTRL_ACTION 0x0d00ff81
74 #define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
77 * Here is the default bell parameters: 750HZ, 1/8th of a second
79 #define DEFAULT_BELL_PITCH 750
80 #define DEFAULT_BELL_DURATION (HZ/8)
83 * NOTE!!! We sometimes disable and enable interrupts for a short while
84 * (to put a word in video IO), but this will work even for keyboard
85 * interrupts. We know interrupts aren't enabled when getting a keyboard
86 * interrupt, as we use trap-gates. Hopefully all is well.
89 #include <linux/sched.h>
90 #include <linux/timer.h>
91 #include <linux/interrupt.h>
92 #include <linux/tty.h>
93 #include <linux/tty_flip.h>
94 #include <linux/console.h>
95 #include <linux/config.h>
96 #include <linux/kernel.h>
97 #include <linux/string.h>
98 #include <linux/errno.h>
99 #include <linux/kd.h>
100 #include <linux/malloc.h>
101 #include <linux/major.h>
102 #include <linux/mm.h>
103 #include <linux/ioport.h>
104 #ifdef CONFIG_APM
105 #include <linux/apm_bios.h>
106 #endif
108 #include <asm/io.h>
109 #include <asm/system.h>
110 #include <asm/uaccess.h>
111 #include <asm/bitops.h>
113 #include "kbd_kern.h"
114 #include "vt_kern.h"
115 #include "consolemap.h"
116 #include "selection.h"
117 #include "console_struct.h"
119 #ifndef MIN
120 #define MIN(a,b) ((a) < (b) ? (a) : (b))
121 #endif
123 #ifdef __sparc__
124 int serial_console;
125 #endif
127 struct tty_driver console_driver;
128 static int console_refcount;
129 static struct tty_struct *console_table[MAX_NR_CONSOLES];
130 static struct termios *console_termios[MAX_NR_CONSOLES];
131 static struct termios *console_termios_locked[MAX_NR_CONSOLES];
132 unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
133 struct vc vc_cons [MAX_NR_CONSOLES];
135 static int con_open(struct tty_struct *, struct file *);
136 static void con_setsize(unsigned long rows, unsigned long cols);
137 static void vc_init(unsigned int console, unsigned long rows,
138 unsigned long cols, int do_clear);
139 extern void get_scrmem(int currcons);
140 extern void set_scrmem(int currcons, long offset);
141 static void set_origin(int currcons);
142 static void blank_screen(void);
143 static void unblank_screen(void);
144 extern void change_console(unsigned int);
145 extern void poke_blanked_console(void);
146 static void gotoxy(int currcons, int new_x, int new_y);
147 static void save_cur(int currcons);
148 extern void set_cursor(int currcons);
149 extern void hide_cursor(void);
150 static void reset_terminal(int currcons, int do_clear);
151 extern void reset_vc(unsigned int new_console);
152 extern void vt_init(void);
153 extern void set_vesa_blanking(unsigned long arg);
154 extern void vesa_blank(void);
155 extern void vesa_unblank(void);
156 extern void vesa_powerdown(void);
157 extern void compute_shiftstate(void);
158 extern void reset_palette(int currcons);
159 extern void set_palette(void);
160 extern unsigned long con_type_init(unsigned long, const char **);
161 extern void con_type_init_finish(void);
162 extern int set_get_cmap(unsigned char *, int);
163 extern int set_get_font(unsigned char *, int, int);
164 extern void rs_cons_hook(int chip, int out, int channel);
166 /* Description of the hardware situation */
167 unsigned char video_type; /* Type of display being used */
168 unsigned long video_mem_base; /* Base of video memory */
169 unsigned long video_mem_term; /* End of video memory */
170 unsigned short video_port_reg; /* Video register select port */
171 unsigned short video_port_val; /* Video register value port */
172 unsigned long video_num_columns; /* Number of text columns */
173 unsigned long video_num_lines; /* Number of text lines */
174 unsigned long video_size_row;
175 unsigned long video_screen_size;
177 int can_do_color = 0;
178 static int printable = 0; /* Is console ready for printing? */
180 int video_mode_512ch = 0; /* 512-character mode */
181 unsigned long video_font_height; /* Height of current screen font */
182 unsigned long video_scan_lines; /* Number of scan lines on screen */
183 static unsigned long default_font_height; /* Height of default screen font */
184 int video_font_is_default = 1;
185 static unsigned short console_charmask = 0x0ff;
187 /* used by kbd_bh - set by keyboard_interrupt */
188 int do_poke_blanked_console = 0;
189 int console_blanked = 0;
190 static int blankinterval = 10*60*HZ;
191 static int vesa_off_interval = 0;
192 static long blank_origin, blank__origin, unblank_origin;
195 * fg_console is the current virtual console,
196 * last_console is the last used one,
197 * want_console is the console we want to switch to,
198 * kmsg_redirect is the console for kernel messages,
200 int fg_console = 0;
201 int last_console = 0;
202 int want_console = -1;
203 int kmsg_redirect = 0;
205 int vc_cons_allocated(unsigned int i)
207 return (i < MAX_NR_CONSOLES && vc_cons[i].d);
210 int vc_allocate(unsigned int i) /* return 0 on success */
212 if (i >= MAX_NR_CONSOLES)
213 return -ENXIO;
214 if (!vc_cons[i].d) {
215 long p, q;
217 /* prevent users from taking too much memory */
218 if (i >= MAX_NR_USER_CONSOLES && !suser())
219 return -EPERM;
221 /* due to the granularity of kmalloc, we waste some memory here */
222 /* the alloc is done in two steps, to optimize the common situation
223 of a 25x80 console (structsize=216, video_screen_size=4000) */
224 q = (long) kmalloc(video_screen_size, GFP_KERNEL);
225 if (!q)
226 return -ENOMEM;
227 p = (long) kmalloc(structsize, GFP_KERNEL);
228 if (!p) {
229 kfree_s((char *) q, video_screen_size);
230 return -ENOMEM;
233 vc_cons[i].d = (struct vc_data *) p;
234 p += sizeof(struct vc_data);
235 vt_cons[i] = (struct vt_struct *) p;
236 vc_scrbuf[i] = (unsigned short *) q;
237 vc_cons[i].d->vc_kmalloced = 1;
238 vc_cons[i].d->vc_screenbuf_size = video_screen_size;
239 vc_init (i, video_num_lines, video_num_columns, 1);
241 return 0;
245 * Change # of rows and columns (0 means unchanged)
246 * [this is to be used together with some user program
247 * like resize that changes the hardware videomode]
249 int vc_resize(unsigned long lines, unsigned long cols)
251 unsigned long cc, ll, ss, sr;
252 unsigned long occ, oll, oss, osr;
253 unsigned short *p;
254 unsigned int currcons, i;
255 unsigned short *newscreens[MAX_NR_CONSOLES];
256 long ol, nl, rlth, rrem;
258 cc = (cols ? cols : video_num_columns);
259 ll = (lines ? lines : video_num_lines);
260 sr = cc << 1;
261 ss = sr * ll;
263 if (ss > video_mem_term - video_mem_base)
264 return -ENOMEM;
267 * Some earlier version had all consoles of potentially
268 * different sizes, but that was really messy.
269 * So now we only change if there is room for all consoles
270 * of the same size.
272 for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
273 if (!vc_cons_allocated(currcons))
274 newscreens[currcons] = 0;
275 else {
276 p = (unsigned short *) kmalloc(ss, GFP_USER);
277 if (!p) {
278 for (i = 0; i< currcons; i++)
279 if (newscreens[i])
280 kfree_s(newscreens[i], ss);
281 return -ENOMEM;
283 newscreens[currcons] = p;
287 get_scrmem(fg_console);
289 oll = video_num_lines;
290 occ = video_num_columns;
291 osr = video_size_row;
292 oss = video_screen_size;
294 video_num_lines = ll;
295 video_num_columns = cc;
296 video_size_row = sr;
297 video_screen_size = ss;
299 for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) {
300 if (!vc_cons_allocated(currcons))
301 continue;
303 rlth = MIN(osr, sr);
304 rrem = sr - rlth;
305 ol = origin;
306 nl = (long) newscreens[currcons];
307 if (ll < oll)
308 ol += (oll - ll) * osr;
310 while (ol < scr_end) {
311 memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
312 if (rrem)
313 memsetw((void *)(nl + rlth), video_erase_char, rrem);
314 ol += osr;
315 nl += sr;
318 if (kmalloced)
319 kfree_s(vc_scrbuf[currcons], screenbuf_size);
320 vc_scrbuf[currcons] = newscreens[currcons];
321 kmalloced = 1;
322 screenbuf_size = ss;
324 origin = video_mem_start = (long) vc_scrbuf[currcons];
325 scr_end = video_mem_end = video_mem_start + ss;
327 if (scr_end > nl)
328 memsetw((void *) nl, video_erase_char, scr_end - nl);
330 /* do part of a reset_terminal() */
331 top = 0;
332 bottom = video_num_lines;
333 gotoxy(currcons, x, y);
334 save_cur(currcons);
337 set_scrmem(fg_console, 0);
338 set_origin(fg_console);
339 set_cursor(fg_console);
341 return 0;
344 void vc_disallocate(unsigned int currcons)
346 if (vc_cons_allocated(currcons)) {
347 if (kmalloced)
348 kfree_s(vc_scrbuf[currcons], screenbuf_size);
349 if (currcons >= MIN_NR_CONSOLES)
350 kfree_s(vc_cons[currcons].d, structsize);
351 vc_cons[currcons].d = 0;
356 #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
357 #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
358 #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
360 #define decarm VC_REPEAT
361 #define decckm VC_CKMODE
362 #define kbdapplic VC_APPLIC
363 #define lnm VC_CRLF
366 * this is what the terminal answers to a ESC-Z or csi0c query.
368 #define VT100ID "\033[?1;2c"
369 #define VT102ID "\033[?6c"
371 unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
372 8,12,10,14, 9,13,11,15 };
374 /* the default colour table, for VGA+ colour systems */
375 int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
376 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
377 int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
378 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
379 int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
380 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
383 * gotoxy() must verify all boundaries, because the arguments
384 * might also be negative. If the given position is out of
385 * bounds, the cursor is placed at the nearest margin.
387 static void gotoxy(int currcons, int new_x, int new_y)
389 int min_y, max_y;
391 if (new_x < 0)
392 x = 0;
393 else
394 if (new_x >= video_num_columns)
395 x = video_num_columns - 1;
396 else
397 x = new_x;
398 if (decom) {
399 min_y = top;
400 max_y = bottom;
401 } else {
402 min_y = 0;
403 max_y = video_num_lines;
405 if (new_y < min_y)
406 y = min_y;
407 else if (new_y >= max_y)
408 y = max_y - 1;
409 else
410 y = new_y;
411 pos = origin + y*video_size_row + (x<<1);
412 need_wrap = 0;
415 /* for absolute user moves, when decom is set */
416 static void gotoxay(int currcons, int new_x, int new_y)
418 gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
422 * Hardware scrollback support
424 extern void __set_origin(unsigned short);
425 unsigned short __real_origin; /* offset of non-scrolled screen */
426 unsigned short __origin; /* offset of currently displayed screen */
427 unsigned char has_wrapped; /* all of videomem is data of fg_console */
428 static unsigned char hardscroll_enabled;
429 static unsigned char hardscroll_disabled_by_init = 0;
431 void no_scroll(char *str, int *ints)
434 * Disabling scrollback is required for the Braillex ib80-piezo
435 * Braille reader made by F.H. Papenmeier (Germany).
436 * Use the "no-scroll" bootflag.
438 hardscroll_disabled_by_init = 1;
439 hardscroll_enabled = 0;
442 static void scrolldelta(int lines)
444 int new_origin;
445 int last_origin_rel = (((video_mem_term - video_mem_base)
446 / video_num_columns / 2) - (video_num_lines - 1)) * video_num_columns;
448 new_origin = __origin + lines * video_num_columns;
449 if (__origin > __real_origin)
450 new_origin -= last_origin_rel;
451 if (new_origin < 0) {
452 int s_top = __real_origin + video_num_lines*video_num_columns;
453 new_origin += last_origin_rel;
454 if (new_origin < s_top)
455 new_origin = s_top;
456 if (new_origin > last_origin_rel - video_num_columns
457 || has_wrapped == 0)
458 new_origin = 0;
459 else {
460 unsigned short * d = (unsigned short *) video_mem_base;
461 unsigned short * s = d + last_origin_rel;
462 int count = (video_num_lines-1)*video_num_columns;
463 while (count) {
464 count--;
465 scr_writew(scr_readw(d++),s++);
468 } else if (new_origin > __real_origin)
469 new_origin = __real_origin;
471 __set_origin(new_origin);
474 void scrollback(int lines)
476 if (!lines)
477 lines = video_num_lines/2;
478 scrolldelta(-lines);
481 void scrollfront(int lines)
483 if (!lines)
484 lines = video_num_lines/2;
485 scrolldelta(lines);
488 static void set_origin(int currcons)
490 if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC
491 && video_type != VIDEO_TYPE_EGAM)
492 return;
493 if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
494 return;
495 __real_origin = (origin-video_mem_base) >> 1;
496 __set_origin(__real_origin);
499 static void scrup(int currcons, unsigned int t, unsigned int b)
501 int hardscroll = hardscroll_enabled;
503 if (b > video_num_lines || t >= b)
504 return;
505 if (t || b != video_num_lines)
506 hardscroll = 0;
507 if (hardscroll) {
508 origin += video_size_row;
509 pos += video_size_row;
510 scr_end += video_size_row;
511 if (scr_end > video_mem_end) {
512 unsigned short * d = (unsigned short *) video_mem_start;
513 unsigned short * s = (unsigned short *) origin;
514 unsigned int count;
516 count = (video_num_lines-1)*video_num_columns;
517 while (count) {
518 count--;
519 scr_writew(scr_readw(s++),d++);
521 count = video_num_columns;
522 while (count) {
523 count--;
524 scr_writew(video_erase_char, d++);
526 scr_end -= origin-video_mem_start;
527 pos -= origin-video_mem_start;
528 origin = video_mem_start;
529 has_scrolled = 1;
530 if (currcons == fg_console)
531 has_wrapped = 1;
532 } else {
533 unsigned short * d;
534 unsigned int count;
536 d = (unsigned short *) (scr_end - video_size_row);
537 count = video_num_columns;
538 while (count) {
539 count--;
540 scr_writew(video_erase_char, d++);
543 set_origin(currcons);
544 } else {
545 unsigned short * d = (unsigned short *) (origin+video_size_row*t);
546 unsigned short * s = (unsigned short *) (origin+video_size_row*(t+1));
548 memcpyw(d, s, (b-t-1) * video_size_row);
549 memsetw(d + (b-t-1) * video_num_columns, video_erase_char, video_size_row);
553 static void
554 scrdown(int currcons, unsigned int t, unsigned int b)
556 unsigned short *s;
557 unsigned int count;
559 if (b > video_num_lines || t >= b)
560 return;
561 s = (unsigned short *) (origin+video_size_row*(b-2));
562 if (b >= t + 1) {
563 count = b - t - 1;
564 while (count) {
565 count--;
566 memcpyw(s + video_num_columns, s, video_size_row);
567 s -= video_num_columns;
570 memsetw(s + video_num_columns, video_erase_char, video_size_row);
571 has_scrolled = 1;
574 static void lf(int currcons)
576 /* don't scroll if above bottom of scrolling region, or
577 * if below scrolling region
579 if (y+1 == bottom)
580 scrup(currcons,top,bottom);
581 else if (y < video_num_lines-1) {
582 y++;
583 pos += video_size_row;
585 need_wrap = 0;
588 static void ri(int currcons)
590 /* don't scroll if below top of scrolling region, or
591 * if above scrolling region
593 if (y == top)
594 scrdown(currcons,top,bottom);
595 else if (y > 0) {
596 y--;
597 pos -= video_size_row;
599 need_wrap = 0;
602 static inline void cr(int currcons)
604 pos -= x<<1;
605 need_wrap = x = 0;
608 static inline void bs(int currcons)
610 if (x) {
611 pos -= 2;
612 x--;
613 need_wrap = 0;
617 static inline void del(int currcons)
619 /* ignored */
622 static void csi_J(int currcons, int vpar)
624 unsigned long count;
625 unsigned short * start;
627 switch (vpar) {
628 case 0: /* erase from cursor to end of display */
629 count = (scr_end-pos)>>1;
630 start = (unsigned short *) pos;
631 break;
632 case 1: /* erase from start to cursor */
633 count = ((pos-origin)>>1)+1;
634 start = (unsigned short *) origin;
635 break;
636 case 2: /* erase whole display */
637 count = video_num_columns * video_num_lines;
638 start = (unsigned short *) origin;
639 break;
640 default:
641 return;
643 memsetw(start, video_erase_char, 2*count);
644 need_wrap = 0;
647 static void csi_K(int currcons, int vpar)
649 unsigned long count;
650 unsigned short * start;
652 switch (vpar) {
653 case 0: /* erase from cursor to end of line */
654 count = video_num_columns-x;
655 start = (unsigned short *) pos;
656 break;
657 case 1: /* erase from start of line to cursor */
658 start = (unsigned short *) (pos - (x<<1));
659 count = x+1;
660 break;
661 case 2: /* erase whole line */
662 start = (unsigned short *) (pos - (x<<1));
663 count = video_num_columns;
664 break;
665 default:
666 return;
668 memsetw(start, video_erase_char, 2 * count);
669 need_wrap = 0;
672 static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
673 { /* not vt100? */
674 if (!vpar)
675 vpar++;
677 memsetw((unsigned short *) pos, video_erase_char,
678 (vpar > video_num_columns-x) ? 2 * (video_num_columns-x) : 2 * vpar);
679 need_wrap = 0;
682 static void update_attr(int currcons)
684 attr = color;
685 if (can_do_color) {
686 if (underline)
687 attr = (attr & 0xf0) | ulcolor;
688 else if (intensity == 0)
689 attr = (attr & 0xf0) | halfcolor;
691 if (reverse ^ decscnm)
692 attr = reverse_video_char(attr);
693 if (blink)
694 attr ^= 0x80;
695 if (intensity == 2)
696 attr ^= 0x08;
697 if (!can_do_color) {
698 if (underline)
699 attr = (attr & 0xf8) | 0x01;
700 else if (intensity == 0)
701 attr = (attr & 0xf0) | 0x08;
703 if (decscnm)
704 video_erase_char = (reverse_video_char(color) << 8) | ' ';
705 else
706 video_erase_char = (color << 8) | ' ';
709 static void default_attr(int currcons)
711 intensity = 1;
712 underline = 0;
713 reverse = 0;
714 blink = 0;
715 color = def_color;
718 static void csi_m(int currcons)
720 int i;
722 for (i=0;i<=npar;i++)
723 switch (par[i]) {
724 case 0: /* all attributes off */
725 default_attr(currcons);
726 break;
727 case 1:
728 intensity = 2;
729 break;
730 case 2:
731 intensity = 0;
732 break;
733 case 4:
734 underline = 1;
735 break;
736 case 5:
737 blink = 1;
738 break;
739 case 7:
740 reverse = 1;
741 break;
742 case 10: /* ANSI X3.64-1979 (SCO-ish?)
743 * Select primary font, don't display
744 * control chars if defined, don't set
745 * bit 8 on output.
747 translate = set_translate(charset == 0
748 ? G0_charset
749 : G1_charset);
750 disp_ctrl = 0;
751 toggle_meta = 0;
752 break;
753 case 11: /* ANSI X3.64-1979 (SCO-ish?)
754 * Select first alternate font, lets
755 * chars < 32 be displayed as ROM chars.
757 translate = set_translate(IBMPC_MAP);
758 disp_ctrl = 1;
759 toggle_meta = 0;
760 break;
761 case 12: /* ANSI X3.64-1979 (SCO-ish?)
762 * Select second alternate font, toggle
763 * high bit before displaying as ROM char.
765 translate = set_translate(IBMPC_MAP);
766 disp_ctrl = 1;
767 toggle_meta = 1;
768 break;
769 case 21:
770 case 22:
771 intensity = 1;
772 break;
773 case 24:
774 underline = 0;
775 break;
776 case 25:
777 blink = 0;
778 break;
779 case 27:
780 reverse = 0;
781 break;
782 case 38: /* ANSI X3.64-1979 (SCO-ish?)
783 * Enables underscore, white foreground
784 * with white underscore (Linux - use
785 * default foreground).
787 color = (def_color & 0x0f) | background;
788 underline = 1;
789 break;
790 case 39: /* ANSI X3.64-1979 (SCO-ish?)
791 * Disable underline option.
792 * Reset colour to default? It did this
793 * before...
795 color = (def_color & 0x0f) | background;
796 underline = 0;
797 break;
798 case 49:
799 color = (def_color & 0xf0) | foreground;
800 break;
801 default:
802 if (par[i] >= 30 && par[i] <= 37)
803 color = color_table[par[i]-30]
804 | background;
805 else if (par[i] >= 40 && par[i] <= 47)
806 color = (color_table[par[i]-40]<<4)
807 | foreground;
808 break;
810 update_attr(currcons);
813 static void respond_string(const char * p, struct tty_struct * tty)
815 while (*p) {
816 tty_insert_flip_char(tty, *p, 0);
817 p++;
819 tty_schedule_flip(tty);
822 static void cursor_report(int currcons, struct tty_struct * tty)
824 char buf[40];
826 sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1);
827 respond_string(buf, tty);
830 static inline void status_report(struct tty_struct * tty)
832 respond_string("\033[0n", tty); /* Terminal ok */
835 static inline void respond_ID(struct tty_struct * tty)
837 respond_string(VT102ID, tty);
840 void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
842 char buf[8];
844 sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
845 (char)('!' + mry));
846 respond_string(buf, tty);
849 /* invoked via ioctl(TIOCLINUX) and through set_selection */
850 int mouse_reporting(void)
852 int currcons = fg_console;
854 return report_mouse;
857 int tioclinux(struct tty_struct *tty, unsigned long arg)
859 char type, data;
861 if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
862 return -EINVAL;
863 if (current->tty != tty && !suser())
864 return -EPERM;
865 if (get_user(type, (char *)arg))
866 return -EFAULT;
867 switch (type)
869 case 2:
870 return set_selection(arg, tty, 1);
871 case 3:
872 return paste_selection(tty);
873 case 4:
874 do_unblank_screen();
875 return 0;
876 case 5:
877 return sel_loadlut(arg);
878 case 6:
881 * Make it possible to react to Shift+Mousebutton.
882 * Note that 'shift_state' is an undocumented
883 * kernel-internal variable; programs not closely
884 * related to the kernel should not use this.
886 data = shift_state;
887 return __put_user(data, (char *) arg);
888 case 7:
889 data = mouse_reporting();
890 return __put_user(data, (char *) arg);
891 case 10:
892 set_vesa_blanking(arg);
893 return 0;
894 case 11: /* set kmsg redirect */
895 if (!suser())
896 return -EPERM;
897 if (get_user(data, (char *)arg+1))
898 return -EFAULT;
899 kmsg_redirect = data;
900 return 0;
901 case 12: /* get fg_console */
902 return fg_console;
904 return -EINVAL;
907 static inline unsigned short *screenpos(int currcons, int offset, int viewed)
909 unsigned short *p = (unsigned short *)(origin + offset);
910 if (viewed && currcons == fg_console)
911 p -= (__real_origin - __origin);
912 return p;
915 /* Note: inverting the screen twice should revert to the original state */
916 void invert_screen(int currcons, int offset, int count, int viewed)
918 unsigned short *p;
920 count /= 2;
921 p = screenpos(currcons, offset, viewed);
922 if (can_do_color)
923 while (count--) {
924 unsigned short old = scr_readw(p);
925 scr_writew(reverse_video_short(old), p);
926 p++;
928 else
929 while (count--) {
930 unsigned short old = scr_readw(p);
931 scr_writew(old ^ (((old & 0x0700) == 0x0100)
932 ? 0x7000 : 0x7700), p);
933 p++;
937 /* used by selection: complement pointer position */
938 void complement_pos(int currcons, int offset)
940 static unsigned short *p = NULL;
941 static unsigned short old = 0;
943 if (p)
944 scr_writew(old, p);
945 if (offset == -1)
946 p = NULL;
947 else {
948 p = screenpos(currcons, offset, 1);
949 old = scr_readw(p);
950 scr_writew(old ^ 0x7700, p);
954 /* used by selection */
955 unsigned short screen_word(int currcons, int offset, int viewed)
957 return scr_readw(screenpos(currcons, offset, viewed));
960 /* used by selection - convert a screen word to a glyph number */
961 int scrw2glyph(unsigned short scr_word)
963 return ( video_mode_512ch )
964 ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff)
965 : scr_word & 0x00ff;
968 /* used by vcs - note the word offset */
969 unsigned short *screen_pos(int currcons, int w_offset, int viewed)
971 return screenpos(currcons, 2 * w_offset, viewed);
974 void getconsxy(int currcons, char *p)
976 p[0] = x;
977 p[1] = y;
980 void putconsxy(int currcons, char *p)
982 gotoxy(currcons, p[0], p[1]);
983 set_cursor(currcons);
986 static void set_mode(int currcons, int on_off)
988 int i;
990 for (i=0; i<=npar; i++)
991 if (ques) switch(par[i]) { /* DEC private modes set/reset */
992 case 1: /* Cursor keys send ^[Ox/^[[x */
993 if (on_off)
994 set_kbd(decckm);
995 else
996 clr_kbd(decckm);
997 break;
998 case 3: /* 80/132 mode switch unimplemented */
999 deccolm = on_off;
1000 #if 0
1001 (void) vc_resize(video_num_lines, deccolm ? 132 : 80);
1002 /* this alone does not suffice; some user mode
1003 utility has to change the hardware regs */
1004 #endif
1005 break;
1006 case 5: /* Inverted screen on/off */
1007 if (decscnm != on_off) {
1008 decscnm = on_off;
1009 invert_screen(currcons, 0, video_screen_size, 0);
1010 update_attr(currcons);
1012 break;
1013 case 6: /* Origin relative/absolute */
1014 decom = on_off;
1015 gotoxay(currcons,0,0);
1016 break;
1017 case 7: /* Autowrap on/off */
1018 decawm = on_off;
1019 break;
1020 case 8: /* Autorepeat on/off */
1021 if (on_off)
1022 set_kbd(decarm);
1023 else
1024 clr_kbd(decarm);
1025 break;
1026 case 9:
1027 report_mouse = on_off ? 1 : 0;
1028 break;
1029 case 25: /* Cursor on/off */
1030 deccm = on_off;
1031 set_cursor(currcons);
1032 break;
1033 case 1000:
1034 report_mouse = on_off ? 2 : 0;
1035 break;
1036 } else switch(par[i]) { /* ANSI modes set/reset */
1037 case 3: /* Monitor (display ctrls) */
1038 disp_ctrl = on_off;
1039 break;
1040 case 4: /* Insert Mode on/off */
1041 decim = on_off;
1042 break;
1043 case 20: /* Lf, Enter == CrLf/Lf */
1044 if (on_off)
1045 set_kbd(lnm);
1046 else
1047 clr_kbd(lnm);
1048 break;
1052 static void setterm_command(int currcons)
1054 switch(par[0]) {
1055 case 1: /* set color for underline mode */
1056 if (can_do_color && par[1] < 16) {
1057 ulcolor = color_table[par[1]];
1058 if (underline)
1059 update_attr(currcons);
1061 break;
1062 case 2: /* set color for half intensity mode */
1063 if (can_do_color && par[1] < 16) {
1064 halfcolor = color_table[par[1]];
1065 if (intensity == 0)
1066 update_attr(currcons);
1068 break;
1069 case 8: /* store colors as defaults */
1070 def_color = attr;
1071 default_attr(currcons);
1072 update_attr(currcons);
1073 break;
1074 case 9: /* set blanking interval */
1075 blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1076 poke_blanked_console();
1077 break;
1078 case 10: /* set bell frequency in Hz */
1079 if (npar >= 1)
1080 bell_pitch = par[1];
1081 else
1082 bell_pitch = DEFAULT_BELL_PITCH;
1083 break;
1084 case 11: /* set bell duration in msec */
1085 if (npar >= 1)
1086 bell_duration = (par[1] < 2000) ?
1087 par[1]*HZ/1000 : 0;
1088 else
1089 bell_duration = DEFAULT_BELL_DURATION;
1090 break;
1091 case 12: /* bring specified console to the front */
1092 if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
1093 update_screen(par[1]-1);
1094 break;
1095 case 13: /* unblank the screen */
1096 unblank_screen();
1097 break;
1098 case 14: /* set vesa powerdown interval */
1099 vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1100 break;
1104 static void insert_char(int currcons)
1106 unsigned int i = x;
1107 unsigned short tmp, old = video_erase_char;
1108 unsigned short * p = (unsigned short *) pos;
1110 while (i++ < video_num_columns) {
1111 tmp = scr_readw(p);
1112 scr_writew(old, p);
1113 old = tmp;
1114 p++;
1116 need_wrap = 0;
1119 static void insert_line(int currcons)
1121 scrdown(currcons,y,bottom);
1122 need_wrap = 0;
1125 static void delete_char(int currcons)
1127 unsigned int i = x;
1128 unsigned short * p = (unsigned short *) pos;
1130 while (++i < video_num_columns) {
1131 scr_writew(scr_readw(p+1), p);
1132 p++;
1134 scr_writew(video_erase_char, p);
1135 need_wrap = 0;
1138 static void delete_line(int currcons)
1140 scrup(currcons,y,bottom);
1141 need_wrap = 0;
1144 static void csi_at(int currcons, unsigned int nr)
1146 if (nr > video_num_columns)
1147 nr = video_num_columns;
1148 else if (!nr)
1149 nr = 1;
1150 while (nr--)
1151 insert_char(currcons);
1154 static void csi_L(int currcons, unsigned int nr)
1156 if (nr > video_num_lines)
1157 nr = video_num_lines;
1158 else if (!nr)
1159 nr = 1;
1160 while (nr--)
1161 insert_line(currcons);
1164 static void csi_P(int currcons, unsigned int nr)
1166 if (nr > video_num_columns)
1167 nr = video_num_columns;
1168 else if (!nr)
1169 nr = 1;
1170 while (nr--)
1171 delete_char(currcons);
1174 static void csi_M(int currcons, unsigned int nr)
1176 if (nr > video_num_lines)
1177 nr = video_num_lines;
1178 else if (!nr)
1179 nr=1;
1180 while (nr--)
1181 delete_line(currcons);
1184 static void save_cur(int currcons)
1186 saved_x = x;
1187 saved_y = y;
1188 s_intensity = intensity;
1189 s_underline = underline;
1190 s_blink = blink;
1191 s_reverse = reverse;
1192 s_charset = charset;
1193 s_color = color;
1194 saved_G0 = G0_charset;
1195 saved_G1 = G1_charset;
1198 static void restore_cur(int currcons)
1200 gotoxy(currcons,saved_x,saved_y);
1201 intensity = s_intensity;
1202 underline = s_underline;
1203 blink = s_blink;
1204 reverse = s_reverse;
1205 charset = s_charset;
1206 color = s_color;
1207 G0_charset = saved_G0;
1208 G1_charset = saved_G1;
1209 translate = set_translate(charset ? G1_charset : G0_charset);
1210 update_attr(currcons);
1211 need_wrap = 0;
1214 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
1215 EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
1216 ESpalette };
1218 static void reset_terminal(int currcons, int do_clear)
1220 top = 0;
1221 bottom = video_num_lines;
1222 vc_state = ESnormal;
1223 ques = 0;
1224 translate = set_translate(LAT1_MAP);
1225 G0_charset = LAT1_MAP;
1226 G1_charset = GRAF_MAP;
1227 charset = 0;
1228 need_wrap = 0;
1229 report_mouse = 0;
1230 utf = 0;
1231 utf_count = 0;
1233 disp_ctrl = 0;
1234 toggle_meta = 0;
1236 decscnm = 0;
1237 decom = 0;
1238 decawm = 1;
1239 deccm = 1;
1240 decim = 0;
1242 set_kbd(decarm);
1243 clr_kbd(decckm);
1244 clr_kbd(kbdapplic);
1245 clr_kbd(lnm);
1246 kbd_table[currcons].lockstate = 0;
1247 kbd_table[currcons].slockstate = 0;
1248 kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1249 kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1250 set_leds();
1252 default_attr(currcons);
1253 update_attr(currcons);
1255 tab_stop[0] = 0x01010100;
1256 tab_stop[1] =
1257 tab_stop[2] =
1258 tab_stop[3] =
1259 tab_stop[4] = 0x01010101;
1261 bell_pitch = DEFAULT_BELL_PITCH;
1262 bell_duration = DEFAULT_BELL_DURATION;
1264 gotoxy(currcons,0,0);
1265 save_cur(currcons);
1266 if (do_clear)
1267 csi_J(currcons,2);
1271 * Turn the Scroll-Lock LED on when the tty is stopped
1273 static void con_stop(struct tty_struct *tty)
1275 int console_num;
1276 if (!tty)
1277 return;
1278 console_num = MINOR(tty->device) - (tty->driver.minor_start);
1279 if (!vc_cons_allocated(console_num))
1280 return;
1281 #if !CONFIG_AP1000
1282 set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
1283 set_leds();
1284 #endif
1288 * Turn the Scroll-Lock LED off when the console is started
1290 static void con_start(struct tty_struct *tty)
1292 int console_num;
1293 if (!tty)
1294 return;
1295 console_num = MINOR(tty->device) - (tty->driver.minor_start);
1296 if (!vc_cons_allocated(console_num))
1297 return;
1298 #if !CONFIG_AP1000
1299 clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
1300 set_leds();
1301 #endif
1304 static void con_flush_chars(struct tty_struct *tty)
1306 unsigned int currcons;
1307 struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1309 currcons = vt->vc_num;
1310 if (vcmode != KD_GRAPHICS)
1311 set_cursor(currcons);
1314 static int do_con_write(struct tty_struct * tty, int from_user,
1315 const unsigned char *buf, int count)
1317 int c, tc, ok, n = 0;
1318 unsigned int currcons;
1319 struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1321 #if CONFIG_AP1000
1322 ap_write(1,buf,count);
1323 return(count);
1324 #endif
1326 currcons = vt->vc_num;
1327 if (!vc_cons_allocated(currcons)) {
1328 /* could this happen? */
1329 static int error = 0;
1330 if (!error) {
1331 error = 1;
1332 printk("con_write: tty %d not allocated\n", currcons+1);
1334 return 0;
1337 if (currcons == sel_cons)
1338 clear_selection();
1340 if (from_user) {
1341 /* just to make sure that noone lurks at places he shouldn't see. */
1342 if (verify_area(VERIFY_READ, buf, count))
1343 return 0; /* ?? are error codes legal here ?? */
1346 disable_bh(CONSOLE_BH);
1347 while (!tty->stopped && count) {
1348 enable_bh(CONSOLE_BH);
1349 if (from_user)
1350 __get_user(c, buf);
1351 else
1352 c = *buf;
1353 buf++; n++; count--;
1354 disable_bh(CONSOLE_BH);
1356 if (utf) {
1357 /* Combine UTF-8 into Unicode */
1358 /* Incomplete characters silently ignored */
1359 if(c > 0x7f) {
1360 if (utf_count > 0 && (c & 0xc0) == 0x80) {
1361 utf_char = (utf_char << 6) | (c & 0x3f);
1362 utf_count--;
1363 if (utf_count == 0)
1364 tc = c = utf_char;
1365 else continue;
1366 } else {
1367 if ((c & 0xe0) == 0xc0) {
1368 utf_count = 1;
1369 utf_char = (c & 0x1f);
1370 } else if ((c & 0xf0) == 0xe0) {
1371 utf_count = 2;
1372 utf_char = (c & 0x0f);
1373 } else if ((c & 0xf8) == 0xf0) {
1374 utf_count = 3;
1375 utf_char = (c & 0x07);
1376 } else if ((c & 0xfc) == 0xf8) {
1377 utf_count = 4;
1378 utf_char = (c & 0x03);
1379 } else if ((c & 0xfe) == 0xfc) {
1380 utf_count = 5;
1381 utf_char = (c & 0x01);
1382 } else
1383 utf_count = 0;
1384 continue;
1386 } else {
1387 tc = c;
1388 utf_count = 0;
1390 } else { /* no utf */
1391 tc = translate[toggle_meta ? (c|0x80) : c];
1394 /* If the original code was a control character we
1395 * only allow a glyph to be displayed if the code is
1396 * not normally used (such as for cursor movement) or
1397 * if the disp_ctrl mode has been explicitly enabled.
1398 * Certain characters (as given by the CTRL_ALWAYS
1399 * bitmap) are always displayed as control characters,
1400 * as the console would be pretty useless without
1401 * them; to display an arbitrary font position use the
1402 * direct-to-font zone in UTF-8 mode.
1404 ok = tc && (c >= 32 ||
1405 (!utf && !(((disp_ctrl ? CTRL_ALWAYS
1406 : CTRL_ACTION) >> c) & 1)))
1407 && (c != 127 || disp_ctrl)
1408 && (c != 128+27);
1410 if (vc_state == ESnormal && ok) {
1411 /* Now try to find out how to display it */
1412 tc = conv_uni_to_pc(tc);
1413 if ( tc == -4 ) {
1414 /* If we got -4 (not found) then see if we have
1415 defined a replacement character (U+FFFD) */
1416 tc = conv_uni_to_pc(0xfffd);
1417 } else if ( tc == -3 ) {
1418 /* Bad hash table -- hope for the best */
1419 tc = c;
1421 if (tc & ~console_charmask)
1422 continue; /* Conversion failed */
1424 if (need_wrap) {
1425 cr(currcons);
1426 lf(currcons);
1428 if (decim)
1429 insert_char(currcons);
1430 scr_writew( video_mode_512ch ?
1431 ((attr & 0xf7) << 8) + ((tc & 0x100) << 3) +
1432 (tc & 0x0ff) : (attr << 8) + tc,
1433 (unsigned short *) pos);
1434 if (x == video_num_columns - 1)
1435 need_wrap = decawm;
1436 else {
1437 x++;
1438 pos+=2;
1440 continue;
1444 * Control characters can be used in the _middle_
1445 * of an escape sequence.
1447 switch (c) {
1448 case 0:
1449 continue;
1450 case 7:
1451 if (bell_duration)
1452 kd_mksound(bell_pitch, bell_duration);
1453 continue;
1454 case 8:
1455 bs(currcons);
1456 continue;
1457 case 9:
1458 pos -= (x << 1);
1459 while (x < video_num_columns - 1) {
1460 x++;
1461 if (tab_stop[x >> 5] & (1 << (x & 31)))
1462 break;
1464 pos += (x << 1);
1465 continue;
1466 case 10: case 11: case 12:
1467 lf(currcons);
1468 if (!is_kbd(lnm))
1469 continue;
1470 case 13:
1471 cr(currcons);
1472 continue;
1473 case 14:
1474 charset = 1;
1475 translate = set_translate(G1_charset);
1476 disp_ctrl = 1;
1477 continue;
1478 case 15:
1479 charset = 0;
1480 translate = set_translate(G0_charset);
1481 disp_ctrl = 0;
1482 continue;
1483 case 24: case 26:
1484 vc_state = ESnormal;
1485 continue;
1486 case 27:
1487 vc_state = ESesc;
1488 continue;
1489 case 127:
1490 del(currcons);
1491 continue;
1492 case 128+27:
1493 vc_state = ESsquare;
1494 continue;
1496 switch(vc_state) {
1497 case ESesc:
1498 vc_state = ESnormal;
1499 switch (c) {
1500 case '[':
1501 vc_state = ESsquare;
1502 continue;
1503 case ']':
1504 vc_state = ESnonstd;
1505 continue;
1506 case '%':
1507 vc_state = ESpercent;
1508 continue;
1509 case 'E':
1510 cr(currcons);
1511 lf(currcons);
1512 continue;
1513 case 'M':
1514 ri(currcons);
1515 continue;
1516 case 'D':
1517 lf(currcons);
1518 continue;
1519 case 'H':
1520 tab_stop[x >> 5] |= (1 << (x & 31));
1521 continue;
1522 case 'Z':
1523 respond_ID(tty);
1524 continue;
1525 case '7':
1526 save_cur(currcons);
1527 continue;
1528 case '8':
1529 restore_cur(currcons);
1530 continue;
1531 case '(':
1532 vc_state = ESsetG0;
1533 continue;
1534 case ')':
1535 vc_state = ESsetG1;
1536 continue;
1537 case '#':
1538 vc_state = EShash;
1539 continue;
1540 case 'c':
1541 reset_terminal(currcons,1);
1542 continue;
1543 case '>': /* Numeric keypad */
1544 clr_kbd(kbdapplic);
1545 continue;
1546 case '=': /* Appl. keypad */
1547 set_kbd(kbdapplic);
1548 continue;
1550 continue;
1551 case ESnonstd:
1552 if (c=='P') { /* palette escape sequence */
1553 for (npar=0; npar<NPAR; npar++)
1554 par[npar] = 0 ;
1555 npar = 0 ;
1556 vc_state = ESpalette;
1557 continue;
1558 } else if (c=='R') { /* reset palette */
1559 reset_palette (currcons);
1560 vc_state = ESnormal;
1561 } else
1562 vc_state = ESnormal;
1563 continue;
1564 case ESpalette:
1565 if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
1566 par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
1567 if (npar==7) {
1568 int i = par[0]*3, j = 1;
1569 palette[i] = 16*par[j++];
1570 palette[i++] += par[j++];
1571 palette[i] = 16*par[j++];
1572 palette[i++] += par[j++];
1573 palette[i] = 16*par[j++];
1574 palette[i] += par[j];
1575 set_palette() ;
1576 vc_state = ESnormal;
1578 } else
1579 vc_state = ESnormal;
1580 continue;
1581 case ESsquare:
1582 for(npar = 0 ; npar < NPAR ; npar++)
1583 par[npar] = 0;
1584 npar = 0;
1585 vc_state = ESgetpars;
1586 if (c == '[') { /* Function key */
1587 vc_state=ESfunckey;
1588 continue;
1590 ques = (c=='?');
1591 if (ques)
1592 continue;
1593 case ESgetpars:
1594 if (c==';' && npar<NPAR-1) {
1595 npar++;
1596 continue;
1597 } else if (c>='0' && c<='9') {
1598 par[npar] *= 10;
1599 par[npar] += c-'0';
1600 continue;
1601 } else vc_state=ESgotpars;
1602 case ESgotpars:
1603 vc_state = ESnormal;
1604 switch(c) {
1605 case 'h':
1606 set_mode(currcons,1);
1607 continue;
1608 case 'l':
1609 set_mode(currcons,0);
1610 continue;
1611 case 'n':
1612 if (!ques)
1613 if (par[0] == 5)
1614 status_report(tty);
1615 else if (par[0] == 6)
1616 cursor_report(currcons,tty);
1617 continue;
1619 if (ques) {
1620 ques = 0;
1621 continue;
1623 switch(c) {
1624 case 'G': case '`':
1625 if (par[0]) par[0]--;
1626 gotoxy(currcons,par[0],y);
1627 continue;
1628 case 'A':
1629 if (!par[0]) par[0]++;
1630 gotoxy(currcons,x,y-par[0]);
1631 continue;
1632 case 'B': case 'e':
1633 if (!par[0]) par[0]++;
1634 gotoxy(currcons,x,y+par[0]);
1635 continue;
1636 case 'C': case 'a':
1637 if (!par[0]) par[0]++;
1638 gotoxy(currcons,x+par[0],y);
1639 continue;
1640 case 'D':
1641 if (!par[0]) par[0]++;
1642 gotoxy(currcons,x-par[0],y);
1643 continue;
1644 case 'E':
1645 if (!par[0]) par[0]++;
1646 gotoxy(currcons,0,y+par[0]);
1647 continue;
1648 case 'F':
1649 if (!par[0]) par[0]++;
1650 gotoxy(currcons,0,y-par[0]);
1651 continue;
1652 case 'd':
1653 if (par[0]) par[0]--;
1654 gotoxay(currcons,x,par[0]);
1655 continue;
1656 case 'H': case 'f':
1657 if (par[0]) par[0]--;
1658 if (par[1]) par[1]--;
1659 gotoxay(currcons,par[1],par[0]);
1660 continue;
1661 case 'J':
1662 csi_J(currcons,par[0]);
1663 continue;
1664 case 'K':
1665 csi_K(currcons,par[0]);
1666 continue;
1667 case 'L':
1668 csi_L(currcons,par[0]);
1669 continue;
1670 case 'M':
1671 csi_M(currcons,par[0]);
1672 continue;
1673 case 'P':
1674 csi_P(currcons,par[0]);
1675 continue;
1676 case 'c':
1677 if (!par[0])
1678 respond_ID(tty);
1679 continue;
1680 case 'g':
1681 if (!par[0])
1682 tab_stop[x >> 5] &= ~(1 << (x & 31));
1683 else if (par[0] == 3) {
1684 tab_stop[0] =
1685 tab_stop[1] =
1686 tab_stop[2] =
1687 tab_stop[3] =
1688 tab_stop[4] = 0;
1690 continue;
1691 case 'm':
1692 csi_m(currcons);
1693 continue;
1694 case 'q': /* DECLL - but only 3 leds */
1695 /* map 0,1,2,3 to 0,1,2,4 */
1696 if (par[0] < 4)
1697 setledstate(kbd_table + currcons,
1698 (par[0] < 3) ? par[0] : 4);
1699 continue;
1700 case 'r':
1701 if (!par[0])
1702 par[0]++;
1703 if (!par[1])
1704 par[1] = video_num_lines;
1705 /* Minimum allowed region is 2 lines */
1706 if (par[0] < par[1] &&
1707 par[1] <= video_num_lines) {
1708 top=par[0]-1;
1709 bottom=par[1];
1710 gotoxay(currcons,0,0);
1712 continue;
1713 case 's':
1714 save_cur(currcons);
1715 continue;
1716 case 'u':
1717 restore_cur(currcons);
1718 continue;
1719 case 'X':
1720 csi_X(currcons, par[0]);
1721 continue;
1722 case '@':
1723 csi_at(currcons,par[0]);
1724 continue;
1725 case ']': /* setterm functions */
1726 setterm_command(currcons);
1727 continue;
1729 continue;
1730 case ESpercent:
1731 vc_state = ESnormal;
1732 switch (c) {
1733 case '@': /* defined in ISO 2022 */
1734 utf = 0;
1735 continue;
1736 case 'G': /* prelim official escape code */
1737 case '8': /* retained for compatibility */
1738 utf = 1;
1739 continue;
1741 continue;
1742 case ESfunckey:
1743 vc_state = ESnormal;
1744 continue;
1745 case EShash:
1746 vc_state = ESnormal;
1747 if (c == '8') {
1748 /* DEC screen alignment test. kludge :-) */
1749 video_erase_char =
1750 (video_erase_char & 0xff00) | 'E';
1751 csi_J(currcons, 2);
1752 video_erase_char =
1753 (video_erase_char & 0xff00) | ' ';
1755 continue;
1756 case ESsetG0:
1757 if (c == '0')
1758 G0_charset = GRAF_MAP;
1759 else if (c == 'B')
1760 G0_charset = LAT1_MAP;
1761 else if (c == 'U')
1762 G0_charset = IBMPC_MAP;
1763 else if (c == 'K')
1764 G0_charset = USER_MAP;
1765 if (charset == 0)
1766 translate = set_translate(G0_charset);
1767 vc_state = ESnormal;
1768 continue;
1769 case ESsetG1:
1770 if (c == '0')
1771 G1_charset = GRAF_MAP;
1772 else if (c == 'B')
1773 G1_charset = LAT1_MAP;
1774 else if (c == 'U')
1775 G1_charset = IBMPC_MAP;
1776 else if (c == 'K')
1777 G1_charset = USER_MAP;
1778 if (charset == 1)
1779 translate = set_translate(G1_charset);
1780 vc_state = ESnormal;
1781 continue;
1782 default:
1783 vc_state = ESnormal;
1786 enable_bh(CONSOLE_BH);
1787 return n;
1790 static int con_write(struct tty_struct * tty, int from_user,
1791 const unsigned char *buf, int count)
1793 int retval;
1795 retval = do_con_write(tty, from_user, buf, count);
1796 con_flush_chars(tty);
1798 return retval;
1801 static void con_put_char(struct tty_struct *tty, unsigned char ch)
1803 do_con_write(tty, 0, &ch, 1);
1806 static int con_write_room(struct tty_struct *tty)
1808 if (tty->stopped)
1809 return 0;
1810 return 4096; /* No limit, really; we're not buffering */
1813 static int con_chars_in_buffer(struct tty_struct *tty)
1815 return 0; /* we're not buffering */
1818 void poke_blanked_console(void)
1820 timer_active &= ~(1<<BLANK_TIMER);
1821 if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
1822 return;
1823 if (console_blanked) {
1824 timer_table[BLANK_TIMER].fn = unblank_screen;
1825 timer_table[BLANK_TIMER].expires = 0;
1826 timer_active |= 1<<BLANK_TIMER;
1827 } else if (blankinterval) {
1828 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1829 timer_active |= 1<<BLANK_TIMER;
1833 #ifdef CONFIG_VT_CONSOLE
1834 void vt_console_print(const char * b, unsigned count)
1836 int currcons = fg_console;
1837 unsigned char c;
1838 static int printing = 0;
1840 #if CONFIG_AP1000
1841 prom_printf(b);
1842 return;
1843 #endif
1844 if (!printable || printing)
1845 return; /* console not yet initialized */
1846 printing = 1;
1848 if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
1849 currcons = kmsg_redirect - 1;
1851 if (!vc_cons_allocated(currcons)) {
1852 /* impossible */
1853 printk("vt_console_print: tty %d not allocated ??\n", currcons+1);
1854 return;
1857 while (count-- > 0) {
1858 c = *(b++);
1859 if (c == 10 || c == 13 || need_wrap) {
1860 if (c != 13)
1861 lf(currcons);
1862 cr(currcons);
1863 if (c == 10 || c == 13)
1864 continue;
1866 if (c == 8) { /* backspace */
1867 bs(currcons);
1868 continue;
1870 scr_writew((attr << 8) + c, (unsigned short *) pos);
1871 if (x == video_num_columns - 1) {
1872 need_wrap = 1;
1873 continue;
1875 x++;
1876 pos+=2;
1878 set_cursor(currcons);
1879 poke_blanked_console();
1880 printing = 0;
1883 static int vt_console_device(void)
1885 return MKDEV(TTY_MAJOR, fg_console + 1);
1888 extern void keyboard_wait_for_keypress(void);
1890 struct console vt_console_driver = {
1891 vt_console_print, do_unblank_screen,
1892 keyboard_wait_for_keypress, vt_console_device
1894 #endif
1897 * con_throttle and con_unthrottle are only used for
1898 * paste_selection(), which has to stuff in a large number of
1899 * characters...
1901 static void con_throttle(struct tty_struct *tty)
1905 static void con_unthrottle(struct tty_struct *tty)
1907 struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
1909 wake_up_interruptible(&vt->paste_wait);
1912 static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
1914 long base = (long) vc_scrbuf[currcons];
1915 int j, k ;
1917 video_num_columns = cols;
1918 video_num_lines = rows;
1919 video_size_row = cols<<1;
1920 video_screen_size = video_num_lines * video_size_row;
1922 pos = origin = video_mem_start = base;
1923 scr_end = base + video_screen_size;
1924 video_mem_end = base + video_screen_size;
1925 reset_vc(currcons);
1926 for (j=k=0; j<16; j++) {
1927 vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
1928 vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
1929 vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
1931 def_color = 0x07; /* white */
1932 ulcolor = 0x0f; /* bold white */
1933 halfcolor = 0x08; /* grey */
1934 vt_cons[currcons]->paste_wait = 0;
1935 reset_terminal(currcons, do_clear);
1938 static void con_setsize(unsigned long rows, unsigned long cols)
1940 video_num_lines = rows;
1941 video_num_columns = cols;
1942 video_size_row = 2 * cols;
1943 video_screen_size = video_num_lines * video_size_row;
1947 * This is the console switching bottom half handler.
1949 * Doing console switching in a bottom half handler allows
1950 * us to do the switches asynchronously (needed when we want
1951 * to switch due to a keyboard interrupt), while still giving
1952 * us the option to easily disable it to avoid races when we
1953 * need to write to the console.
1955 static void console_bh(void)
1957 if (want_console >= 0) {
1958 if (want_console != fg_console) {
1959 change_console(want_console);
1960 /* we only changed when the console had already
1961 been allocated - a new console is not created
1962 in an interrupt routine */
1964 want_console = -1;
1966 if (do_poke_blanked_console) { /* do not unblank for a LED change */
1967 do_poke_blanked_console = 0;
1968 poke_blanked_console();
1973 * unsigned long con_init(unsigned long);
1975 * This routine initializes console interrupts, and does nothing
1976 * else. If you want the screen to clear, call tty_write with
1977 * the appropriate escape-sequence.
1979 * Reads the information preserved by setup.s to determine the current display
1980 * type and sets everything accordingly.
1982 unsigned long con_init(unsigned long kmem_start)
1984 const char *display_desc = "????";
1985 int currcons = 0;
1986 int orig_x = ORIG_X;
1987 int orig_y = ORIG_Y;
1989 #ifdef __sparc__
1990 if (serial_console) {
1991 fg_console = 0;
1993 #if CONFIG_SUN_SERIAL
1994 rs_cons_hook(0, 0, serial_console);
1995 rs_cons_hook(0, 1, serial_console);
1996 #endif
1998 return kmem_start;
2000 #endif
2002 memset(&console_driver, 0, sizeof(struct tty_driver));
2003 console_driver.magic = TTY_DRIVER_MAGIC;
2004 console_driver.name = "tty";
2005 console_driver.name_base = 1;
2006 console_driver.major = TTY_MAJOR;
2007 console_driver.minor_start = 1;
2008 console_driver.num = MAX_NR_CONSOLES;
2009 console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
2010 console_driver.init_termios = tty_std_termios;
2011 console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2012 console_driver.refcount = &console_refcount;
2013 console_driver.table = console_table;
2014 console_driver.termios = console_termios;
2015 console_driver.termios_locked = console_termios_locked;
2017 console_driver.open = con_open;
2018 console_driver.write = con_write;
2019 console_driver.write_room = con_write_room;
2020 console_driver.put_char = con_put_char;
2021 console_driver.flush_chars = con_flush_chars;
2022 console_driver.chars_in_buffer = con_chars_in_buffer;
2023 console_driver.ioctl = vt_ioctl;
2024 console_driver.stop = con_stop;
2025 console_driver.start = con_start;
2026 console_driver.throttle = con_throttle;
2027 console_driver.unthrottle = con_unthrottle;
2029 if (tty_register_driver(&console_driver))
2030 panic("Couldn't register console driver\n");
2032 #if CONFIG_AP1000
2033 return(kmem_start);
2034 #endif
2035 con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
2037 timer_table[BLANK_TIMER].fn = blank_screen;
2038 timer_table[BLANK_TIMER].expires = 0;
2039 if (blankinterval) {
2040 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
2041 timer_active |= 1<<BLANK_TIMER;
2044 kmem_start = con_type_init(kmem_start, &display_desc);
2046 hardscroll_enabled = (hardscroll_disabled_by_init ? 0 :
2047 (video_type == VIDEO_TYPE_EGAC
2048 || video_type == VIDEO_TYPE_VGAC
2049 || video_type == VIDEO_TYPE_EGAM));
2050 has_wrapped = 0 ;
2052 /* Due to kmalloc roundup allocating statically is more efficient -
2053 so provide MIN_NR_CONSOLES for people with very little memory */
2054 for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2055 int j, k ;
2057 vc_cons[currcons].d = (struct vc_data *) kmem_start;
2058 kmem_start += sizeof(struct vc_data);
2059 vt_cons[currcons] = (struct vt_struct *) kmem_start;
2060 kmem_start += sizeof(struct vt_struct);
2061 vc_scrbuf[currcons] = (unsigned short *) kmem_start;
2062 kmem_start += video_screen_size;
2063 kmalloced = 0;
2064 screenbuf_size = video_screen_size;
2065 vc_init(currcons, video_num_lines, video_num_columns, currcons);
2066 for (j=k=0; j<16; j++) {
2067 vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
2068 vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
2069 vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
2073 currcons = fg_console = 0;
2075 video_mem_start = video_mem_base;
2076 video_mem_end = video_mem_term;
2077 origin = video_mem_start;
2078 scr_end = video_mem_start + video_num_lines * video_size_row;
2079 gotoxy(currcons,orig_x,orig_y);
2080 set_origin(currcons);
2081 csi_J(currcons, 0);
2083 /* Figure out the size of the screen and screen font so we
2084 can figure out the appropriate screen size should we load
2085 a different font */
2087 printable = 1;
2088 if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
2089 || video_type == VIDEO_TYPE_EGAM || video_type == VIDEO_TYPE_TGAC
2090 || video_type == VIDEO_TYPE_SUN )
2092 default_font_height = video_font_height = ORIG_VIDEO_POINTS;
2093 /* This may be suboptimal but is a safe bet - go with it */
2094 video_scan_lines = video_font_height * video_num_lines;
2096 printk("Console: %ld point font, %ld scans\n",
2097 video_font_height, video_scan_lines);
2100 printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
2101 can_do_color ? "colour" : "mono",
2102 display_desc, video_num_columns, video_num_lines,
2103 MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s",
2104 MAX_NR_CONSOLES);
2106 con_type_init_finish();
2109 * can't register TGA yet, because PCI bus probe has *not* taken
2110 * place before con_init() gets called. Trigger the real TGA hw
2111 * initialization and register_console() event from
2112 * within the bus probing code... :-(
2114 #ifdef CONFIG_VT_CONSOLE
2115 if (video_type != VIDEO_TYPE_TGAC)
2116 register_console(&vt_console_driver);
2117 #endif
2119 init_bh(CONSOLE_BH, console_bh);
2120 return kmem_start;
2123 void vesa_powerdown_screen(void)
2125 timer_active &= ~(1<<BLANK_TIMER);
2126 timer_table[BLANK_TIMER].fn = unblank_screen;
2128 vesa_powerdown();
2131 void do_blank_screen(int nopowersave)
2133 int currcons;
2135 if (console_blanked)
2136 return;
2138 if(vesa_off_interval && !nopowersave) {
2139 timer_table[BLANK_TIMER].fn = vesa_powerdown_screen;
2140 timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval;
2141 timer_active |= (1<<BLANK_TIMER);
2142 } else {
2143 timer_active &= ~(1<<BLANK_TIMER);
2144 timer_table[BLANK_TIMER].fn = unblank_screen;
2147 /* try not to lose information by blanking, and not to waste memory */
2148 currcons = fg_console;
2149 has_scrolled = 0;
2150 blank__origin = __origin;
2151 blank_origin = origin;
2152 set_origin(fg_console);
2153 get_scrmem(fg_console);
2154 unblank_origin = origin;
2155 memsetw((void *)blank_origin, BLANK,
2156 2*video_num_lines*video_num_columns);
2157 hide_cursor();
2158 console_blanked = fg_console + 1;
2160 if(!nopowersave)
2162 #ifdef CONFIG_APM
2163 if (apm_display_blank())
2164 return;
2165 #endif
2166 vesa_blank();
2170 void do_unblank_screen(void)
2172 int currcons;
2173 int resetorg;
2174 long offset;
2176 if (!console_blanked)
2177 return;
2178 if (!vc_cons_allocated(fg_console)) {
2179 /* impossible */
2180 printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2181 return;
2183 timer_table[BLANK_TIMER].fn = blank_screen;
2184 if (blankinterval) {
2185 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
2186 timer_active |= 1<<BLANK_TIMER;
2189 currcons = fg_console;
2190 offset = 0;
2191 resetorg = 0;
2192 if (console_blanked == fg_console + 1 && origin == unblank_origin
2193 && !has_scrolled) {
2194 /* try to restore the exact situation before blanking */
2195 resetorg = 1;
2196 offset = (blank_origin - video_mem_base)
2197 - (unblank_origin - video_mem_start);
2200 console_blanked = 0;
2201 set_scrmem(fg_console, offset);
2202 set_origin(fg_console);
2203 set_cursor(fg_console);
2204 if (resetorg)
2205 __set_origin(blank__origin);
2207 vesa_unblank();
2208 #ifdef CONFIG_APM
2209 if (apm_display_unblank())
2210 return;
2211 #endif
2215 * If a blank_screen is due to a timer, then a power save is allowed.
2216 * If it is related to console_switching, then avoid vesa_blank().
2218 static void blank_screen(void)
2220 do_blank_screen(0);
2223 static void unblank_screen(void)
2225 do_unblank_screen();
2228 void update_screen(int new_console)
2230 static int lock = 0;
2232 if (new_console == fg_console || lock)
2233 return;
2234 if (!vc_cons_allocated(new_console)) {
2235 /* strange ... */
2236 printk("update_screen: tty %d not allocated ??\n", new_console+1);
2237 return;
2239 lock = 1;
2241 clear_selection();
2243 if (!console_blanked)
2244 get_scrmem(fg_console);
2245 else
2246 console_blanked = -1; /* no longer of the form console+1 */
2247 fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
2248 /* consequently, fg_console will always be allocated */
2249 set_scrmem(fg_console, 0);
2250 set_origin(fg_console);
2251 set_cursor(fg_console);
2252 set_leds();
2253 compute_shiftstate();
2254 lock = 0;
2258 * Allocate the console screen memory.
2260 static int con_open(struct tty_struct *tty, struct file * filp)
2262 unsigned int idx;
2263 int i;
2265 idx = MINOR(tty->device) - tty->driver.minor_start;
2267 i = vc_allocate(idx);
2268 if (i)
2269 return i;
2271 vt_cons[idx]->vc_num = idx;
2272 tty->driver_data = vt_cons[idx];
2274 if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2275 tty->winsize.ws_row = video_num_lines;
2276 tty->winsize.ws_col = video_num_columns;
2278 return 0;
2283 * Load palette into the EGA/VGA DAC registers. arg points to a colour
2284 * map, 3 bytes per colour, 16 colours, range from 0 to 255.
2287 int con_set_cmap (unsigned char *arg)
2289 return set_get_cmap (arg,1);
2292 int con_get_cmap (unsigned char *arg)
2294 return set_get_cmap (arg,0);
2297 void reset_palette (int currcons)
2299 int j, k ;
2300 for (j=k=0; j<16; j++) {
2301 palette[k++] = default_red[j];
2302 palette[k++] = default_grn[j];
2303 palette[k++] = default_blu[j];
2305 set_palette() ;
2309 * Load font into the EGA/VGA character generator. arg points to a 8192
2310 * byte map, 32 bytes per character. Only first H of them are used for
2311 * 8xH fonts (0 < H <= 32).
2314 int con_set_font (char *arg, int ch512)
2316 int i;
2318 i = set_get_font (arg,1,ch512);
2319 if ( !i ) {
2320 hashtable_contents_valid = 0;
2321 video_mode_512ch = ch512;
2322 console_charmask = ch512 ? 0x1ff : 0x0ff;
2324 return i;
2327 int con_get_font (char *arg)
2329 return set_get_font (arg,0,video_mode_512ch);