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