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