* add p cc
[mascara-docs.git] / i386 / linux / linux-0.99 / drivers / char / console.c
bloba22889856a7a7ff003e4fa071ac6dc6e3217ee1b
1 /*
2 * linux/kernel/console.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
7 /*
8 * console.c
10 * This module exports the console io functions:
12 * 'long con_init(long)'
13 * 'int con_open(struct tty_struct *tty, struct file * filp)'
14 * 'void update_screen(int new_console)'
15 * 'void blank_screen(void)'
16 * 'void unblank_screen(void)'
18 * 'int con_get_font(char *)'
19 * 'int con_set_font(char *)'
20 * 'int con_get_trans(char *)'
21 * 'int con_set_trans(char *)'
23 * Hopefully this will be a rather complete VT102 implementation.
25 * Beeping thanks to John T Kohl.
27 * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
28 * Chars, and VT100 enhancements by Peter MacDonald.
30 * Copy and paste function by Andrew Haylett.
32 * User definable mapping table and font loading by Eugene G. Crosser,
33 * <crosser@pccross.msk.su>
35 * Code to check for different video-cards mostly by Galen Hunt,
36 * <g-hunt@ee.utah.edu>
40 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
43 * NOTE!!! We sometimes disable and enable interrupts for a short while
44 * (to put a word in video IO), but this will work even for keyboard
45 * interrupts. We know interrupts aren't enabled when getting a keyboard
46 * interrupt, as we use trap-gates. Hopefully all is well.
49 #include <linux/sched.h>
50 #include <linux/timer.h>
51 #include <linux/tty.h>
52 #include <linux/config.h>
53 #include <linux/kernel.h>
54 #include <linux/string.h>
55 #include <linux/errno.h>
56 #include <linux/kd.h>
58 #include <asm/io.h>
59 #include <asm/system.h>
60 #include <asm/segment.h>
62 #include "kbd_kern.h"
63 #include "vt_kern.h"
65 #ifdef CONFIG_SELECTION
66 #include <linux/ctype.h>
68 /* Routines for selection control. */
69 int set_selection(const int arg);
70 int paste_selection(struct tty_struct *tty);
71 static void clear_selection(void);
73 /* Variables for selection control. */
74 #define SEL_BUFFER_SIZE TTY_BUF_SIZE
75 static int sel_cons;
76 static int sel_start = -1;
77 static int sel_end;
78 static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
79 #endif /* CONFIG_SELECTION */
81 #define NPAR 16
83 extern void vt_init(void);
84 extern void register_console(void (*proc)(const char *));
85 extern void compute_shiftstate(void);
87 unsigned long video_num_columns; /* Number of text columns */
88 unsigned long video_num_lines; /* Number of text lines */
90 static unsigned char video_type; /* Type of display being used */
91 static unsigned long video_mem_base; /* Base of video memory */
92 static unsigned long video_mem_term; /* End of video memory */
93 static unsigned long video_size_row; /* Bytes per row */
94 static unsigned char video_page; /* Initial video page */
95 static unsigned short video_port_reg; /* Video register select port */
96 static unsigned short video_port_val; /* Video register value port */
97 static int can_do_color = 0;
98 static int printable = 0;
100 static struct {
101 unsigned short vc_video_erase_char; /* Background erase character */
102 unsigned char vc_attr; /* Current attributes */
103 unsigned char vc_def_color; /* Default colors */
104 unsigned char vc_color; /* Foreground & background */
105 unsigned char vc_s_color; /* Saved foreground & background */
106 unsigned char vc_ulcolor; /* Colour for underline mode */
107 unsigned char vc_halfcolor; /* Colour for half intensity mode */
108 unsigned long vc_origin; /* Used for EGA/VGA fast scroll */
109 unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */
110 unsigned long vc_pos;
111 unsigned long vc_x,vc_y;
112 unsigned long vc_top,vc_bottom;
113 unsigned long vc_state;
114 unsigned long vc_npar,vc_par[NPAR];
115 unsigned long vc_video_mem_start; /* Start of video RAM */
116 unsigned long vc_video_mem_end; /* End of video RAM (sort of) */
117 unsigned long vc_saved_x;
118 unsigned long vc_saved_y;
119 /* mode flags */
120 unsigned long vc_charset : 1; /* Character set G0 / G1 */
121 unsigned long vc_s_charset : 1; /* Saved character set */
122 unsigned long vc_decscnm : 1; /* Screen Mode */
123 unsigned long vc_decom : 1; /* Origin Mode */
124 unsigned long vc_decawm : 1; /* Autowrap Mode */
125 unsigned long vc_deccm : 1; /* Cursor Visible */
126 unsigned long vc_decim : 1; /* Insert Mode */
127 /* attribute flags */
128 unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
129 unsigned long vc_underline : 1;
130 unsigned long vc_blink : 1;
131 unsigned long vc_reverse : 1;
132 unsigned long vc_s_intensity : 2; /* saved rendition */
133 unsigned long vc_s_underline : 1;
134 unsigned long vc_s_blink : 1;
135 unsigned long vc_s_reverse : 1;
136 /* misc */
137 unsigned long vc_ques : 1;
138 unsigned long vc_need_wrap : 1;
139 unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
140 unsigned char * vc_translate;
141 unsigned char * vc_G0_charset;
142 unsigned char * vc_G1_charset;
143 unsigned char * vc_saved_G0;
144 unsigned char * vc_saved_G1;
145 /* additional information is in vt_kern.h */
146 } vc_cons [NR_CONSOLES];
148 unsigned short *vc_scrbuf[NR_CONSOLES];
149 static unsigned short * vc_scrmembuf;
150 static int console_blanked = 0;
152 #define origin (vc_cons[currcons].vc_origin)
153 #define scr_end (vc_cons[currcons].vc_scr_end)
154 #define pos (vc_cons[currcons].vc_pos)
155 #define top (vc_cons[currcons].vc_top)
156 #define bottom (vc_cons[currcons].vc_bottom)
157 #define x (vc_cons[currcons].vc_x)
158 #define y (vc_cons[currcons].vc_y)
159 #define state (vc_cons[currcons].vc_state)
160 #define npar (vc_cons[currcons].vc_npar)
161 #define par (vc_cons[currcons].vc_par)
162 #define ques (vc_cons[currcons].vc_ques)
163 #define attr (vc_cons[currcons].vc_attr)
164 #define saved_x (vc_cons[currcons].vc_saved_x)
165 #define saved_y (vc_cons[currcons].vc_saved_y)
166 #define translate (vc_cons[currcons].vc_translate)
167 #define G0_charset (vc_cons[currcons].vc_G0_charset)
168 #define G1_charset (vc_cons[currcons].vc_G1_charset)
169 #define saved_G0 (vc_cons[currcons].vc_saved_G0)
170 #define saved_G1 (vc_cons[currcons].vc_saved_G1)
171 #define video_mem_start (vc_cons[currcons].vc_video_mem_start)
172 #define video_mem_end (vc_cons[currcons].vc_video_mem_end)
173 #define video_erase_char (vc_cons[currcons].vc_video_erase_char)
174 #define decscnm (vc_cons[currcons].vc_decscnm)
175 #define decom (vc_cons[currcons].vc_decom)
176 #define decawm (vc_cons[currcons].vc_decawm)
177 #define deccm (vc_cons[currcons].vc_deccm)
178 #define decim (vc_cons[currcons].vc_decim)
179 #define need_wrap (vc_cons[currcons].vc_need_wrap)
180 #define color (vc_cons[currcons].vc_color)
181 #define s_color (vc_cons[currcons].vc_s_color)
182 #define def_color (vc_cons[currcons].vc_def_color)
183 #define foreground (color & 0x0f)
184 #define background (color & 0xf0)
185 #define charset (vc_cons[currcons].vc_charset)
186 #define s_charset (vc_cons[currcons].vc_s_charset)
187 #define intensity (vc_cons[currcons].vc_intensity)
188 #define underline (vc_cons[currcons].vc_underline)
189 #define blink (vc_cons[currcons].vc_blink)
190 #define reverse (vc_cons[currcons].vc_reverse)
191 #define s_intensity (vc_cons[currcons].vc_s_intensity)
192 #define s_underline (vc_cons[currcons].vc_s_underline)
193 #define s_blink (vc_cons[currcons].vc_s_blink)
194 #define s_reverse (vc_cons[currcons].vc_s_reverse)
195 #define ulcolor (vc_cons[currcons].vc_ulcolor)
196 #define halfcolor (vc_cons[currcons].vc_halfcolor)
197 #define tab_stop (vc_cons[currcons].vc_tab_stop)
198 #define vcmode (vt_cons[currcons].vc_mode)
199 #define vtmode (vt_cons[currcons].vt_mode)
200 #define vtpid (vt_cons[currcons].vt_pid)
201 #define vtnewvt (vt_cons[currcons].vt_newvt)
203 #define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
204 #define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
205 #define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
207 #define decarm VC_REPEAT
208 #define decckm VC_CKMODE
209 #define kbdapplic VC_APPLIC
210 #define kbdraw VC_RAW
211 #define lnm VC_CRLF
213 int blankinterval = 10*60*HZ;
214 static int screen_size = 0;
217 * this is what the terminal answers to a ESC-Z or csi0c query.
219 #define VT100ID "\033[?1;2c"
220 #define VT102ID "\033[?6c"
222 static unsigned char * translations[] = {
223 /* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */
224 (unsigned char *)
225 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
226 "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
227 " !\"#$%&'()*+,-./0123456789:;<=>?"
228 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
229 "`abcdefghijklmnopqrstuvwxyz{|}~\0"
230 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
231 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
232 "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
233 "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
234 "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
235 "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
236 "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
237 "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
238 /* vt100 graphics */
239 (unsigned char *)
240 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
241 "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
242 " !\"#$%&'()*+,-./0123456789:;<=>?"
243 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
244 "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
245 "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
246 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
247 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
248 "\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
249 "\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
250 "\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
251 "\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
252 "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
253 "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
254 /* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
255 (unsigned char *)
256 "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
257 "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
258 "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
259 "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
260 "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
261 "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
262 "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
263 "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
264 "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
265 "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
266 "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
267 "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
268 "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
269 "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
270 "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
271 "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
272 /* USER: customizable mappings, initialized as the previous one (IBM) */
273 (unsigned char *)
274 "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017"
275 "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
276 "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
277 "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
278 "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
279 "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
280 "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
281 "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
282 "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
283 "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
284 "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
285 "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
286 "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
287 "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
288 "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
289 "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
292 #define NORM_TRANS (translations[0])
293 #define GRAF_TRANS (translations[1])
294 #define NULL_TRANS (translations[2])
295 #define USER_TRANS (translations[3])
297 static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
298 8,12,10,14, 9,13,11,15 };
301 * gotoxy() must verify all boundaries, because the arguments
302 * might also be negative. If the given position is out of
303 * bounds, the cursor is placed at the nearest margin.
305 static void gotoxy(int currcons, int new_x, int new_y)
307 int max_y;
309 if (new_x < 0)
310 x = 0;
311 else
312 if (new_x >= video_num_columns)
313 x = video_num_columns - 1;
314 else
315 x = new_x;
316 if (decom) {
317 new_y += top;
318 max_y = bottom;
319 } else
320 max_y = video_num_lines;
321 if (new_y < 0)
322 y = 0;
323 else
324 if (new_y >= max_y)
325 y = max_y - 1;
326 else
327 y = new_y;
328 pos = origin + y*video_size_row + (x<<1);
329 need_wrap = 0;
333 * *Very* limited hardware scrollback support..
335 static unsigned short __real_origin;
336 static unsigned short __origin;
338 static inline void __set_origin(unsigned short offset)
340 unsigned long flags;
341 #ifdef CONFIG_SELECTION
342 clear_selection();
343 #endif /* CONFIG_SELECTION */
344 save_flags(flags); cli();
345 __origin = offset;
346 outb_p(12, video_port_reg);
347 outb_p(offset >> 8, video_port_val);
348 outb_p(13, video_port_reg);
349 outb_p(offset, video_port_val);
350 restore_flags(flags);
353 void scrollback(int lines)
355 if (!lines)
356 lines = video_num_lines/2;
357 lines *= video_num_columns;
358 lines = __origin - lines;
359 if (lines < 0)
360 lines = 0;
361 __set_origin(lines);
364 void scrollfront(int lines)
366 if (!lines)
367 lines = video_num_lines/2;
368 lines *= video_num_columns;
369 lines = __origin + lines;
370 if (lines > __real_origin)
371 lines = __real_origin;
372 __set_origin(lines);
375 static void set_origin(int currcons)
377 if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
378 return;
379 if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
380 return;
381 __real_origin = (origin-video_mem_base) >> 1;
382 __set_origin(__real_origin);
385 static inline void hide_cursor(int currcons)
387 outb_p(14, video_port_reg);
388 outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
389 outb_p(15, video_port_reg);
390 outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
393 static inline void set_cursor(int currcons)
395 unsigned long flags;
397 if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
398 return;
399 if (__real_origin != __origin)
400 set_origin(__real_origin);
401 save_flags(flags); cli();
402 if (deccm) {
403 outb_p(14, video_port_reg);
404 outb_p(0xff&((pos-video_mem_base)>>9), video_port_val);
405 outb_p(15, video_port_reg);
406 outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
407 } else
408 hide_cursor(currcons);
409 restore_flags(flags);
412 static void scrup(int currcons, unsigned int t, unsigned int b)
414 int hardscroll = 1;
416 if (b > video_num_lines || t >= b)
417 return;
418 if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
419 hardscroll = 0;
420 else if (t || b != video_num_lines)
421 hardscroll = 0;
422 if (hardscroll) {
423 origin += video_size_row;
424 pos += video_size_row;
425 scr_end += video_size_row;
426 if (scr_end > video_mem_end) {
427 __asm__("cld\n\t"
428 "rep\n\t"
429 "movsl\n\t"
430 "movl _video_num_columns,%1\n\t"
431 "rep\n\t"
432 "stosw"
433 : /* no output */
434 :"a" (video_erase_char),
435 "c" ((video_num_lines-1)*video_num_columns>>1),
436 "D" (video_mem_start),
437 "S" (origin)
438 :"cx","di","si");
439 scr_end -= origin-video_mem_start;
440 pos -= origin-video_mem_start;
441 origin = video_mem_start;
442 } else {
443 __asm__("cld\n\t"
444 "rep\n\t"
445 "stosw"
446 : /* no output */
447 :"a" (video_erase_char),
448 "c" (video_num_columns),
449 "D" (scr_end-video_size_row)
450 :"cx","di");
452 set_origin(currcons);
453 } else {
454 __asm__("cld\n\t"
455 "rep\n\t"
456 "movsl\n\t"
457 "movl _video_num_columns,%%ecx\n\t"
458 "rep\n\t"
459 "stosw"
460 : /* no output */
461 :"a" (video_erase_char),
462 "c" ((b-t-1)*video_num_columns>>1),
463 "D" (origin+video_size_row*t),
464 "S" (origin+video_size_row*(t+1))
465 :"cx","di","si");
469 static void scrdown(int currcons, unsigned int t, unsigned int b)
471 if (b > video_num_lines || t >= b)
472 return;
473 __asm__("std\n\t"
474 "rep\n\t"
475 "movsl\n\t"
476 "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
477 "movl _video_num_columns,%%ecx\n\t"
478 "rep\n\t"
479 "stosw\n\t"
480 "cld"
481 : /* no output */
482 :"a" (video_erase_char),
483 "c" ((b-t-1)*video_num_columns>>1),
484 "D" (origin+video_size_row*b-4),
485 "S" (origin+video_size_row*(b-1)-4)
486 :"ax","cx","di","si");
489 static void lf(int currcons)
491 if (y+1<bottom) {
492 y++;
493 pos += video_size_row;
494 return;
495 } else
496 scrup(currcons,top,bottom);
497 need_wrap = 0;
500 static void ri(int currcons)
502 if (y>top) {
503 y--;
504 pos -= video_size_row;
505 return;
506 } else
507 scrdown(currcons,top,bottom);
508 need_wrap = 0;
511 static inline void cr(int currcons)
513 pos -= x<<1;
514 need_wrap = x = 0;
517 static inline void bs(int currcons)
519 if (x) {
520 pos -= 2;
521 x--;
522 need_wrap = 0;
526 static inline void del(int currcons)
528 #if 0
529 if (x) {
530 if (!need_wrap) { /* this is not the right condition */
531 pos -= 2;
532 x--;
534 *(unsigned short *)pos = video_erase_char;
535 need_wrap = 0;
537 #endif
540 static void csi_J(int currcons, int vpar)
542 unsigned long count;
543 unsigned long start;
545 switch (vpar) {
546 case 0: /* erase from cursor to end of display */
547 count = (scr_end-pos)>>1;
548 start = pos;
549 break;
550 case 1: /* erase from start to cursor */
551 count = ((pos-origin)>>1)+1;
552 start = origin;
553 break;
554 case 2: /* erase whole display */
555 count = video_num_columns * video_num_lines;
556 start = origin;
557 break;
558 default:
559 return;
561 __asm__("cld\n\t"
562 "rep\n\t"
563 "stosw\n\t"
564 : /* no output */
565 :"c" (count),
566 "D" (start),"a" (video_erase_char)
567 :"cx","di");
568 need_wrap = 0;
571 static void csi_K(int currcons, int vpar)
573 long count;
574 long start;
576 switch (vpar) {
577 case 0: /* erase from cursor to end of line */
578 count = video_num_columns-x;
579 start = pos;
580 break;
581 case 1: /* erase from start of line to cursor */
582 start = pos - (x<<1);
583 count = x+1;
584 break;
585 case 2: /* erase whole line */
586 start = pos - (x<<1);
587 count = video_num_columns;
588 break;
589 default:
590 return;
592 __asm__("cld\n\t"
593 "rep\n\t"
594 "stosw\n\t"
595 : /* no output */
596 :"c" (count),
597 "D" (start),"a" (video_erase_char)
598 :"cx","di");
599 need_wrap = 0;
603 * I hope this works. The monochrome part is untested.
605 static void update_attr(int currcons)
607 attr = color;
608 if (can_do_color) {
609 if (underline)
610 attr = (attr & 0xf0) | ulcolor;
611 else if (intensity == 0)
612 attr = (attr & 0xf0) | halfcolor;
614 if (reverse ^ decscnm)
615 attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77);
616 if (blink)
617 attr ^= 0x80;
618 if (intensity == 2)
619 attr ^= 0x08;
620 if (!can_do_color) {
621 if (underline)
622 attr = (attr & 0xf8) | 0x01;
623 else if (intensity == 0)
624 attr = (attr & 0xf0) | 0x08;
626 if (decscnm)
627 video_erase_char = (((color & 0x88) | (((color >> 4) | (color << 4)) & 0x77)) << 8) | ' ';
628 else
629 video_erase_char = (color << 8) | ' ';
632 static void default_attr(int currcons)
634 intensity = 1;
635 underline = 0;
636 reverse = 0;
637 blink = 0;
638 color = def_color;
641 static void csi_m(int currcons)
643 int i;
645 for (i=0;i<=npar;i++)
646 switch (par[i]) {
647 case 0: /* all attributes off */
648 default_attr(currcons);
649 break;
650 case 1:
651 intensity = 2;
652 break;
653 case 2:
654 intensity = 0;
655 break;
656 case 4:
657 underline = 1;
658 break;
659 case 5:
660 blink = 1;
661 break;
662 case 7:
663 reverse = 1;
664 break;
665 case 21:
666 case 22:
667 intensity = 1;
668 break;
669 case 24:
670 underline = 0;
671 break;
672 case 25:
673 blink = 0;
674 break;
675 case 27:
676 reverse = 0;
677 break;
678 case 39:
679 color = (def_color & 0x0f) | background;
680 break;
681 case 49:
682 color = (def_color & 0xf0) | foreground;
683 break;
684 default:
685 if (par[i] >= 30 && par[i] <= 37)
686 color = color_table[par[i]-30]
687 | background;
688 else if (par[i] >= 40 && par[i] <= 47)
689 color = (color_table[par[i]-40]<<4)
690 | foreground;
691 break;
693 update_attr(currcons);
696 static void respond_string(char * p, int currcons, struct tty_struct * tty)
698 while (*p) {
699 put_tty_queue(*p, &tty->read_q);
700 p++;
702 TTY_READ_FLUSH(tty);
705 static void respond_num(unsigned int n, int currcons, struct tty_struct * tty)
707 char buff[3];
708 int i = 0;
710 do {
711 buff[i++] = (n%10)+'0';
712 n /= 10;
713 } while(n && i < 3); /* We'll take no chances */
714 while (i--) {
715 put_tty_queue(buff[i], &tty->read_q);
717 /* caller must flush */
720 static void cursor_report(int currcons, struct tty_struct * tty)
722 put_tty_queue('\033', &tty->read_q);
723 put_tty_queue('[', &tty->read_q);
724 respond_num(y + (decom ? top+1 : 1), currcons, tty);
725 put_tty_queue(';', &tty->read_q);
726 respond_num(x+1, currcons, tty);
727 put_tty_queue('R', &tty->read_q);
728 TTY_READ_FLUSH(tty);
731 static inline void status_report(int currcons, struct tty_struct * tty)
733 respond_string("\033[0n", currcons, tty); /* Terminal ok */
736 static inline void respond_ID(int currcons, struct tty_struct * tty)
738 respond_string(VT102ID, currcons, tty);
741 static void invert_screen(int currcons) {
742 unsigned char *p;
744 if (can_do_color)
745 for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
746 *p = (*p & 0x88) | (((*p >> 4) | (*p << 4)) & 0x77);
747 else
748 for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2)
749 *p ^= *p & 0x07 == 1 ? 0x70 : 0x77;
752 static void set_mode(int currcons, int on_off)
754 int i;
756 for (i=0; i<=npar; i++)
757 if (ques) switch(par[i]) { /* DEC private modes set/reset */
758 case 1: /* Cursor keys send ^[Ox/^[[x */
759 if (on_off)
760 set_kbd(decckm);
761 else
762 clr_kbd(decckm);
763 break;
764 case 3: /* 80/132 mode switch unimplemented */
765 csi_J(currcons,2);
766 gotoxy(currcons,0,0);
767 break;
768 case 5: /* Inverted screen on/off */
769 if (decscnm != on_off) {
770 decscnm = on_off;
771 invert_screen(currcons);
772 update_attr(currcons);
774 break;
775 case 6: /* Origin relative/absolute */
776 decom = on_off;
777 gotoxy(currcons,0,0);
778 break;
779 case 7: /* Autowrap on/off */
780 decawm = on_off;
781 break;
782 case 8: /* Autorepeat on/off */
783 if (on_off)
784 set_kbd(decarm);
785 else
786 clr_kbd(decarm);
787 break;
788 case 25: /* Cursor on/off */
789 deccm = on_off;
790 set_cursor(currcons);
791 break;
792 } else switch(par[i]) { /* ANSI modes set/reset */
793 case 4: /* Insert Mode on/off */
794 decim = on_off;
795 break;
796 case 20: /* Lf, Enter == CrLf/Lf */
797 if (on_off)
798 set_kbd(lnm);
799 else
800 clr_kbd(lnm);
801 break;
805 static void setterm_command(int currcons)
807 switch(par[0]) {
808 case 1: /* set color for underline mode */
809 if (can_do_color && par[1] < 16) {
810 ulcolor = color_table[par[1]];
811 if (underline)
812 update_attr(currcons);
814 break;
815 case 2: /* set color for half intensity mode */
816 if (can_do_color && par[1] < 16) {
817 halfcolor = color_table[par[1]];
818 if (intensity == 0)
819 update_attr(currcons);
821 break;
822 case 8: /* store colors as defaults */
823 def_color = attr;
824 default_attr(currcons);
825 update_attr(currcons);
826 break;
827 case 9: /* set blanking interval */
828 blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
829 break;
833 static void insert_char(int currcons)
835 unsigned int i = x;
836 unsigned short tmp, old = video_erase_char;
837 unsigned short * p = (unsigned short *) pos;
839 while (i++ < video_num_columns) {
840 tmp = *p;
841 *p = old;
842 old = tmp;
843 p++;
845 need_wrap = 0;
848 static void insert_line(int currcons)
850 scrdown(currcons,y,bottom);
851 need_wrap = 0;
854 static void delete_char(int currcons)
856 unsigned int i = x;
857 unsigned short * p = (unsigned short *) pos;
859 while (++i < video_num_columns) {
860 *p = *(p+1);
861 p++;
863 *p = video_erase_char;
864 need_wrap = 0;
867 static void delete_line(int currcons)
869 scrup(currcons,y,bottom);
870 need_wrap = 0;
873 static void csi_at(int currcons, unsigned int nr)
875 if (nr > video_num_columns)
876 nr = video_num_columns;
877 else if (!nr)
878 nr = 1;
879 while (nr--)
880 insert_char(currcons);
883 static void csi_L(int currcons, unsigned int nr)
885 if (nr > video_num_lines)
886 nr = video_num_lines;
887 else if (!nr)
888 nr = 1;
889 while (nr--)
890 insert_line(currcons);
893 static void csi_P(int currcons, unsigned int nr)
895 if (nr > video_num_columns)
896 nr = video_num_columns;
897 else if (!nr)
898 nr = 1;
899 while (nr--)
900 delete_char(currcons);
903 static void csi_M(int currcons, unsigned int nr)
905 if (nr > video_num_lines)
906 nr = video_num_lines;
907 else if (!nr)
908 nr=1;
909 while (nr--)
910 delete_line(currcons);
913 static void save_cur(int currcons)
915 saved_x = x;
916 saved_y = y;
917 s_intensity = intensity;
918 s_underline = underline;
919 s_blink = blink;
920 s_reverse = reverse;
921 s_charset = charset;
922 s_color = color;
923 saved_G0 = G0_charset;
924 saved_G1 = G1_charset;
927 static void restore_cur(int currcons)
929 gotoxy(currcons,saved_x,saved_y);
930 intensity = s_intensity;
931 underline = s_underline;
932 blink = s_blink;
933 reverse = s_reverse;
934 charset = s_charset;
935 color = s_color;
936 G0_charset = saved_G0;
937 G1_charset = saved_G1;
938 translate = charset ? G1_charset : G0_charset;
939 update_attr(currcons);
940 need_wrap = 0;
943 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
944 EShash, ESsetG0, ESsetG1, ESignore };
946 static void reset_terminal(int currcons, int do_clear)
948 top = 0;
949 bottom = video_num_lines;
950 state = ESnormal;
951 ques = 0;
952 translate = NORM_TRANS;
953 G0_charset = NORM_TRANS;
954 G1_charset = GRAF_TRANS;
955 charset = 0;
956 need_wrap = 0;
958 decscnm = 0;
959 decom = 0;
960 decawm = 1;
961 deccm = 1;
962 decim = 0;
964 set_kbd(decarm);
965 clr_kbd(decckm);
966 clr_kbd(kbdapplic);
967 clr_kbd(lnm);
968 kbd_table[currcons].lockstate = 0;
969 kbd_table[currcons].ledstate = kbd_table[currcons].default_ledstate;
970 set_leds();
972 default_attr(currcons);
973 update_attr(currcons);
975 tab_stop[0] = 0x01010100;
976 tab_stop[1] =
977 tab_stop[2] =
978 tab_stop[3] =
979 tab_stop[4] = 0x01010101;
981 if (do_clear) {
982 gotoxy(currcons,0,0);
983 csi_J(currcons,2);
984 save_cur(currcons);
988 void con_write(struct tty_struct * tty)
990 int c;
991 unsigned int currcons;
993 currcons = tty->line - 1;
994 if (currcons >= NR_CONSOLES) {
995 printk("con_write: illegal tty (%d)\n", currcons);
996 return;
998 #ifdef CONFIG_SELECTION
999 /* clear the selection as soon as any characters are to be written
1000 out on the console holding the selection. */
1001 if (!EMPTY(&tty->write_q) && currcons == sel_cons)
1002 clear_selection();
1003 #endif /* CONFIG_SELECTION */
1004 disable_bh(KEYBOARD_BH);
1005 while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) {
1006 if (state == ESnormal && translate[c]) {
1007 if (need_wrap) {
1008 cr(currcons);
1009 lf(currcons);
1011 if (decim)
1012 insert_char(currcons);
1013 c = translate[c];
1014 *(unsigned short *) pos = (attr << 8) + c;
1015 if (x == video_num_columns - 1)
1016 need_wrap = decawm;
1017 else {
1018 x++;
1019 pos+=2;
1021 continue;
1025 * Control characters can be used in the _middle_
1026 * of an escape sequence.
1028 switch (c) {
1029 case 7:
1030 kd_mksound(0x637, HZ/8);
1031 continue;
1032 case 8:
1033 bs(currcons);
1034 continue;
1035 case 9:
1036 pos -= (x << 1);
1037 while (x < video_num_columns - 1) {
1038 x++;
1039 if (tab_stop[x >> 5] & (1 << (x & 31)))
1040 break;
1042 pos += (x << 1);
1043 continue;
1044 case 10: case 11: case 12:
1045 lf(currcons);
1046 if (!is_kbd(lnm))
1047 continue;
1048 case 13:
1049 cr(currcons);
1050 continue;
1051 case 14:
1052 charset = 1;
1053 translate = G1_charset;
1054 continue;
1055 case 15:
1056 charset = 0;
1057 translate = G0_charset;
1058 continue;
1059 case 24: case 26:
1060 state = ESnormal;
1061 continue;
1062 case 27:
1063 state = ESesc;
1064 continue;
1065 case 127:
1066 del(currcons);
1067 continue;
1068 case 128+27:
1069 state = ESsquare;
1070 continue;
1072 switch(state) {
1073 case ESesc:
1074 state = ESnormal;
1075 switch (c) {
1076 case '[':
1077 state = ESsquare;
1078 continue;
1079 case 'E':
1080 cr(currcons);
1081 lf(currcons);
1082 continue;
1083 case 'M':
1084 ri(currcons);
1085 continue;
1086 case 'D':
1087 lf(currcons);
1088 continue;
1089 case 'H':
1090 tab_stop[x >> 5] |= (1 << (x & 31));
1091 continue;
1092 case 'Z':
1093 respond_ID(currcons,tty);
1094 continue;
1095 case '7':
1096 save_cur(currcons);
1097 continue;
1098 case '8':
1099 restore_cur(currcons);
1100 continue;
1101 case '(':
1102 state = ESsetG0;
1103 continue;
1104 case ')':
1105 state = ESsetG1;
1106 continue;
1107 case '#':
1108 state = EShash;
1109 continue;
1110 case 'c':
1111 reset_terminal(currcons,1);
1112 continue;
1113 case '>': /* Numeric keypad */
1114 clr_kbd(kbdapplic);
1115 continue;
1116 case '=': /* Appl. keypad */
1117 set_kbd(kbdapplic);
1118 continue;
1120 continue;
1121 case ESsquare:
1122 for(npar = 0 ; npar < NPAR ; npar++)
1123 par[npar] = 0;
1124 npar = 0;
1125 state = ESgetpars;
1126 if (c == '[') { /* Function key */
1127 state=ESfunckey;
1128 continue;
1130 ques = (c=='?');
1131 if (ques)
1132 continue;
1133 case ESgetpars:
1134 if (c==';' && npar<NPAR-1) {
1135 npar++;
1136 continue;
1137 } else if (c>='0' && c<='9') {
1138 par[npar] *= 10;
1139 par[npar] += c-'0';
1140 continue;
1141 } else state=ESgotpars;
1142 case ESgotpars:
1143 state = ESnormal;
1144 switch(c) {
1145 case 'h':
1146 set_mode(currcons,1);
1147 continue;
1148 case 'l':
1149 set_mode(currcons,0);
1150 continue;
1151 case 'n':
1152 if (!ques)
1153 if (par[0] == 5)
1154 status_report(currcons,tty);
1155 else if (par[0] == 6)
1156 cursor_report(currcons,tty);
1157 continue;
1159 if (ques) {
1160 ques = 0;
1161 continue;
1163 switch(c) {
1164 case 'G': case '`':
1165 if (par[0]) par[0]--;
1166 gotoxy(currcons,par[0],y);
1167 continue;
1168 case 'A':
1169 if (!par[0]) par[0]++;
1170 gotoxy(currcons,x,y-par[0]);
1171 continue;
1172 case 'B': case 'e':
1173 if (!par[0]) par[0]++;
1174 gotoxy(currcons,x,y+par[0]);
1175 continue;
1176 case 'C': case 'a':
1177 if (!par[0]) par[0]++;
1178 gotoxy(currcons,x+par[0],y);
1179 continue;
1180 case 'D':
1181 if (!par[0]) par[0]++;
1182 gotoxy(currcons,x-par[0],y);
1183 continue;
1184 case 'E':
1185 if (!par[0]) par[0]++;
1186 gotoxy(currcons,0,y+par[0]);
1187 continue;
1188 case 'F':
1189 if (!par[0]) par[0]++;
1190 gotoxy(currcons,0,y-par[0]);
1191 continue;
1192 case 'd':
1193 if (par[0]) par[0]--;
1194 gotoxy(currcons,x,par[0]);
1195 continue;
1196 case 'H': case 'f':
1197 if (par[0]) par[0]--;
1198 if (par[1]) par[1]--;
1199 gotoxy(currcons,par[1],par[0]);
1200 continue;
1201 case 'J':
1202 csi_J(currcons,par[0]);
1203 continue;
1204 case 'K':
1205 csi_K(currcons,par[0]);
1206 continue;
1207 case 'L':
1208 csi_L(currcons,par[0]);
1209 continue;
1210 case 'M':
1211 csi_M(currcons,par[0]);
1212 continue;
1213 case 'P':
1214 csi_P(currcons,par[0]);
1215 continue;
1216 case 'c':
1217 if (!par[0])
1218 respond_ID(currcons,tty);
1219 continue;
1220 case 'g':
1221 if (!par[0])
1222 tab_stop[x >> 5] &= ~(1 << (x & 31));
1223 else if (par[0] == 3) {
1224 tab_stop[0] =
1225 tab_stop[1] =
1226 tab_stop[2] =
1227 tab_stop[3] =
1228 tab_stop[4] = 0;
1230 continue;
1231 case 'm':
1232 csi_m(currcons);
1233 continue;
1234 case 'r':
1235 if (!par[0])
1236 par[0]++;
1237 if (!par[1])
1238 par[1] = video_num_lines;
1239 /* Minimum allowed region is 2 lines */
1240 if (par[0] < par[1] &&
1241 par[1] <= video_num_lines) {
1242 top=par[0]-1;
1243 bottom=par[1];
1244 gotoxy(currcons,0,0);
1246 continue;
1247 case 's':
1248 save_cur(currcons);
1249 continue;
1250 case 'u':
1251 restore_cur(currcons);
1252 continue;
1253 case '@':
1254 csi_at(currcons,par[0]);
1255 continue;
1256 case ']': /* setterm functions */
1257 setterm_command(currcons);
1258 continue;
1260 continue;
1261 case ESfunckey:
1262 state = ESnormal;
1263 continue;
1264 case EShash:
1265 state = ESnormal;
1266 if (c == '8') {
1267 /* DEC screen alignment test. kludge :-) */
1268 video_erase_char =
1269 (video_erase_char & 0xff00) | 'E';
1270 csi_J(currcons, 2);
1271 video_erase_char =
1272 (video_erase_char & 0xff00) | ' ';
1274 continue;
1275 case ESsetG0:
1276 if (c == '0')
1277 G0_charset = GRAF_TRANS;
1278 else if (c == 'B')
1279 G0_charset = NORM_TRANS;
1280 else if (c == 'U')
1281 G0_charset = NULL_TRANS;
1282 else if (c == 'K')
1283 G0_charset = USER_TRANS;
1284 if (charset == 0)
1285 translate = G0_charset;
1286 state = ESnormal;
1287 continue;
1288 case ESsetG1:
1289 if (c == '0')
1290 G1_charset = GRAF_TRANS;
1291 else if (c == 'B')
1292 G1_charset = NORM_TRANS;
1293 else if (c == 'U')
1294 G1_charset = NULL_TRANS;
1295 else if (c == 'K')
1296 G1_charset = USER_TRANS;
1297 if (charset == 1)
1298 translate = G1_charset;
1299 state = ESnormal;
1300 continue;
1301 default:
1302 state = ESnormal;
1305 if (vcmode != KD_GRAPHICS)
1306 set_cursor(currcons);
1307 enable_bh(KEYBOARD_BH);
1308 if (LEFT(&tty->write_q) > WAKEUP_CHARS)
1309 wake_up_interruptible(&tty->write_q.proc_list);
1312 void do_keyboard_interrupt(void)
1314 TTY_READ_FLUSH(TTY_TABLE(0));
1315 timer_active &= ~(1<<BLANK_TIMER);
1316 if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
1317 return;
1318 if (console_blanked) {
1319 timer_table[BLANK_TIMER].expires = 0;
1320 timer_active |= 1<<BLANK_TIMER;
1321 } else if (blankinterval) {
1322 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1323 timer_active |= 1<<BLANK_TIMER;
1327 void * memsetw(void * s,unsigned short c,int count)
1329 __asm__("cld\n\t"
1330 "rep\n\t"
1331 "stosw"
1332 : /* no output */
1333 :"a" (c),"D" (s),"c" (count)
1334 :"cx","di");
1335 return s;
1338 void console_print(const char * b)
1340 int currcons = fg_console;
1341 unsigned char c;
1343 if (!printable || currcons<0 || currcons>=NR_CONSOLES)
1344 return;
1345 while ((c = *(b++)) != 0) {
1346 if (c == 10 || c == 13 || need_wrap) {
1347 if (c != 13)
1348 lf(currcons);
1349 cr(currcons);
1350 if (c == 10 || c == 13)
1351 continue;
1353 *(unsigned short *) pos = (attr << 8) + c;
1354 if (x == video_num_columns - 1) {
1355 need_wrap = 1;
1356 continue;
1358 x++;
1359 pos+=2;
1361 set_cursor(currcons);
1362 if (vt_cons[fg_console].vc_mode == KD_GRAPHICS)
1363 return;
1364 timer_active &= ~(1<<BLANK_TIMER);
1365 if (console_blanked) {
1366 timer_table[BLANK_TIMER].expires = 0;
1367 timer_active |= 1<<BLANK_TIMER;
1368 } else if (blankinterval) {
1369 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1370 timer_active |= 1<<BLANK_TIMER;
1375 * long con_init(long);
1377 * This routine initalizes console interrupts, and does nothing
1378 * else. If you want the screen to clear, call tty_write with
1379 * the appropriate escape-sequece.
1381 * Reads the information preserved by setup.s to determine the current display
1382 * type and sets everything accordingly.
1384 long con_init(long kmem_start)
1386 char *display_desc = "????";
1387 int currcons = 0;
1388 long base;
1389 int orig_x = ORIG_X;
1390 int orig_y = ORIG_Y;
1392 vc_scrmembuf = (unsigned short *) kmem_start;
1393 video_num_columns = ORIG_VIDEO_COLS;
1394 video_size_row = video_num_columns * 2;
1395 video_num_lines = ORIG_VIDEO_LINES;
1396 video_page = ORIG_VIDEO_PAGE;
1397 screen_size = (video_num_lines * video_size_row);
1398 kmem_start += NR_CONSOLES * screen_size;
1399 timer_table[BLANK_TIMER].fn = blank_screen;
1400 timer_table[BLANK_TIMER].expires = 0;
1401 if (blankinterval) {
1402 timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
1403 timer_active |= 1<<BLANK_TIMER;
1406 if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
1408 video_mem_base = 0xb0000;
1409 video_port_reg = 0x3b4;
1410 video_port_val = 0x3b5;
1411 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1413 video_type = VIDEO_TYPE_EGAM;
1414 video_mem_term = 0xb8000;
1415 display_desc = "EGA+";
1417 else
1419 video_type = VIDEO_TYPE_MDA;
1420 video_mem_term = 0xb2000;
1421 display_desc = "*MDA";
1424 else /* If not, it is color. */
1426 can_do_color = 1;
1427 video_mem_base = 0xb8000;
1428 video_port_reg = 0x3d4;
1429 video_port_val = 0x3d5;
1430 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
1432 video_type = VIDEO_TYPE_EGAC;
1433 video_mem_term = 0xc0000;
1434 display_desc = "EGA+";
1436 else
1438 video_type = VIDEO_TYPE_CGA;
1439 video_mem_term = 0xba000;
1440 display_desc = "*CGA";
1444 /* Initialize the variables used for scrolling (mostly EGA/VGA) */
1446 base = (long)vc_scrmembuf;
1447 for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
1448 pos = origin = video_mem_start = base;
1449 scr_end = video_mem_end = (base += screen_size);
1450 vc_scrbuf[currcons] = (unsigned short *) origin;
1451 vcmode = KD_TEXT;
1452 vtmode.mode = VT_AUTO;
1453 vtmode.waitv = 0;
1454 vtmode.relsig = 0;
1455 vtmode.acqsig = 0;
1456 vtmode.frsig = 0;
1457 vtpid = -1;
1458 vtnewvt = -1;
1459 clr_kbd(kbdraw);
1460 def_color = 0x07; /* white */
1461 ulcolor = 0x0f; /* bold white */
1462 halfcolor = 0x08; /* grey */
1463 reset_terminal(currcons, currcons);
1465 currcons = fg_console = 0;
1467 video_mem_start = video_mem_base;
1468 video_mem_end = video_mem_term;
1469 origin = video_mem_start;
1470 scr_end = video_mem_start + video_num_lines * video_size_row;
1471 gotoxy(currcons,0,0);
1472 save_cur(currcons);
1473 gotoxy(currcons,orig_x,orig_y);
1474 update_screen(fg_console);
1475 printable = 1;
1476 printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
1477 can_do_color?"colour":"mono",
1478 display_desc,
1479 video_num_columns,video_num_lines,
1480 NR_CONSOLES);
1481 register_console(console_print);
1482 return kmem_start;
1486 * kbdsave doesn't need to do anything: it's all handled automatically
1487 * with the new data structures..
1489 void kbdsave(int new_console)
1493 static void get_scrmem(int currcons)
1495 memcpy((void *)vc_scrbuf[currcons],(void *)origin, screen_size);
1496 video_mem_start = (unsigned long)vc_scrbuf[currcons];
1497 origin = video_mem_start;
1498 scr_end = video_mem_end = video_mem_start+screen_size;
1499 pos = origin + y*video_size_row + (x<<1);
1502 static void set_scrmem(int currcons)
1504 #ifdef CONFIG_HGA
1505 /* This works with XFree86 1.2, 1.3 and 2.0
1506 This code could be extended and made more generally useful if we could
1507 determine the actual video mode. It appears that this should be
1508 possible on a genuine Hercules card, but I (WM) haven't been able to
1509 read from any of the required registers on my clone card.
1511 /* This code should work with Hercules and MDA cards. */
1512 if (video_type == VIDEO_TYPE_MDA)
1514 if (vcmode == KD_TEXT)
1516 /* Ensure that the card is in text mode. */
1517 int i;
1518 static char herc_txt_tbl[12] = {
1519 0x61,0x50,0x52,0x0f,0x19,6,0x19,0x19,2,0x0d,0x0b,0x0c };
1520 outb_p(0, 0x3bf); /* Back to power-on defaults */
1521 outb_p(0, 0x3b8); /* Blank the screen, select page 0, etc */
1522 for ( i = 0 ; i < 12 ; i++ )
1524 outb_p(i, 0x3b4);
1525 outb_p(herc_txt_tbl[i], 0x3b5);
1528 #define HGA_BLINKER_ON 0x20
1529 #define HGA_SCREEN_ON 8
1530 /* Make sure that the hardware is not blanked */
1531 outb_p(HGA_BLINKER_ON | HGA_SCREEN_ON, 0x3b8);
1533 #endif CONFIG_HGA
1535 video_mem_start = video_mem_base;
1536 video_mem_end = video_mem_term;
1537 origin = video_mem_start;
1538 scr_end = video_mem_start + screen_size;
1539 pos = origin + y*video_size_row + (x<<1);
1540 memcpy((void *)video_mem_base, (void *)vc_scrbuf[fg_console], screen_size);
1543 void blank_screen(void)
1545 if (console_blanked)
1546 return;
1547 timer_table[BLANK_TIMER].fn = unblank_screen;
1548 get_scrmem(fg_console);
1549 hide_cursor(fg_console);
1550 console_blanked = 1;
1551 memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
1554 void unblank_screen(void)
1556 if (!console_blanked)
1557 return;
1558 timer_table[BLANK_TIMER].fn = blank_screen;
1559 if (blankinterval) {
1560 timer_table[BLANK_TIMER].expires = jiffies + blankinterval;
1561 timer_active |= 1<<BLANK_TIMER;
1563 console_blanked = 0;
1564 set_scrmem(fg_console);
1565 set_origin(fg_console);
1566 set_cursor(fg_console);
1569 void update_screen(int new_console)
1571 static int lock = 0;
1573 if (new_console == fg_console || lock)
1574 return;
1575 lock = 1;
1576 kbdsave(new_console);
1577 get_scrmem(fg_console);
1578 fg_console = new_console;
1579 set_scrmem(fg_console);
1580 set_origin(fg_console);
1581 set_cursor(new_console);
1582 set_leds();
1583 compute_shiftstate();
1584 lock = 0;
1587 int do_screendump(int arg)
1589 char *sptr, *buf = (char *)arg;
1590 int currcons, l;
1592 if (!suser())
1593 return -EPERM;
1594 l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
1595 if (l)
1596 return l;
1597 currcons = get_fs_byte(buf+1);
1598 if ((currcons<0) || (currcons>NR_CONSOLES))
1599 return -EIO;
1600 put_fs_byte((char)(video_num_lines),buf++);
1601 put_fs_byte((char)(video_num_columns),buf++);
1602 currcons = (currcons ? currcons-1 : fg_console);
1603 sptr = (char *) origin;
1604 for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
1605 put_fs_byte(*sptr++,buf++);
1606 return(0);
1610 * All we do is set the write and ioctl subroutines; later on maybe we'll
1611 * dynamically allocate the console screen memory.
1613 int con_open(struct tty_struct *tty, struct file * filp)
1615 tty->write = con_write;
1616 tty->ioctl = vt_ioctl;
1617 if (tty->line > NR_CONSOLES)
1618 return -ENODEV;
1619 return 0;
1622 #ifdef CONFIG_SELECTION
1623 /* correction factor for when screen is hardware-scrolled */
1624 #define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0)
1626 /* set reverse video on characters s-e of console with selection. */
1627 static void highlight(const int currcons, const int s, const int e)
1629 unsigned char *p, *p1, *p2;
1631 p1 = (unsigned char *)origin - hwscroll_offset + s + 1;
1632 p2 = (unsigned char *)origin - hwscroll_offset + e + 1;
1633 if (p1 > p2)
1635 p = p1;
1636 p1 = p2;
1637 p2 = p;
1639 for (p = p1; p <= p2; p += 2)
1640 *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
1643 /* is c in range [a-zA-Z0-9_]? */
1644 static inline int inword(const char c) { return (isalnum(c) || c == '_'); }
1646 /* does screen address p correspond to character at LH/RH edge of screen? */
1647 static inline int atedge(const int p)
1649 return (!(p % video_size_row) || !((p + 2) % video_size_row));
1652 /* constrain v such that l <= v <= u */
1653 static inline short limit(const int v, const int l, const int u)
1655 return (v < l) ? l : ((v > u) ? u : v);
1658 /* set the current selection. Invoked by ioctl(). */
1659 int set_selection(const int arg)
1661 unsigned short *args, xs, ys, xe, ye;
1662 int currcons = fg_console;
1663 int sel_mode, new_sel_start, new_sel_end, spc;
1664 char *bp, *obp, *spos;
1665 int i, ps, pe;
1666 char *off = (char *)origin - hwscroll_offset;
1668 unblank_screen();
1669 args = (unsigned short *)(arg + 1);
1670 xs = get_fs_word(args++) - 1;
1671 ys = get_fs_word(args++) - 1;
1672 xe = get_fs_word(args++) - 1;
1673 ye = get_fs_word(args++) - 1;
1674 sel_mode = get_fs_word(args);
1676 xs = limit(xs, 0, video_num_columns - 1);
1677 ys = limit(ys, 0, video_num_lines - 1);
1678 xe = limit(xe, 0, video_num_columns - 1);
1679 ye = limit(ye, 0, video_num_lines - 1);
1680 ps = ys * video_size_row + (xs << 1);
1681 pe = ye * video_size_row + (xe << 1);
1683 if (ps > pe) /* make sel_start <= sel_end */
1685 int tmp = ps;
1686 ps = pe;
1687 pe = tmp;
1690 switch (sel_mode)
1692 case 0: /* character-by-character selection */
1693 default:
1694 new_sel_start = ps;
1695 new_sel_end = pe;
1696 break;
1697 case 1: /* word-by-word selection */
1698 spc = isspace(*(off + ps));
1699 for (new_sel_start = ps; ; ps -= 2)
1701 if ((spc && !isspace(*(off + ps))) ||
1702 (!spc && !inword(*(off + ps))))
1703 break;
1704 new_sel_start = ps;
1705 if (!(ps % video_size_row))
1706 break;
1708 spc = isspace(*(off + pe));
1709 for (new_sel_end = pe; ; pe += 2)
1711 if ((spc && !isspace(*(off + pe))) ||
1712 (!spc && !inword(*(off + pe))))
1713 break;
1714 new_sel_end = pe;
1715 if (!((pe + 2) % video_size_row))
1716 break;
1718 break;
1719 case 2: /* line-by-line selection */
1720 new_sel_start = ps - ps % video_size_row;
1721 new_sel_end = pe + video_size_row
1722 - pe % video_size_row - 2;
1723 break;
1725 /* select to end of line if on trailing space */
1726 if (new_sel_end > new_sel_start &&
1727 !atedge(new_sel_end) && isspace(*(off + new_sel_end)))
1729 for (pe = new_sel_end + 2; ; pe += 2)
1731 if (!isspace(*(off + pe)) || atedge(pe))
1732 break;
1734 if (isspace(*(off + pe)))
1735 new_sel_end = pe;
1737 if (sel_cons != currcons)
1739 clear_selection();
1740 sel_cons = currcons;
1742 if (sel_start == -1) /* no current selection */
1743 highlight(sel_cons, new_sel_start, new_sel_end);
1744 else if (new_sel_start == sel_start)
1746 if (new_sel_end == sel_end) /* no action required */
1747 return 0;
1748 else if (new_sel_end > sel_end) /* extend to right */
1749 highlight(sel_cons, sel_end + 2, new_sel_end);
1750 else /* contract from right */
1751 highlight(sel_cons, new_sel_end + 2, sel_end);
1753 else if (new_sel_end == sel_end)
1755 if (new_sel_start < sel_start) /* extend to left */
1756 highlight(sel_cons, new_sel_start, sel_start - 2);
1757 else /* contract from left */
1758 highlight(sel_cons, sel_start, new_sel_start - 2);
1760 else /* some other case; start selection from scratch */
1762 clear_selection();
1763 highlight(sel_cons, new_sel_start, new_sel_end);
1765 sel_start = new_sel_start;
1766 sel_end = new_sel_end;
1767 obp = bp = sel_buffer;
1768 for (i = sel_start; i <= sel_end; i += 2)
1770 spos = (char *)off + i;
1771 *bp++ = *spos;
1772 if (!isspace(*spos))
1773 obp = bp;
1774 if (! ((i + 2) % video_size_row))
1776 /* strip trailing blanks from line and add newline,
1777 unless non-space at end of line. */
1778 if (obp != bp)
1780 bp = obp;
1781 *bp++ = '\r';
1783 obp = bp;
1785 /* check for space, leaving room for next character, possible
1786 newline, and null at end. */
1787 if (bp - sel_buffer > SEL_BUFFER_SIZE - 3)
1788 break;
1790 *bp = '\0';
1791 return 0;
1794 /* insert the contents of the selection buffer into the queue of the
1795 tty associated with the current console. Invoked by ioctl(). */
1796 int paste_selection(struct tty_struct *tty)
1798 char *bp = sel_buffer;
1800 if (! *bp)
1801 return 0;
1802 unblank_screen();
1803 while (*bp)
1805 put_tty_queue(*bp, &tty->read_q);
1806 bp++;
1808 TTY_READ_FLUSH(tty);
1809 return 0;
1812 /* remove the current selection highlight, if any, from the console holding
1813 the selection. */
1814 static void clear_selection()
1816 if (sel_start != -1)
1818 highlight(sel_cons, sel_start, sel_end);
1819 sel_start = -1;
1822 #endif /* CONFIG_SELECTION */
1825 * PIO_FONT support.
1828 #define colourmap ((char *)0xa0000)
1829 #define blackwmap ((char *)0xb0000)
1830 #define cmapsz 8192
1831 #define seq_port_reg (0x3c4)
1832 #define seq_port_val (0x3c5)
1833 #define gr_port_reg (0x3ce)
1834 #define gr_port_val (0x3cf)
1836 static int set_get_font(char * arg, int set)
1838 #ifdef CAN_LOAD_EGA_FONTS
1839 int i;
1840 char *charmap;
1842 /* no use to "load" CGA... */
1844 if (video_type == VIDEO_TYPE_EGAC)
1845 charmap = colourmap;
1846 else if (video_type == VIDEO_TYPE_EGAM)
1847 charmap = blackwmap;
1848 else
1849 return -EINVAL;
1851 i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
1852 if (i)
1853 return i;
1855 cli();
1856 outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
1857 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
1858 outb_p( 0x02, seq_port_reg );
1859 outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
1860 outb_p( 0x04, seq_port_reg );
1861 outb_p( 0x07, seq_port_val ); /* Sequential addressing */
1862 outb_p( 0x00, seq_port_reg );
1863 outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
1865 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
1866 outb_p( 0x02, gr_port_val ); /* select map 2 */
1867 outb_p( 0x05, gr_port_reg );
1868 outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
1869 outb_p( 0x06, gr_port_reg );
1870 outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
1871 sti();
1873 if (set)
1874 for (i=0; i<cmapsz ; i++)
1875 *(charmap+i) = get_fs_byte(arg+i);
1876 else
1877 for (i=0; i<cmapsz ; i++)
1878 put_fs_byte(*(charmap+i), arg+i);
1880 cli();
1881 outb_p( 0x00, seq_port_reg ); /* Frist, the sequencer */
1882 outb_p( 0x01, seq_port_val ); /* Synchronous reset */
1883 outb_p( 0x02, seq_port_reg );
1884 outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
1885 outb_p( 0x04, seq_port_reg );
1886 outb_p( 0x03, seq_port_val ); /* odd-even addressing */
1887 outb_p( 0x00, seq_port_reg );
1888 outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
1890 outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
1891 outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
1892 outb_p( 0x05, gr_port_reg );
1893 outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
1894 outb_p( 0x06, gr_port_reg );
1895 outb_p( 0x0e, gr_port_val ); /* map starts at b800:0000 */
1896 sti();
1898 return 0;
1899 #else
1900 return -EINVAL;
1901 #endif
1905 * Load font into the EGA/VGA character generator. arg points to a 8192
1906 * byte map, 32 bytes per character. Only first H of them are used for
1907 * 8xH fonts (0 < H <= 32).
1910 int con_set_font (char *arg)
1912 return set_get_font (arg,1);
1915 int con_get_font (char *arg)
1917 return set_get_font (arg,0);
1921 * Load customizable translation table (USER_TRANS[]). All checks are here,
1922 * so we need only include 'return con_set_trans(arg)' in the ioctl handler
1923 * arg points to a 256 byte translation table.
1925 int con_set_trans(char * arg)
1927 int i;
1929 i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ);
1930 if (i)
1931 return i;
1933 for (i=0; i<E_TABSZ ; i++) USER_TRANS[i] = get_fs_byte(arg+i);
1934 USER_TRANS[012]=0;
1935 USER_TRANS[014]=0;
1936 USER_TRANS[015]=0;
1937 USER_TRANS[033]=0;
1938 return 0;
1941 int con_get_trans(char * arg)
1943 int i;
1945 i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
1946 if (i)
1947 return i;
1949 for (i=0; i<E_TABSZ ; i++) put_fs_byte(USER_TRANS[i],arg+i);
1950 return 0;