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