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