VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / video / console / vgacon.c
1 /*
2  *  linux/drivers/video/vgacon.c -- Low level VGA based console driver
3  *
4  *      Created 28 Sep 1997 by Geert Uytterhoeven
5  *
6  *      Rewritten by Martin Mares <mj@ucw.cz>, July 1998
7  *
8  *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.
9  *
10  *      Copyright (C) 1991, 1992  Linus Torvalds
11  *                          1995  Jay Estabrook
12  *
13  *      User definable mapping table and font loading by Eugene G. Crosser,
14  *      <crosser@average.org>
15  *
16  *      Improved loadable font/UTF-8 support by H. Peter Anvin
17  *      Feb-Sep 1995 <peter.anvin@linux.org>
18  *
19  *      Colour palette handling, by Simon Tatham
20  *      17-Jun-95 <sgt20@cam.ac.uk>
21  *
22  *      if 512 char mode is already enabled don't re-enable it,
23  *      because it causes screen to flicker, by Mitja Horvat
24  *      5-May-96 <mitja.horvat@guest.arnes.si>
25  *
26  *      Use 2 outw instead of 4 outb_p to reduce erroneous text
27  *      flashing on RHS of screen during heavy console scrolling .
28  *      Oct 1996, Paul Gortmaker.
29  *
30  *
31  *  This file is subject to the terms and conditions of the GNU General Public
32  *  License.  See the file COPYING in the main directory of this archive for
33  *  more details.
34  */
35
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/sched.h>
40 #include <linux/fs.h>
41 #include <linux/kernel.h>
42 #include <linux/tty.h>
43 #include <linux/console.h>
44 #include <linux/string.h>
45 #include <linux/kd.h>
46 #include <linux/slab.h>
47 #include <linux/vt_kern.h>
48 #include <linux/selection.h>
49 #include <linux/spinlock.h>
50 #include <linux/ioport.h>
51 #include <linux/init.h>
52 #include <video/vga.h>
53 #include <asm/io.h>
54
55 static spinlock_t vga_lock = SPIN_LOCK_UNLOCKED;
56 static struct vgastate state;
57
58 #define BLANK 0x0020
59
60 #define CAN_LOAD_EGA_FONTS      /* undefine if the user must not do this */
61 #define CAN_LOAD_PALETTE        /* undefine if the user must not do this */
62
63 /* You really do _NOT_ want to define this, unless you have buggy
64  * Trident VGA which will resize cursor when moving it between column
65  * 15 & 16. If you define this and your VGA is OK, inverse bug will
66  * appear.
67  */
68 #undef TRIDENT_GLITCH
69
70 /*
71  *  Interface used by the world
72  */
73
74 static const char *vgacon_startup(void);
75 static void vgacon_init(struct vc_data *c, int init);
76 static void vgacon_deinit(struct vc_data *c);
77 static void vgacon_cursor(struct vc_data *c, int mode);
78 static int vgacon_switch(struct vc_data *c);
79 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
80 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
81 static int vgacon_scrolldelta(struct vc_data *c, int lines);
82 static int vgacon_set_origin(struct vc_data *c);
83 static void vgacon_save_screen(struct vc_data *c);
84 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
85                          int lines);
86 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
87                             u8 blink, u8 underline, u8 reverse);
88 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
89 static unsigned long vgacon_uni_pagedir[2];
90
91
92 /* Description of the hardware situation */
93 static unsigned long    vga_vram_base;          /* Base of video memory */
94 static unsigned long    vga_vram_end;           /* End of video memory */
95 static u16              vga_video_port_reg;     /* Video register select port */
96 static u16              vga_video_port_val;     /* Video register value port */
97 static unsigned int     vga_video_num_columns;  /* Number of text columns */
98 static unsigned int     vga_video_num_lines;    /* Number of text lines */
99 static int              vga_can_do_color = 0;   /* Do we support colors? */
100 static unsigned int     vga_default_font_height;/* Height of default screen font */
101 static unsigned char    vga_video_type;         /* Card type */
102 static unsigned char    vga_hardscroll_enabled;
103 static unsigned char    vga_hardscroll_user_enable = 1;
104 static unsigned char    vga_font_is_default = 1;
105 static int              vga_vesa_blanked;
106 static int              vga_palette_blanked;
107 static int              vga_is_gfx;
108 static int              vga_512_chars;
109 static int              vga_video_font_height;
110 static int              vga_scan_lines;
111 static unsigned int     vga_rolled_over = 0;
112
113 static int __init no_scroll(char *str)
114 {
115         /*
116          * Disabling scrollback is required for the Braillex ib80-piezo
117          * Braille reader made by F.H. Papenmeier (Germany).
118          * Use the "no-scroll" bootflag.
119          */
120         vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
121         return 1;
122 }
123
124 __setup("no-scroll", no_scroll);
125
126 /*
127  * By replacing the four outb_p with two back to back outw, we can reduce
128  * the window of opportunity to see text mislocated to the RHS of the
129  * console during heavy scrolling activity. However there is the remote
130  * possibility that some pre-dinosaur hardware won't like the back to back
131  * I/O. Since the Xservers get away with it, we should be able to as well.
132  */
133 static inline void write_vga(unsigned char reg, unsigned int val)
134 {
135         unsigned int v1, v2;
136         unsigned long flags;
137
138         /*
139          * ddprintk might set the console position from interrupt
140          * handlers, thus the write has to be IRQ-atomic.
141          */
142         spin_lock_irqsave(&vga_lock, flags);
143
144 #ifndef SLOW_VGA
145         v1 = reg + (val & 0xff00);
146         v2 = reg + 1 + ((val << 8) & 0xff00);
147         outw(v1, vga_video_port_reg);
148         outw(v2, vga_video_port_reg);
149 #else
150         outb_p(reg, vga_video_port_reg);
151         outb_p(val >> 8, vga_video_port_val);
152         outb_p(reg + 1, vga_video_port_reg);
153         outb_p(val & 0xff, vga_video_port_val);
154 #endif
155         spin_unlock_irqrestore(&vga_lock, flags);
156 }
157
158 static const char __init *vgacon_startup(void)
159 {
160         const char *display_desc = NULL;
161         u16 saved1, saved2;
162         volatile u16 *p;
163
164         if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
165               no_vga:
166 #ifdef CONFIG_DUMMY_CONSOLE
167                 conswitchp = &dummy_con;
168                 return conswitchp->con_startup();
169 #else
170                 return NULL;
171 #endif
172         }
173
174         /* VGA16 modes are not handled by VGACON */
175         if ((ORIG_VIDEO_MODE == 0x0D) ||        /* 320x200/4 */
176             (ORIG_VIDEO_MODE == 0x0E) ||        /* 640x200/4 */
177             (ORIG_VIDEO_MODE == 0x10) ||        /* 640x350/4 */
178             (ORIG_VIDEO_MODE == 0x12) ||        /* 640x480/4 */
179             (ORIG_VIDEO_MODE == 0x6A))  /* 800x600/4, 0x6A is very common */
180                 goto no_vga;
181
182         vga_video_num_lines = ORIG_VIDEO_LINES;
183         vga_video_num_columns = ORIG_VIDEO_COLS;
184         state.vgabase = NULL;
185
186         if (ORIG_VIDEO_MODE == 7) {     /* Is this a monochrome display? */
187                 vga_vram_base = 0xb0000;
188                 vga_video_port_reg = VGA_CRT_IM;
189                 vga_video_port_val = VGA_CRT_DM;
190                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
191                         static struct resource ega_console_resource =
192                             { "ega", 0x3B0, 0x3BF };
193                         vga_video_type = VIDEO_TYPE_EGAM;
194                         vga_vram_end = 0xb8000;
195                         display_desc = "EGA+";
196                         request_resource(&ioport_resource,
197                                          &ega_console_resource);
198                 } else {
199                         static struct resource mda1_console_resource =
200                             { "mda", 0x3B0, 0x3BB };
201                         static struct resource mda2_console_resource =
202                             { "mda", 0x3BF, 0x3BF };
203                         vga_video_type = VIDEO_TYPE_MDA;
204                         vga_vram_end = 0xb2000;
205                         display_desc = "*MDA";
206                         request_resource(&ioport_resource,
207                                          &mda1_console_resource);
208                         request_resource(&ioport_resource,
209                                          &mda2_console_resource);
210                         vga_video_font_height = 14;
211                 }
212         } else {
213                 /* If not, it is color. */
214                 vga_can_do_color = 1;
215                 vga_vram_base = 0xb8000;
216                 vga_video_port_reg = VGA_CRT_IC;
217                 vga_video_port_val = VGA_CRT_DC;
218                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
219                         int i;
220
221                         vga_vram_end = 0xc0000;
222
223                         if (!ORIG_VIDEO_ISVGA) {
224                                 static struct resource ega_console_resource
225                                     = { "ega", 0x3C0, 0x3DF };
226                                 vga_video_type = VIDEO_TYPE_EGAC;
227                                 display_desc = "EGA";
228                                 request_resource(&ioport_resource,
229                                                  &ega_console_resource);
230                         } else {
231                                 static struct resource vga_console_resource
232                                     = { "vga+", 0x3C0, 0x3DF };
233                                 vga_video_type = VIDEO_TYPE_VGAC;
234                                 display_desc = "VGA+";
235                                 request_resource(&ioport_resource,
236                                                  &vga_console_resource);
237
238 #ifdef VGA_CAN_DO_64KB
239                                 /*
240                                  * get 64K rather than 32K of video RAM.
241                                  * This doesn't actually work on all "VGA"
242                                  * controllers (it seems like setting MM=01
243                                  * and COE=1 isn't necessarily a good idea)
244                                  */
245                                 vga_vram_base = 0xa0000;
246                                 vga_vram_end = 0xb0000;
247                                 outb_p(6, VGA_GFX_I);
248                                 outb_p(6, VGA_GFX_D);
249 #endif
250                                 /*
251                                  * Normalise the palette registers, to point
252                                  * the 16 screen colours to the first 16
253                                  * DAC entries.
254                                  */
255
256                                 for (i = 0; i < 16; i++) {
257                                         inb_p(VGA_IS1_RC);
258                                         outb_p(i, VGA_ATT_W);
259                                         outb_p(i, VGA_ATT_W);
260                                 }
261                                 outb_p(0x20, VGA_ATT_W);
262
263                                 /*
264                                  * Now set the DAC registers back to their
265                                  * default values
266                                  */
267                                 for (i = 0; i < 16; i++) {
268                                         outb_p(color_table[i], VGA_PEL_IW);
269                                         outb_p(default_red[i], VGA_PEL_D);
270                                         outb_p(default_grn[i], VGA_PEL_D);
271                                         outb_p(default_blu[i], VGA_PEL_D);
272                                 }
273                         }
274                 } else {
275                         static struct resource cga_console_resource =
276                             { "cga", 0x3D4, 0x3D5 };
277                         vga_video_type = VIDEO_TYPE_CGA;
278                         vga_vram_end = 0xba000;
279                         display_desc = "*CGA";
280                         request_resource(&ioport_resource,
281                                          &cga_console_resource);
282                         vga_video_font_height = 8;
283                 }
284         }
285
286         vga_vram_base = VGA_MAP_MEM(vga_vram_base);
287         vga_vram_end = VGA_MAP_MEM(vga_vram_end);
288
289         /*
290          *      Find out if there is a graphics card present.
291          *      Are there smarter methods around?
292          */
293         p = (volatile u16 *) vga_vram_base;
294         saved1 = scr_readw(p);
295         saved2 = scr_readw(p + 1);
296         scr_writew(0xAA55, p);
297         scr_writew(0x55AA, p + 1);
298         if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
299                 scr_writew(saved1, p);
300                 scr_writew(saved2, p + 1);
301                 goto no_vga;
302         }
303         scr_writew(0x55AA, p);
304         scr_writew(0xAA55, p + 1);
305         if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
306                 scr_writew(saved1, p);
307                 scr_writew(saved2, p + 1);
308                 goto no_vga;
309         }
310         scr_writew(saved1, p);
311         scr_writew(saved2, p + 1);
312
313         if (vga_video_type == VIDEO_TYPE_EGAC
314             || vga_video_type == VIDEO_TYPE_VGAC
315             || vga_video_type == VIDEO_TYPE_EGAM) {
316                 vga_hardscroll_enabled = vga_hardscroll_user_enable;
317                 vga_default_font_height = ORIG_VIDEO_POINTS;
318                 vga_video_font_height = ORIG_VIDEO_POINTS;
319                 /* This may be suboptimal but is a safe bet - go with it */
320                 vga_scan_lines =
321                     vga_video_font_height * vga_video_num_lines;
322         }
323         return display_desc;
324 }
325
326 static void vgacon_init(struct vc_data *c, int init)
327 {
328         unsigned long p;
329
330         /* We cannot be loaded as a module, therefore init is always 1 */
331         c->vc_can_do_color = vga_can_do_color;
332         c->vc_cols = vga_video_num_columns;
333         c->vc_rows = vga_video_num_lines;
334         c->vc_scan_lines = vga_scan_lines;
335         c->vc_font.height = vga_video_font_height;
336         c->vc_complement_mask = 0x7700;
337         p = *c->vc_uni_pagedir_loc;
338         if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
339             !--c->vc_uni_pagedir_loc[1])
340                 con_free_unimap(c->vc_num);
341         c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
342         vgacon_uni_pagedir[1]++;
343         if (!vgacon_uni_pagedir[0] && p)
344                 con_set_default_unimap(c->vc_num);
345 }
346
347 static inline void vga_set_mem_top(struct vc_data *c)
348 {
349         write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
350 }
351
352 static void vgacon_deinit(struct vc_data *c)
353 {
354         /* When closing the last console, reset video origin */
355         if (!--vgacon_uni_pagedir[1]) {
356                 c->vc_visible_origin = vga_vram_base;
357                 vga_set_mem_top(c);
358                 con_free_unimap(c->vc_num);
359         }
360         c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
361         con_set_default_unimap(c->vc_num);
362 }
363
364 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
365                             u8 blink, u8 underline, u8 reverse)
366 {
367         u8 attr = color;
368
369         if (vga_can_do_color) {
370                 if (underline)
371                         attr = (attr & 0xf0) | c->vc_ulcolor;
372                 else if (intensity == 0)
373                         attr = (attr & 0xf0) | c->vc_halfcolor;
374         }
375         if (reverse)
376                 attr =
377                     ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
378                                        0x77);
379         if (blink)
380                 attr ^= 0x80;
381         if (intensity == 2)
382                 attr ^= 0x08;
383         if (!vga_can_do_color) {
384                 if (underline)
385                         attr = (attr & 0xf8) | 0x01;
386                 else if (intensity == 0)
387                         attr = (attr & 0xf0) | 0x08;
388         }
389         return attr;
390 }
391
392 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
393 {
394         int col = vga_can_do_color;
395
396         while (count--) {
397                 u16 a = scr_readw(p);
398                 if (col)
399                         a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
400                             (((a) & 0x0700) << 4);
401                 else
402                         a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
403                 scr_writew(a, p++);
404         }
405 }
406
407 static void vgacon_set_cursor_size(int xpos, int from, int to)
408 {
409         unsigned long flags;
410         int curs, cure;
411         static int lastfrom, lastto;
412
413 #ifdef TRIDENT_GLITCH
414         if (xpos < 16)
415                 from--, to--;
416 #endif
417
418         if ((from == lastfrom) && (to == lastto))
419                 return;
420         lastfrom = from;
421         lastto = to;
422
423         spin_lock_irqsave(&vga_lock, flags);
424         outb_p(0x0a, vga_video_port_reg);       /* Cursor start */
425         curs = inb_p(vga_video_port_val);
426         outb_p(0x0b, vga_video_port_reg);       /* Cursor end */
427         cure = inb_p(vga_video_port_val);
428
429         curs = (curs & 0xc0) | from;
430         cure = (cure & 0xe0) | to;
431
432         outb_p(0x0a, vga_video_port_reg);       /* Cursor start */
433         outb_p(curs, vga_video_port_val);
434         outb_p(0x0b, vga_video_port_reg);       /* Cursor end */
435         outb_p(cure, vga_video_port_val);
436         spin_unlock_irqrestore(&vga_lock, flags);
437 }
438
439 static void vgacon_cursor(struct vc_data *c, int mode)
440 {
441         if (c->vc_origin != c->vc_visible_origin)
442                 vgacon_scrolldelta(c, 0);
443         switch (mode) {
444         case CM_ERASE:
445                 write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
446                 break;
447
448         case CM_MOVE:
449         case CM_DRAW:
450                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
451                 switch (c->vc_cursor_type & 0x0f) {
452                 case CUR_UNDERLINE:
453                         vgacon_set_cursor_size(c->vc_x,
454                                                c->vc_font.height -
455                                                (c->vc_font.height <
456                                                 10 ? 2 : 3),
457                                                c->vc_font.height -
458                                                (c->vc_font.height <
459                                                 10 ? 1 : 2));
460                         break;
461                 case CUR_TWO_THIRDS:
462                         vgacon_set_cursor_size(c->vc_x,
463                                                c->vc_font.height / 3,
464                                                c->vc_font.height -
465                                                (c->vc_font.height <
466                                                 10 ? 1 : 2));
467                         break;
468                 case CUR_LOWER_THIRD:
469                         vgacon_set_cursor_size(c->vc_x,
470                                                (c->vc_font.height * 2) / 3,
471                                                c->vc_font.height -
472                                                (c->vc_font.height <
473                                                 10 ? 1 : 2));
474                         break;
475                 case CUR_LOWER_HALF:
476                         vgacon_set_cursor_size(c->vc_x,
477                                                c->vc_font.height / 2,
478                                                c->vc_font.height -
479                                                (c->vc_font.height <
480                                                 10 ? 1 : 2));
481                         break;
482                 case CUR_NONE:
483                         vgacon_set_cursor_size(c->vc_x, 31, 30);
484                         break;
485                 default:
486                         vgacon_set_cursor_size(c->vc_x, 1,
487                                                c->vc_font.height);
488                         break;
489                 }
490                 break;
491         }
492 }
493
494 static int vgacon_switch(struct vc_data *c)
495 {
496         /*
497          * We need to save screen size here as it's the only way
498          * we can spot the screen has been resized and we need to
499          * set size of freshly allocated screens ourselves.
500          */
501         vga_video_num_columns = c->vc_cols;
502         vga_video_num_lines = c->vc_rows;
503         if (!vga_is_gfx)
504                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
505                             c->vc_screenbuf_size);
506         return 0;               /* Redrawing not needed */
507 }
508
509 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
510 {
511         int i, j;
512
513         for (i = j = 0; i < 16; i++) {
514                 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
515                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
516                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
517                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
518         }
519 }
520
521 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
522 {
523 #ifdef CAN_LOAD_PALETTE
524         if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
525             || !CON_IS_VISIBLE(vc))
526                 return -EINVAL;
527         vga_set_palette(vc, table);
528         return 0;
529 #else
530         return -EINVAL;
531 #endif
532 }
533
534 /* structure holding original VGA register settings */
535 static struct {
536         unsigned char SeqCtrlIndex;     /* Sequencer Index reg.   */
537         unsigned char CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
538         unsigned char CrtMiscIO;        /* Miscellaneous register */
539         unsigned char HorizontalTotal;  /* CRT-Controller:00h */
540         unsigned char HorizDisplayEnd;  /* CRT-Controller:01h */
541         unsigned char StartHorizRetrace;        /* CRT-Controller:04h */
542         unsigned char EndHorizRetrace;  /* CRT-Controller:05h */
543         unsigned char Overflow; /* CRT-Controller:07h */
544         unsigned char StartVertRetrace; /* CRT-Controller:10h */
545         unsigned char EndVertRetrace;   /* CRT-Controller:11h */
546         unsigned char ModeControl;      /* CRT-Controller:17h */
547         unsigned char ClockingMode;     /* Seq-Controller:01h */
548 } vga_state;
549
550 static void vga_vesa_blank(struct vgastate *state, int mode)
551 {
552         /* save original values of VGA controller registers */
553         if (!vga_vesa_blanked) {
554                 spin_lock_irq(&vga_lock);
555                 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
556                 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
557                 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
558                 spin_unlock_irq(&vga_lock);
559
560                 outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
561                 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
562                 outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
563                 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
564                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
565                 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
566                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
567                 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
568                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
569                 vga_state.Overflow = inb_p(vga_video_port_val);
570                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
571                 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
572                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
573                 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
574                 outb_p(0x17, vga_video_port_reg);       /* ModeControl */
575                 vga_state.ModeControl = inb_p(vga_video_port_val);
576                 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
577         }
578
579         /* assure that video is enabled */
580         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
581         spin_lock_irq(&vga_lock);
582         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
583
584         /* test for vertical retrace in process.... */
585         if ((vga_state.CrtMiscIO & 0x80) == 0x80)
586                 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
587
588         /*
589          * Set <End of vertical retrace> to minimum (0) and
590          * <Start of vertical Retrace> to maximum (incl. overflow)
591          * Result: turn off vertical sync (VSync) pulse.
592          */
593         if (mode & VESA_VSYNC_SUSPEND) {
594                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
595                 outb_p(0xff, vga_video_port_val);       /* maximum value */
596                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
597                 outb_p(0x40, vga_video_port_val);       /* minimum (bits 0..3)  */
598                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
599                 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);  /* bits 9,10 of vert. retrace */
600         }
601
602         if (mode & VESA_HSYNC_SUSPEND) {
603                 /*
604                  * Set <End of horizontal retrace> to minimum (0) and
605                  *  <Start of horizontal Retrace> to maximum
606                  * Result: turn off horizontal sync (HSync) pulse.
607                  */
608                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
609                 outb_p(0xff, vga_video_port_val);       /* maximum */
610                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
611                 outb_p(0x00, vga_video_port_val);       /* minimum (0) */
612         }
613
614         /* restore both index registers */
615         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
616         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
617         spin_unlock_irq(&vga_lock);
618 }
619
620 static void vga_vesa_unblank(struct vgastate *state)
621 {
622         /* restore original values of VGA controller registers */
623         spin_lock_irq(&vga_lock);
624         vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
625
626         outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
627         outb_p(vga_state.HorizontalTotal, vga_video_port_val);
628         outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
629         outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
630         outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
631         outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
632         outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
633         outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
634         outb_p(0x07, vga_video_port_reg);       /* Overflow */
635         outb_p(vga_state.Overflow, vga_video_port_val);
636         outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
637         outb_p(vga_state.StartVertRetrace, vga_video_port_val);
638         outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
639         outb_p(vga_state.EndVertRetrace, vga_video_port_val);
640         outb_p(0x17, vga_video_port_reg);       /* ModeControl */
641         outb_p(vga_state.ModeControl, vga_video_port_val);
642         /* ClockingMode */
643         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
644
645         /* restore index/control registers */
646         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
647         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
648         spin_unlock_irq(&vga_lock);
649 }
650
651 static void vga_pal_blank(struct vgastate *state)
652 {
653         int i;
654
655         for (i = 0; i < 16; i++) {
656                 vga_w(state->vgabase, VGA_PEL_IW, i);
657                 vga_w(state->vgabase, VGA_PEL_D, 0);
658                 vga_w(state->vgabase, VGA_PEL_D, 0);
659                 vga_w(state->vgabase, VGA_PEL_D, 0);
660         }
661 }
662
663 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
664 {
665         switch (blank) {
666         case 0:         /* Unblank */
667                 if (vga_vesa_blanked) {
668                         vga_vesa_unblank(&state);
669                         vga_vesa_blanked = 0;
670                 }
671                 if (vga_palette_blanked) {
672                         vga_set_palette(c, color_table);
673                         vga_palette_blanked = 0;
674                         return 0;
675                 }
676                 vga_is_gfx = 0;
677                 /* Tell console.c that it has to restore the screen itself */
678                 return 1;
679         case 1:         /* Normal blanking */
680         case -1:        /* Obsolete */
681                 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
682                         vga_pal_blank(&state);
683                         vga_palette_blanked = 1;
684                         return 0;
685                 }
686                 vgacon_set_origin(c);
687                 scr_memsetw((void *) vga_vram_base, BLANK,
688                             c->vc_screenbuf_size);
689                 if (mode_switch)
690                         vga_is_gfx = 1;
691                 return 1;
692         default:                /* VESA blanking */
693                 if (vga_video_type == VIDEO_TYPE_VGAC) {
694                         vga_vesa_blank(&state, blank - 1);
695                         vga_vesa_blanked = blank;
696                 }
697                 return 0;
698         }
699 }
700
701 /*
702  * PIO_FONT support.
703  *
704  * The font loading code goes back to the codepage package by
705  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
706  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
707  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
708  *
709  * Change for certain monochrome monitors by Yury Shevchuck
710  * (sizif@botik.yaroslavl.su).
711  */
712
713 #ifdef CAN_LOAD_EGA_FONTS
714
715 #define colourmap 0xa0000
716 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
717    should use 0xA0000 for the bwmap as well.. */
718 #define blackwmap 0xa0000
719 #define cmapsz 8192
720
721 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
722 {
723         unsigned short video_port_status = vga_video_port_reg + 6;
724         int font_select = 0x00, beg, i;
725         char *charmap;
726         
727         if (vga_video_type != VIDEO_TYPE_EGAM) {
728                 charmap = (char *) VGA_MAP_MEM(colourmap);
729                 beg = 0x0e;
730 #ifdef VGA_CAN_DO_64KB
731                 if (vga_video_type == VIDEO_TYPE_VGAC)
732                         beg = 0x06;
733 #endif
734         } else {
735                 charmap = (char *) VGA_MAP_MEM(blackwmap);
736                 beg = 0x0a;
737         }
738
739 #ifdef BROKEN_GRAPHICS_PROGRAMS
740         /*
741          * All fonts are loaded in slot 0 (0:1 for 512 ch)
742          */
743
744         if (!arg)
745                 return -EINVAL; /* Return to default font not supported */
746
747         vga_font_is_default = 0;
748         font_select = ch512 ? 0x04 : 0x00;
749 #else
750         /*
751          * The default font is kept in slot 0 and is never touched.
752          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
753          */
754
755         if (set) {
756                 vga_font_is_default = !arg;
757                 if (!arg)
758                         ch512 = 0;      /* Default font is always 256 */
759                 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
760         }
761
762         if (!vga_font_is_default)
763                 charmap += 4 * cmapsz;
764 #endif
765
766         spin_lock_irq(&vga_lock);
767         /* First, the Sequencer */
768         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
769         /* CPU writes only to map 2 */
770         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);    
771         /* Sequential addressing */
772         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);    
773         /* Clear synchronous reset */
774         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
775
776         /* Now, the graphics controller, select map 2 */
777         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);             
778         /* disable odd-even addressing */
779         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
780         /* map start at A000:0000 */
781         vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
782         spin_unlock_irq(&vga_lock);
783
784         if (arg) {
785                 if (set)
786                         for (i = 0; i < cmapsz; i++)
787                                 vga_writeb(arg[i], charmap + i);
788                 else
789                         for (i = 0; i < cmapsz; i++)
790                                 arg[i] = vga_readb(charmap + i);
791
792                 /*
793                  * In 512-character mode, the character map is not contiguous if
794                  * we want to remain EGA compatible -- which we do
795                  */
796
797                 if (ch512) {
798                         charmap += 2 * cmapsz;
799                         arg += cmapsz;
800                         if (set)
801                                 for (i = 0; i < cmapsz; i++)
802                                         vga_writeb(arg[i], charmap + i);
803                         else
804                                 for (i = 0; i < cmapsz; i++)
805                                         arg[i] = vga_readb(charmap + i);
806                 }
807         }
808
809         spin_lock_irq(&vga_lock);
810         /* First, the sequencer, Synchronous reset */
811         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);  
812         /* CPU writes to maps 0 and 1 */
813         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
814         /* odd-even addressing */
815         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
816         /* Character Map Select */
817         if (set)
818                 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
819         /* clear synchronous reset */
820         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
821
822         /* Now, the graphics controller, select map 0 for CPU */
823         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
824         /* enable even-odd addressing */
825         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
826         /* map starts at b800:0 or b000:0 */
827         vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
828
829         /* if 512 char mode is already enabled don't re-enable it. */
830         if ((set) && (ch512 != vga_512_chars)) {
831                 int i;  
832                 
833                 /* attribute controller */
834                 for (i = 0; i < MAX_NR_CONSOLES; i++) {
835                         struct vc_data *c = vc_cons[i].d;
836                         if (c && c->vc_sw == &vga_con)
837                                 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
838                 }
839                 vga_512_chars = ch512;
840                 /* 256-char: enable intensity bit
841                    512-char: disable intensity bit */
842                 inb_p(video_port_status);       /* clear address flip-flop */
843                 /* color plane enable register */
844                 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
845                 /* Wilton (1987) mentions the following; I don't know what
846                    it means, but it works, and it appears necessary */
847                 inb_p(video_port_status);
848                 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);    
849         }
850         spin_unlock_irq(&vga_lock);
851         return 0;
852 }
853
854 /*
855  * Adjust the screen to fit a font of a certain height
856  */
857 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
858 {
859         unsigned char ovr, vde, fsr;
860         int rows, maxscan, i;
861
862         if (fontheight == vc->vc_font.height)
863                 return 0;
864
865         vc->vc_font.height = fontheight;
866
867         rows = vc->vc_scan_lines / fontheight;  /* Number of video rows we end up with */
868         maxscan = rows * fontheight - 1;        /* Scan lines to actually display-1 */
869
870         /* Reprogram the CRTC for the new font size
871            Note: the attempt to read the overflow register will fail
872            on an EGA, but using 0xff for the previous value appears to
873            be OK for EGA text modes in the range 257-512 scan lines, so I
874            guess we don't need to worry about it.
875
876            The same applies for the spill bits in the font size and cursor
877            registers; they are write-only on EGA, but it appears that they
878            are all don't care bits on EGA, so I guess it doesn't matter. */
879
880         spin_lock_irq(&vga_lock);
881         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
882         ovr = inb_p(vga_video_port_val);
883         outb_p(0x09, vga_video_port_reg);       /* Font size register */
884         fsr = inb_p(vga_video_port_val);
885         spin_unlock_irq(&vga_lock);
886
887         vde = maxscan & 0xff;   /* Vertical display end reg */
888         ovr = (ovr & 0xbd) +    /* Overflow register */
889             ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
890         fsr = (fsr & 0xe0) + (fontheight - 1);  /*  Font size register */
891
892         spin_lock_irq(&vga_lock);
893         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
894         outb_p(ovr, vga_video_port_val);
895         outb_p(0x09, vga_video_port_reg);       /* Font size */
896         outb_p(fsr, vga_video_port_val);
897         outb_p(0x12, vga_video_port_reg);       /* Vertical display limit */
898         outb_p(vde, vga_video_port_val);
899         spin_unlock_irq(&vga_lock);
900
901         for (i = 0; i < MAX_NR_CONSOLES; i++) {
902                 struct vc_data *c = vc_cons[i].d;
903
904                 if (c && c->vc_sw == &vga_con)
905                         vc_resize(c->vc_num, 0, rows);  /* Adjust console size */
906         }
907         return 0;
908 }
909
910 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
911 {
912         unsigned charcount = font->charcount;
913         int rc;
914
915         if (vga_video_type < VIDEO_TYPE_EGAM)
916                 return -EINVAL;
917
918         if (font->width != 8 || (charcount != 256 && charcount != 512))
919                 return -EINVAL;
920
921         rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
922         if (rc)
923                 return rc;
924
925         if (!(flags & KD_FONT_FLAG_DONT_RECALC))
926                 rc = vgacon_adjust_height(c, font->height);
927         return rc;
928 }
929
930 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
931 {
932         if (vga_video_type < VIDEO_TYPE_EGAM)
933                 return -EINVAL;
934
935         font->width = 8;
936         font->height = c->vc_font.height;
937         font->charcount = vga_512_chars ? 512 : 256;
938         if (!font->data)
939                 return 0;
940         return vgacon_do_font_op(&state, font->data, 0, 0);
941 }
942
943 #else
944
945 #define vgacon_font_set NULL
946 #define vgacon_font_get NULL
947
948 #endif
949
950 static int vgacon_scrolldelta(struct vc_data *c, int lines)
951 {
952         if (!lines)             /* Turn scrollback off */
953                 c->vc_visible_origin = c->vc_origin;
954         else {
955                 int vram_size = vga_vram_end - vga_vram_base;
956                 int margin = c->vc_size_row * 4;
957                 int ul, we, p, st;
958
959                 if (vga_rolled_over >
960                     (c->vc_scr_end - vga_vram_base) + margin) {
961                         ul = c->vc_scr_end - vga_vram_base;
962                         we = vga_rolled_over + c->vc_size_row;
963                 } else {
964                         ul = 0;
965                         we = vram_size;
966                 }
967                 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
968                     lines * c->vc_size_row;
969                 st = (c->vc_origin - vga_vram_base - ul + we) % we;
970                 if (st < 2 * margin)
971                         margin = 0;
972                 if (p < margin)
973                         p = 0;
974                 if (p > st - margin)
975                         p = st;
976                 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
977         }
978         vga_set_mem_top(c);
979         return 1;
980 }
981
982 static int vgacon_set_origin(struct vc_data *c)
983 {
984         if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
985             (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
986                 return 0;
987         c->vc_origin = c->vc_visible_origin = vga_vram_base;
988         vga_set_mem_top(c);
989         vga_rolled_over = 0;
990         return 1;
991 }
992
993 static void vgacon_save_screen(struct vc_data *c)
994 {
995         static int vga_bootup_console = 0;
996
997         if (!vga_bootup_console) {
998                 /* This is a gross hack, but here is the only place we can
999                  * set bootup console parameters without messing up generic
1000                  * console initialization routines.
1001                  */
1002                 vga_bootup_console = 1;
1003                 c->vc_x = ORIG_X;
1004                 c->vc_y = ORIG_Y;
1005         }
1006         if (!vga_is_gfx)
1007                 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1008                             c->vc_screenbuf_size);
1009 }
1010
1011 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1012                          int lines)
1013 {
1014         unsigned long oldo;
1015         unsigned int delta;
1016
1017         if (t || b != c->vc_rows || vga_is_gfx)
1018                 return 0;
1019
1020         if (c->vc_origin != c->vc_visible_origin)
1021                 vgacon_scrolldelta(c, 0);
1022
1023         if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1024                 return 0;
1025
1026         oldo = c->vc_origin;
1027         delta = lines * c->vc_size_row;
1028         if (dir == SM_UP) {
1029                 if (c->vc_scr_end + delta >= vga_vram_end) {
1030                         scr_memcpyw((u16 *) vga_vram_base,
1031                                     (u16 *) (oldo + delta),
1032                                     c->vc_screenbuf_size - delta);
1033                         c->vc_origin = vga_vram_base;
1034                         vga_rolled_over = oldo - vga_vram_base;
1035                 } else
1036                         c->vc_origin += delta;
1037                 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1038                                      delta), c->vc_video_erase_char,
1039                             delta);
1040         } else {
1041                 if (oldo - delta < vga_vram_base) {
1042                         scr_memmovew((u16 *) (vga_vram_end -
1043                                               c->vc_screenbuf_size +
1044                                               delta), (u16 *) oldo,
1045                                      c->vc_screenbuf_size - delta);
1046                         c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1047                         vga_rolled_over = 0;
1048                 } else
1049                         c->vc_origin -= delta;
1050                 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1051                 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1052                             delta);
1053         }
1054         c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1055         c->vc_visible_origin = c->vc_origin;
1056         vga_set_mem_top(c);
1057         c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1058         return 1;
1059 }
1060
1061
1062 /*
1063  *  The console `switch' structure for the VGA based console
1064  */
1065
1066 static int vgacon_dummy(struct vc_data *c)
1067 {
1068         return 0;
1069 }
1070
1071 #define DUMMY (void *) vgacon_dummy
1072
1073 const struct consw vga_con = {
1074         .owner = THIS_MODULE,
1075         .con_startup = vgacon_startup,
1076         .con_init = vgacon_init,
1077         .con_deinit = vgacon_deinit,
1078         .con_clear = DUMMY,
1079         .con_putc = DUMMY,
1080         .con_putcs = DUMMY,
1081         .con_cursor = vgacon_cursor,
1082         .con_scroll = vgacon_scroll,
1083         .con_bmove = DUMMY,
1084         .con_switch = vgacon_switch,
1085         .con_blank = vgacon_blank,
1086         .con_font_set = vgacon_font_set,
1087         .con_font_get = vgacon_font_get,
1088         .con_set_palette = vgacon_set_palette,
1089         .con_scrolldelta = vgacon_scrolldelta,
1090         .con_set_origin = vgacon_set_origin,
1091         .con_save_screen = vgacon_save_screen,
1092         .con_build_attr = vgacon_build_attr,
1093         .con_invert_region = vgacon_invert_region,
1094 };
1095
1096 MODULE_LICENSE("GPL");