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