GNU Linux-libre 4.4.289-gnu1
[releases.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/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 is always 1,
426          * but vgacon_init can be called more than once, and init will
427          * not be 1.
428          */
429         c->vc_can_do_color = vga_can_do_color;
430
431         /* set dimensions manually if init != 0 since vc_resize() will fail */
432         if (init) {
433                 c->vc_cols = vga_video_num_columns;
434                 c->vc_rows = vga_video_num_lines;
435         } else
436                 vc_resize(c, vga_video_num_columns, vga_video_num_lines);
437
438         c->vc_scan_lines = vga_scan_lines;
439         c->vc_font.height = c->vc_cell_height = vga_video_font_height;
440         c->vc_complement_mask = 0x7700;
441         if (vga_512_chars)
442                 c->vc_hi_font_mask = 0x0800;
443         p = *c->vc_uni_pagedir_loc;
444         if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
445                 con_free_unimap(c);
446                 c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
447                 vgacon_refcount++;
448         }
449         if (!vgacon_uni_pagedir && p)
450                 con_set_default_unimap(c);
451
452         /* Only set the default if the user didn't deliberately override it */
453         if (global_cursor_default == -1)
454                 global_cursor_default =
455                         !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
456 }
457
458 static void vgacon_deinit(struct vc_data *c)
459 {
460         /* When closing the active console, reset video origin */
461         if (CON_IS_VISIBLE(c)) {
462                 c->vc_visible_origin = vga_vram_base;
463                 vga_set_mem_top(c);
464         }
465
466         if (!--vgacon_refcount)
467                 con_free_unimap(c);
468         c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
469         con_set_default_unimap(c);
470 }
471
472 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
473                             u8 blink, u8 underline, u8 reverse, u8 italic)
474 {
475         u8 attr = color;
476
477         if (vga_can_do_color) {
478                 if (italic)
479                         attr = (attr & 0xF0) | c->vc_itcolor;
480                 else if (underline)
481                         attr = (attr & 0xf0) | c->vc_ulcolor;
482                 else if (intensity == 0)
483                         attr = (attr & 0xf0) | c->vc_halfcolor;
484         }
485         if (reverse)
486                 attr =
487                     ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
488                                        0x77);
489         if (blink)
490                 attr ^= 0x80;
491         if (intensity == 2)
492                 attr ^= 0x08;
493         if (!vga_can_do_color) {
494                 if (italic)
495                         attr = (attr & 0xF8) | 0x02;
496                 else if (underline)
497                         attr = (attr & 0xf8) | 0x01;
498                 else if (intensity == 0)
499                         attr = (attr & 0xf0) | 0x08;
500         }
501         return attr;
502 }
503
504 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
505 {
506         int col = vga_can_do_color;
507
508         while (count--) {
509                 u16 a = scr_readw(p);
510                 if (col)
511                         a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
512                             (((a) & 0x0700) << 4);
513                 else
514                         a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
515                 scr_writew(a, p++);
516         }
517 }
518
519 static void vgacon_set_cursor_size(int xpos, int from, int to)
520 {
521         unsigned long flags;
522         int curs, cure;
523
524 #ifdef TRIDENT_GLITCH
525         if (xpos < 16)
526                 from--, to--;
527 #endif
528
529         if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
530                 return;
531         cursor_size_lastfrom = from;
532         cursor_size_lastto = to;
533
534         raw_spin_lock_irqsave(&vga_lock, flags);
535         if (vga_video_type >= VIDEO_TYPE_VGAC) {
536                 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
537                 curs = inb_p(vga_video_port_val);
538                 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
539                 cure = inb_p(vga_video_port_val);
540         } else {
541                 curs = 0;
542                 cure = 0;
543         }
544
545         curs = (curs & 0xc0) | from;
546         cure = (cure & 0xe0) | to;
547
548         outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
549         outb_p(curs, vga_video_port_val);
550         outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
551         outb_p(cure, vga_video_port_val);
552         raw_spin_unlock_irqrestore(&vga_lock, flags);
553 }
554
555 static void vgacon_cursor(struct vc_data *c, int mode)
556 {
557         if (c->vc_mode != KD_TEXT)
558                 return;
559
560         vgacon_restore_screen(c);
561
562         switch (mode) {
563         case CM_ERASE:
564                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
565                 if (vga_video_type >= VIDEO_TYPE_VGAC)
566                         vgacon_set_cursor_size(c->vc_x, 31, 30);
567                 else
568                         vgacon_set_cursor_size(c->vc_x, 31, 31);
569                 break;
570
571         case CM_MOVE:
572         case CM_DRAW:
573                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
574                 switch (c->vc_cursor_type & 0x0f) {
575                 case CUR_UNDERLINE:
576                         vgacon_set_cursor_size(c->vc_x,
577                                                c->vc_cell_height -
578                                                (c->vc_cell_height <
579                                                 10 ? 2 : 3),
580                                                c->vc_cell_height -
581                                                (c->vc_cell_height <
582                                                 10 ? 1 : 2));
583                         break;
584                 case CUR_TWO_THIRDS:
585                         vgacon_set_cursor_size(c->vc_x,
586                                                c->vc_cell_height / 3,
587                                                c->vc_cell_height -
588                                                (c->vc_cell_height <
589                                                 10 ? 1 : 2));
590                         break;
591                 case CUR_LOWER_THIRD:
592                         vgacon_set_cursor_size(c->vc_x,
593                                                (c->vc_cell_height * 2) / 3,
594                                                c->vc_cell_height -
595                                                (c->vc_cell_height <
596                                                 10 ? 1 : 2));
597                         break;
598                 case CUR_LOWER_HALF:
599                         vgacon_set_cursor_size(c->vc_x,
600                                                c->vc_cell_height / 2,
601                                                c->vc_cell_height -
602                                                (c->vc_cell_height <
603                                                 10 ? 1 : 2));
604                         break;
605                 case CUR_NONE:
606                         if (vga_video_type >= VIDEO_TYPE_VGAC)
607                                 vgacon_set_cursor_size(c->vc_x, 31, 30);
608                         else
609                                 vgacon_set_cursor_size(c->vc_x, 31, 31);
610                         break;
611                 default:
612                         vgacon_set_cursor_size(c->vc_x, 1,
613                                                c->vc_cell_height);
614                         break;
615                 }
616                 break;
617         }
618 }
619
620 static int vgacon_doresize(struct vc_data *c,
621                 unsigned int width, unsigned int height)
622 {
623         unsigned long flags;
624         unsigned int scanlines = height * c->vc_cell_height;
625         u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
626
627         raw_spin_lock_irqsave(&vga_lock, flags);
628
629         vgacon_xres = width * VGA_FONTWIDTH;
630         vgacon_yres = height * c->vc_cell_height;
631         if (vga_video_type >= VIDEO_TYPE_VGAC) {
632                 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
633                 max_scan = inb_p(vga_video_port_val);
634
635                 if (max_scan & 0x80)
636                         scanlines <<= 1;
637
638                 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
639                 mode = inb_p(vga_video_port_val);
640
641                 if (mode & 0x04)
642                         scanlines >>= 1;
643
644                 scanlines -= 1;
645                 scanlines_lo = scanlines & 0xff;
646
647                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
648                 r7 = inb_p(vga_video_port_val) & ~0x42;
649
650                 if (scanlines & 0x100)
651                         r7 |= 0x02;
652                 if (scanlines & 0x200)
653                         r7 |= 0x40;
654
655                 /* deprotect registers */
656                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
657                 vsync_end = inb_p(vga_video_port_val);
658                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
659                 outb_p(vsync_end & ~0x80, vga_video_port_val);
660         }
661
662         outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
663         outb_p(width - 1, vga_video_port_val);
664         outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
665         outb_p(width >> 1, vga_video_port_val);
666
667         if (vga_video_type >= VIDEO_TYPE_VGAC) {
668                 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
669                 outb_p(scanlines_lo, vga_video_port_val);
670                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
671                 outb_p(r7,vga_video_port_val);
672
673                 /* reprotect registers */
674                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
675                 outb_p(vsync_end, vga_video_port_val);
676         }
677
678         raw_spin_unlock_irqrestore(&vga_lock, flags);
679         return 0;
680 }
681
682 static int vgacon_switch(struct vc_data *c)
683 {
684         int x = c->vc_cols * VGA_FONTWIDTH;
685         int y = c->vc_rows * c->vc_cell_height;
686         int rows = screen_info.orig_video_lines * vga_default_font_height/
687                 c->vc_cell_height;
688         /*
689          * We need to save screen size here as it's the only way
690          * we can spot the screen has been resized and we need to
691          * set size of freshly allocated screens ourselves.
692          */
693         vga_video_num_columns = c->vc_cols;
694         vga_video_num_lines = c->vc_rows;
695
696         /* We can only copy out the size of the video buffer here,
697          * otherwise we get into VGA BIOS */
698
699         if (!vga_is_gfx) {
700                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
701                             c->vc_screenbuf_size > vga_vram_size ?
702                                 vga_vram_size : c->vc_screenbuf_size);
703
704                 if ((vgacon_xres != x || vgacon_yres != y) &&
705                     (!(vga_video_num_columns % 2) &&
706                      vga_video_num_columns <= screen_info.orig_video_cols &&
707                      vga_video_num_lines <= rows))
708                         vgacon_doresize(c, c->vc_cols, c->vc_rows);
709         }
710
711         return 0;               /* Redrawing not needed */
712 }
713
714 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
715 {
716         int i, j;
717
718         vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
719         for (i = j = 0; i < 16; i++) {
720                 vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
721                 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
722                 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
723                 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
724         }
725 }
726
727 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
728 {
729 #ifdef CAN_LOAD_PALETTE
730         if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
731             || !CON_IS_VISIBLE(vc))
732                 return -EINVAL;
733         vga_set_palette(vc, table);
734         return 0;
735 #else
736         return -EINVAL;
737 #endif
738 }
739
740 /* structure holding original VGA register settings */
741 static struct {
742         unsigned char SeqCtrlIndex;     /* Sequencer Index reg.   */
743         unsigned char CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
744         unsigned char CrtMiscIO;        /* Miscellaneous register */
745         unsigned char HorizontalTotal;  /* CRT-Controller:00h */
746         unsigned char HorizDisplayEnd;  /* CRT-Controller:01h */
747         unsigned char StartHorizRetrace;        /* CRT-Controller:04h */
748         unsigned char EndHorizRetrace;  /* CRT-Controller:05h */
749         unsigned char Overflow; /* CRT-Controller:07h */
750         unsigned char StartVertRetrace; /* CRT-Controller:10h */
751         unsigned char EndVertRetrace;   /* CRT-Controller:11h */
752         unsigned char ModeControl;      /* CRT-Controller:17h */
753         unsigned char ClockingMode;     /* Seq-Controller:01h */
754 } vga_state;
755
756 static void vga_vesa_blank(struct vgastate *state, int mode)
757 {
758         /* save original values of VGA controller registers */
759         if (!vga_vesa_blanked) {
760                 raw_spin_lock_irq(&vga_lock);
761                 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
762                 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
763                 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
764                 raw_spin_unlock_irq(&vga_lock);
765
766                 outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
767                 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
768                 outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
769                 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
770                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
771                 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
772                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
773                 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
774                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
775                 vga_state.Overflow = inb_p(vga_video_port_val);
776                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
777                 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
778                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
779                 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
780                 outb_p(0x17, vga_video_port_reg);       /* ModeControl */
781                 vga_state.ModeControl = inb_p(vga_video_port_val);
782                 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
783         }
784
785         /* assure that video is enabled */
786         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
787         raw_spin_lock_irq(&vga_lock);
788         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
789
790         /* test for vertical retrace in process.... */
791         if ((vga_state.CrtMiscIO & 0x80) == 0x80)
792                 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
793
794         /*
795          * Set <End of vertical retrace> to minimum (0) and
796          * <Start of vertical Retrace> to maximum (incl. overflow)
797          * Result: turn off vertical sync (VSync) pulse.
798          */
799         if (mode & VESA_VSYNC_SUSPEND) {
800                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
801                 outb_p(0xff, vga_video_port_val);       /* maximum value */
802                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
803                 outb_p(0x40, vga_video_port_val);       /* minimum (bits 0..3)  */
804                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
805                 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);  /* bits 9,10 of vert. retrace */
806         }
807
808         if (mode & VESA_HSYNC_SUSPEND) {
809                 /*
810                  * Set <End of horizontal retrace> to minimum (0) and
811                  *  <Start of horizontal Retrace> to maximum
812                  * Result: turn off horizontal sync (HSync) pulse.
813                  */
814                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
815                 outb_p(0xff, vga_video_port_val);       /* maximum */
816                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
817                 outb_p(0x00, vga_video_port_val);       /* minimum (0) */
818         }
819
820         /* restore both index registers */
821         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
822         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
823         raw_spin_unlock_irq(&vga_lock);
824 }
825
826 static void vga_vesa_unblank(struct vgastate *state)
827 {
828         /* restore original values of VGA controller registers */
829         raw_spin_lock_irq(&vga_lock);
830         vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
831
832         outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
833         outb_p(vga_state.HorizontalTotal, vga_video_port_val);
834         outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
835         outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
836         outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
837         outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
838         outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
839         outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
840         outb_p(0x07, vga_video_port_reg);       /* Overflow */
841         outb_p(vga_state.Overflow, vga_video_port_val);
842         outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
843         outb_p(vga_state.StartVertRetrace, vga_video_port_val);
844         outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
845         outb_p(vga_state.EndVertRetrace, vga_video_port_val);
846         outb_p(0x17, vga_video_port_reg);       /* ModeControl */
847         outb_p(vga_state.ModeControl, vga_video_port_val);
848         /* ClockingMode */
849         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
850
851         /* restore index/control registers */
852         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
853         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
854         raw_spin_unlock_irq(&vga_lock);
855 }
856
857 static void vga_pal_blank(struct vgastate *state)
858 {
859         int i;
860
861         vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
862         for (i = 0; i < 16; i++) {
863                 vga_w(state->vgabase, VGA_PEL_IW, i);
864                 vga_w(state->vgabase, VGA_PEL_D, 0);
865                 vga_w(state->vgabase, VGA_PEL_D, 0);
866                 vga_w(state->vgabase, VGA_PEL_D, 0);
867         }
868 }
869
870 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
871 {
872         switch (blank) {
873         case 0:         /* Unblank */
874                 if (vga_vesa_blanked) {
875                         vga_vesa_unblank(&vgastate);
876                         vga_vesa_blanked = 0;
877                 }
878                 if (vga_palette_blanked) {
879                         vga_set_palette(c, color_table);
880                         vga_palette_blanked = 0;
881                         return 0;
882                 }
883                 vga_is_gfx = 0;
884                 /* Tell console.c that it has to restore the screen itself */
885                 return 1;
886         case 1:         /* Normal blanking */
887         case -1:        /* Obsolete */
888                 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
889                         vga_pal_blank(&vgastate);
890                         vga_palette_blanked = 1;
891                         return 0;
892                 }
893                 vgacon_set_origin(c);
894                 scr_memsetw((void *) vga_vram_base, BLANK,
895                             c->vc_screenbuf_size);
896                 if (mode_switch)
897                         vga_is_gfx = 1;
898                 return 1;
899         default:                /* VESA blanking */
900                 if (vga_video_type == VIDEO_TYPE_VGAC) {
901                         vga_vesa_blank(&vgastate, blank - 1);
902                         vga_vesa_blanked = blank;
903                 }
904                 return 0;
905         }
906 }
907
908 /*
909  * PIO_FONT support.
910  *
911  * The font loading code goes back to the codepage package by
912  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
913  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
914  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
915  *
916  * Change for certain monochrome monitors by Yury Shevchuck
917  * (sizif@botik.yaroslavl.su).
918  */
919
920 #ifdef CAN_LOAD_EGA_FONTS
921
922 #define colourmap 0xa0000
923 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
924    should use 0xA0000 for the bwmap as well.. */
925 #define blackwmap 0xa0000
926 #define cmapsz 8192
927
928 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
929 {
930         unsigned short video_port_status = vga_video_port_reg + 6;
931         int font_select = 0x00, beg, i;
932         char *charmap;
933         bool clear_attribs = false;
934         if (vga_video_type != VIDEO_TYPE_EGAM) {
935                 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
936                 beg = 0x0e;
937 #ifdef VGA_CAN_DO_64KB
938                 if (vga_video_type == VIDEO_TYPE_VGAC)
939                         beg = 0x06;
940 #endif
941         } else {
942                 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
943                 beg = 0x0a;
944         }
945
946 #ifdef BROKEN_GRAPHICS_PROGRAMS
947         /*
948          * All fonts are loaded in slot 0 (0:1 for 512 ch)
949          */
950
951         if (!arg)
952                 return -EINVAL; /* Return to default font not supported */
953
954         vga_font_is_default = 0;
955         font_select = ch512 ? 0x04 : 0x00;
956 #else
957         /*
958          * The default font is kept in slot 0 and is never touched.
959          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
960          */
961
962         if (set) {
963                 vga_font_is_default = !arg;
964                 if (!arg)
965                         ch512 = 0;      /* Default font is always 256 */
966                 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
967         }
968
969         if (!vga_font_is_default)
970                 charmap += 4 * cmapsz;
971 #endif
972
973         raw_spin_lock_irq(&vga_lock);
974         /* First, the Sequencer */
975         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
976         /* CPU writes only to map 2 */
977         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);    
978         /* Sequential addressing */
979         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);    
980         /* Clear synchronous reset */
981         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
982
983         /* Now, the graphics controller, select map 2 */
984         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);             
985         /* disable odd-even addressing */
986         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
987         /* map start at A000:0000 */
988         vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
989         raw_spin_unlock_irq(&vga_lock);
990
991         if (arg) {
992                 if (set)
993                         for (i = 0; i < cmapsz; i++) {
994                                 vga_writeb(arg[i], charmap + i);
995                                 cond_resched();
996                         }
997                 else
998                         for (i = 0; i < cmapsz; i++) {
999                                 arg[i] = vga_readb(charmap + i);
1000                                 cond_resched();
1001                         }
1002
1003                 /*
1004                  * In 512-character mode, the character map is not contiguous if
1005                  * we want to remain EGA compatible -- which we do
1006                  */
1007
1008                 if (ch512) {
1009                         charmap += 2 * cmapsz;
1010                         arg += cmapsz;
1011                         if (set)
1012                                 for (i = 0; i < cmapsz; i++) {
1013                                         vga_writeb(arg[i], charmap + i);
1014                                         cond_resched();
1015                                 }
1016                         else
1017                                 for (i = 0; i < cmapsz; i++) {
1018                                         arg[i] = vga_readb(charmap + i);
1019                                         cond_resched();
1020                                 }
1021                 }
1022         }
1023
1024         raw_spin_lock_irq(&vga_lock);
1025         /* First, the sequencer, Synchronous reset */
1026         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);  
1027         /* CPU writes to maps 0 and 1 */
1028         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1029         /* odd-even addressing */
1030         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1031         /* Character Map Select */
1032         if (set)
1033                 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1034         /* clear synchronous reset */
1035         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1036
1037         /* Now, the graphics controller, select map 0 for CPU */
1038         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1039         /* enable even-odd addressing */
1040         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1041         /* map starts at b800:0 or b000:0 */
1042         vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1043
1044         /* if 512 char mode is already enabled don't re-enable it. */
1045         if ((set) && (ch512 != vga_512_chars)) {
1046                 vga_512_chars = ch512;
1047                 /* 256-char: enable intensity bit
1048                    512-char: disable intensity bit */
1049                 inb_p(video_port_status);       /* clear address flip-flop */
1050                 /* color plane enable register */
1051                 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1052                 /* Wilton (1987) mentions the following; I don't know what
1053                    it means, but it works, and it appears necessary */
1054                 inb_p(video_port_status);
1055                 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);    
1056                 clear_attribs = true;
1057         }
1058         raw_spin_unlock_irq(&vga_lock);
1059
1060         if (clear_attribs) {
1061                 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1062                         struct vc_data *c = vc_cons[i].d;
1063                         if (c && c->vc_sw == &vga_con) {
1064                                 /* force hi font mask to 0, so we always clear
1065                                    the bit on either transition */
1066                                 c->vc_hi_font_mask = 0x00;
1067                                 clear_buffer_attributes(c);
1068                                 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1069                         }
1070                 }
1071         }
1072         return 0;
1073 }
1074
1075 /*
1076  * Adjust the screen to fit a font of a certain height
1077  */
1078 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1079 {
1080         unsigned char ovr, vde, fsr;
1081         int rows, maxscan, i;
1082
1083         rows = vc->vc_scan_lines / fontheight;  /* Number of video rows we end up with */
1084         maxscan = rows * fontheight - 1;        /* Scan lines to actually display-1 */
1085
1086         /* Reprogram the CRTC for the new font size
1087            Note: the attempt to read the overflow register will fail
1088            on an EGA, but using 0xff for the previous value appears to
1089            be OK for EGA text modes in the range 257-512 scan lines, so I
1090            guess we don't need to worry about it.
1091
1092            The same applies for the spill bits in the font size and cursor
1093            registers; they are write-only on EGA, but it appears that they
1094            are all don't care bits on EGA, so I guess it doesn't matter. */
1095
1096         raw_spin_lock_irq(&vga_lock);
1097         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1098         ovr = inb_p(vga_video_port_val);
1099         outb_p(0x09, vga_video_port_reg);       /* Font size register */
1100         fsr = inb_p(vga_video_port_val);
1101         raw_spin_unlock_irq(&vga_lock);
1102
1103         vde = maxscan & 0xff;   /* Vertical display end reg */
1104         ovr = (ovr & 0xbd) +    /* Overflow register */
1105             ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1106         fsr = (fsr & 0xe0) + (fontheight - 1);  /*  Font size register */
1107
1108         raw_spin_lock_irq(&vga_lock);
1109         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1110         outb_p(ovr, vga_video_port_val);
1111         outb_p(0x09, vga_video_port_reg);       /* Font size */
1112         outb_p(fsr, vga_video_port_val);
1113         outb_p(0x12, vga_video_port_reg);       /* Vertical display limit */
1114         outb_p(vde, vga_video_port_val);
1115         raw_spin_unlock_irq(&vga_lock);
1116         vga_video_font_height = fontheight;
1117
1118         for (i = 0; i < MAX_NR_CONSOLES; i++) {
1119                 struct vc_data *c = vc_cons[i].d;
1120
1121                 if (c && c->vc_sw == &vga_con) {
1122                         if (CON_IS_VISIBLE(c)) {
1123                                 /* void size to cause regs to be rewritten */
1124                                 cursor_size_lastfrom = 0;
1125                                 cursor_size_lastto = 0;
1126                                 c->vc_sw->con_cursor(c, CM_DRAW);
1127                         }
1128                         c->vc_font.height = c->vc_cell_height = fontheight;
1129                         vc_resize(c, 0, rows);  /* Adjust console size */
1130                 }
1131         }
1132         return 0;
1133 }
1134
1135 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1136 {
1137         unsigned charcount = font->charcount;
1138         int rc;
1139
1140         if (vga_video_type < VIDEO_TYPE_EGAM)
1141                 return -EINVAL;
1142
1143         if (font->width != VGA_FONTWIDTH ||
1144             (charcount != 256 && charcount != 512))
1145                 return -EINVAL;
1146
1147         rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1148         if (rc)
1149                 return rc;
1150
1151         if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1152                 rc = vgacon_adjust_height(c, font->height);
1153         return rc;
1154 }
1155
1156 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1157 {
1158         if (vga_video_type < VIDEO_TYPE_EGAM)
1159                 return -EINVAL;
1160
1161         font->width = VGA_FONTWIDTH;
1162         font->height = c->vc_font.height;
1163         font->charcount = vga_512_chars ? 512 : 256;
1164         if (!font->data)
1165                 return 0;
1166         return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1167 }
1168
1169 #else
1170
1171 #define vgacon_font_set NULL
1172 #define vgacon_font_get NULL
1173
1174 #endif
1175
1176 static int vgacon_resize(struct vc_data *c, unsigned int width,
1177                          unsigned int height, unsigned int user)
1178 {
1179         if ((width << 1) * height > vga_vram_size)
1180                 return -EINVAL;
1181
1182         if (user) {
1183                 /*
1184                  * Ho ho!  Someone (svgatextmode, eh?) may have reprogrammed
1185                  * the video mode!  Set the new defaults then and go away.
1186                  */
1187                 screen_info.orig_video_cols = width;
1188                 screen_info.orig_video_lines = height;
1189                 vga_default_font_height = c->vc_cell_height;
1190                 return 0;
1191         }
1192         if (width % 2 || width > screen_info.orig_video_cols ||
1193             height > (screen_info.orig_video_lines * vga_default_font_height)/
1194             c->vc_cell_height)
1195                 return -EINVAL;
1196
1197         if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
1198                 vgacon_doresize(c, width, height);
1199         return 0;
1200 }
1201
1202 static int vgacon_set_origin(struct vc_data *c)
1203 {
1204         if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
1205             (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
1206                 return 0;
1207         c->vc_origin = c->vc_visible_origin = vga_vram_base;
1208         vga_set_mem_top(c);
1209         vga_rolled_over = 0;
1210         return 1;
1211 }
1212
1213 static void vgacon_save_screen(struct vc_data *c)
1214 {
1215         static int vga_bootup_console = 0;
1216
1217         if (!vga_bootup_console) {
1218                 /* This is a gross hack, but here is the only place we can
1219                  * set bootup console parameters without messing up generic
1220                  * console initialization routines.
1221                  */
1222                 vga_bootup_console = 1;
1223                 c->vc_x = screen_info.orig_x;
1224                 c->vc_y = screen_info.orig_y;
1225         }
1226
1227         /* We can't copy in more than the size of the video buffer,
1228          * or we'll be copying in VGA BIOS */
1229
1230         if (!vga_is_gfx)
1231                 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1232                             c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1233 }
1234
1235 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1236                          int lines)
1237 {
1238         unsigned long oldo;
1239         unsigned int delta;
1240
1241         if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1242                 return 0;
1243
1244         if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1245                 return 0;
1246
1247         vgacon_restore_screen(c);
1248         oldo = c->vc_origin;
1249         delta = lines * c->vc_size_row;
1250         if (dir == SM_UP) {
1251                 if (c->vc_scr_end + delta >= vga_vram_end) {
1252                         scr_memcpyw((u16 *) vga_vram_base,
1253                                     (u16 *) (oldo + delta),
1254                                     c->vc_screenbuf_size - delta);
1255                         c->vc_origin = vga_vram_base;
1256                         vga_rolled_over = oldo - vga_vram_base;
1257                 } else
1258                         c->vc_origin += delta;
1259                 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1260                                      delta), c->vc_video_erase_char,
1261                             delta);
1262         } else {
1263                 if (oldo - delta < vga_vram_base) {
1264                         scr_memmovew((u16 *) (vga_vram_end -
1265                                               c->vc_screenbuf_size +
1266                                               delta), (u16 *) oldo,
1267                                      c->vc_screenbuf_size - delta);
1268                         c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1269                         vga_rolled_over = 0;
1270                 } else
1271                         c->vc_origin -= delta;
1272                 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1273                 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1274                             delta);
1275         }
1276         c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1277         c->vc_visible_origin = c->vc_origin;
1278         vga_set_mem_top(c);
1279         c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1280         return 1;
1281 }
1282
1283
1284 /*
1285  *  The console `switch' structure for the VGA based console
1286  */
1287
1288 static int vgacon_dummy(struct vc_data *c)
1289 {
1290         return 0;
1291 }
1292
1293 #define DUMMY (void *) vgacon_dummy
1294
1295 const struct consw vga_con = {
1296         .owner = THIS_MODULE,
1297         .con_startup = vgacon_startup,
1298         .con_init = vgacon_init,
1299         .con_deinit = vgacon_deinit,
1300         .con_clear = DUMMY,
1301         .con_putc = DUMMY,
1302         .con_putcs = DUMMY,
1303         .con_cursor = vgacon_cursor,
1304         .con_scroll = vgacon_scroll,
1305         .con_bmove = DUMMY,
1306         .con_switch = vgacon_switch,
1307         .con_blank = vgacon_blank,
1308         .con_font_set = vgacon_font_set,
1309         .con_font_get = vgacon_font_get,
1310         .con_resize = vgacon_resize,
1311         .con_set_palette = vgacon_set_palette,
1312         .con_scrolldelta = vgacon_scrolldelta,
1313         .con_set_origin = vgacon_set_origin,
1314         .con_save_screen = vgacon_save_screen,
1315         .con_build_attr = vgacon_build_attr,
1316         .con_invert_region = vgacon_invert_region,
1317 };
1318 EXPORT_SYMBOL(vga_con);
1319
1320 MODULE_LICENSE("GPL");