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