Merge branch 'writeback' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.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 <linux/smp_lock.h>
51 #include <video/vga.h>
52 #include <asm/io.h>
53
54 static DEFINE_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 state;
60
61 #define BLANK 0x0020
62
63 #define CAN_LOAD_EGA_FONTS      /* undefine if the user must not do this */
64 #define CAN_LOAD_PALETTE        /* undefine if the user must not do this */
65
66 /* You really do _NOT_ want to define this, unless you have buggy
67  * Trident VGA which will resize cursor when moving it between column
68  * 15 & 16. If you define this and your VGA is OK, inverse bug will
69  * appear.
70  */
71 #undef TRIDENT_GLITCH
72 #define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */
73 /*
74  *  Interface used by the world
75  */
76
77 static const char *vgacon_startup(void);
78 static void vgacon_init(struct vc_data *c, int init);
79 static void vgacon_deinit(struct vc_data *c);
80 static void vgacon_cursor(struct vc_data *c, int mode);
81 static int vgacon_switch(struct vc_data *c);
82 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
83 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
84 static int vgacon_scrolldelta(struct vc_data *c, int lines);
85 static int vgacon_set_origin(struct vc_data *c);
86 static void vgacon_save_screen(struct vc_data *c);
87 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
88                          int lines);
89 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
90 static unsigned long vgacon_uni_pagedir[2];
91
92 /* Description of the hardware situation */
93 static int              vga_init_done           __read_mostly;
94 static unsigned long    vga_vram_base           __read_mostly;  /* Base of video memory */
95 static unsigned long    vga_vram_end            __read_mostly;  /* End of video memory */
96 static unsigned int     vga_vram_size           __read_mostly;  /* Size of video memory */
97 static u16              vga_video_port_reg      __read_mostly;  /* Video register select port */
98 static u16              vga_video_port_val      __read_mostly;  /* Video register value port */
99 static unsigned int     vga_video_num_columns;                  /* Number of text columns */
100 static unsigned int     vga_video_num_lines;                    /* Number of text lines */
101 static int              vga_can_do_color        __read_mostly;  /* Do we support colors? */
102 static unsigned int     vga_default_font_height __read_mostly;  /* Height of default screen font */
103 static unsigned char    vga_video_type          __read_mostly;  /* Card type */
104 static unsigned char    vga_hardscroll_enabled  __read_mostly;
105 static unsigned char    vga_hardscroll_user_enable __read_mostly = 1;
106 static unsigned char    vga_font_is_default = 1;
107 static int              vga_vesa_blanked;
108 static int              vga_palette_blanked;
109 static int              vga_is_gfx;
110 static int              vga_512_chars;
111 static int              vga_video_font_height;
112 static int              vga_scan_lines          __read_mostly;
113 static unsigned int     vga_rolled_over;
114
115 int vgacon_text_mode_force = 0;
116
117 bool vgacon_text_force(void)
118 {
119         return vgacon_text_mode_force ? true : false;
120 }
121 EXPORT_SYMBOL(vgacon_text_force);
122
123 static int __init text_mode(char *str)
124 {
125         vgacon_text_mode_force = 1;
126         return 1;
127 }
128
129 /* force text mode - used by kernel modesetting */
130 __setup("nomodeset", text_mode);
131
132 static int __init no_scroll(char *str)
133 {
134         /*
135          * Disabling scrollback is required for the Braillex ib80-piezo
136          * Braille reader made by F.H. Papenmeier (Germany).
137          * Use the "no-scroll" bootflag.
138          */
139         vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
140         return 1;
141 }
142
143 __setup("no-scroll", no_scroll);
144
145 /*
146  * By replacing the four outb_p with two back to back outw, we can reduce
147  * the window of opportunity to see text mislocated to the RHS of the
148  * console during heavy scrolling activity. However there is the remote
149  * possibility that some pre-dinosaur hardware won't like the back to back
150  * I/O. Since the Xservers get away with it, we should be able to as well.
151  */
152 static inline void write_vga(unsigned char reg, unsigned int val)
153 {
154         unsigned int v1, v2;
155         unsigned long flags;
156
157         /*
158          * ddprintk might set the console position from interrupt
159          * handlers, thus the write has to be IRQ-atomic.
160          */
161         spin_lock_irqsave(&vga_lock, flags);
162
163 #ifndef SLOW_VGA
164         v1 = reg + (val & 0xff00);
165         v2 = reg + 1 + ((val << 8) & 0xff00);
166         outw(v1, vga_video_port_reg);
167         outw(v2, vga_video_port_reg);
168 #else
169         outb_p(reg, vga_video_port_reg);
170         outb_p(val >> 8, vga_video_port_val);
171         outb_p(reg + 1, vga_video_port_reg);
172         outb_p(val & 0xff, vga_video_port_val);
173 #endif
174         spin_unlock_irqrestore(&vga_lock, flags);
175 }
176
177 static inline void vga_set_mem_top(struct vc_data *c)
178 {
179         write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
180 }
181
182 #ifdef CONFIG_VGACON_SOFT_SCROLLBACK
183 /* software scrollback */
184 static void *vgacon_scrollback;
185 static int vgacon_scrollback_tail;
186 static int vgacon_scrollback_size;
187 static int vgacon_scrollback_rows;
188 static int vgacon_scrollback_cnt;
189 static int vgacon_scrollback_cur;
190 static int vgacon_scrollback_save;
191 static int vgacon_scrollback_restore;
192
193 static void vgacon_scrollback_init(int pitch)
194 {
195         int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;
196
197         if (vgacon_scrollback) {
198                 vgacon_scrollback_cnt  = 0;
199                 vgacon_scrollback_tail = 0;
200                 vgacon_scrollback_cur  = 0;
201                 vgacon_scrollback_rows = rows - 1;
202                 vgacon_scrollback_size = rows * pitch;
203         }
204 }
205
206 /*
207  * Called only duing init so call of alloc_bootmen is ok.
208  * Marked __init_refok to silence modpost.
209  */
210 static void __init_refok vgacon_scrollback_startup(void)
211 {
212         vgacon_scrollback = kcalloc(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE, 1024, GFP_NOWAIT);
213         vgacon_scrollback_init(vga_video_num_columns * 2);
214 }
215
216 static void vgacon_scrollback_update(struct vc_data *c, int t, int count)
217 {
218         void *p;
219
220         if (!vgacon_scrollback_size || c->vc_num != fg_console)
221                 return;
222
223         p = (void *) (c->vc_origin + t * c->vc_size_row);
224
225         while (count--) {
226                 scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,
227                             p, c->vc_size_row);
228                 vgacon_scrollback_cnt++;
229                 p += c->vc_size_row;
230                 vgacon_scrollback_tail += c->vc_size_row;
231
232                 if (vgacon_scrollback_tail >= vgacon_scrollback_size)
233                         vgacon_scrollback_tail = 0;
234
235                 if (vgacon_scrollback_cnt > vgacon_scrollback_rows)
236                         vgacon_scrollback_cnt = vgacon_scrollback_rows;
237
238                 vgacon_scrollback_cur = vgacon_scrollback_cnt;
239         }
240 }
241
242 static void vgacon_restore_screen(struct vc_data *c)
243 {
244         vgacon_scrollback_save = 0;
245
246         if (!vga_is_gfx && !vgacon_scrollback_restore) {
247                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
248                             c->vc_screenbuf_size > vga_vram_size ?
249                             vga_vram_size : c->vc_screenbuf_size);
250                 vgacon_scrollback_restore = 1;
251                 vgacon_scrollback_cur = vgacon_scrollback_cnt;
252         }
253 }
254
255 static int vgacon_scrolldelta(struct vc_data *c, int lines)
256 {
257         int start, end, count, soff;
258
259         if (!lines) {
260                 c->vc_visible_origin = c->vc_origin;
261                 vga_set_mem_top(c);
262                 return 1;
263         }
264
265         if (!vgacon_scrollback)
266                 return 1;
267
268         if (!vgacon_scrollback_save) {
269                 vgacon_cursor(c, CM_ERASE);
270                 vgacon_save_screen(c);
271                 vgacon_scrollback_save = 1;
272         }
273
274         vgacon_scrollback_restore = 0;
275         start = vgacon_scrollback_cur + lines;
276         end = start + abs(lines);
277
278         if (start < 0)
279                 start = 0;
280
281         if (start > vgacon_scrollback_cnt)
282                 start = vgacon_scrollback_cnt;
283
284         if (end < 0)
285                 end = 0;
286
287         if (end > vgacon_scrollback_cnt)
288                 end = vgacon_scrollback_cnt;
289
290         vgacon_scrollback_cur = start;
291         count = end - start;
292         soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *
293                                          c->vc_size_row);
294         soff -= count * c->vc_size_row;
295
296         if (soff < 0)
297                 soff += vgacon_scrollback_size;
298
299         count = vgacon_scrollback_cnt - start;
300
301         if (count > c->vc_rows)
302                 count = c->vc_rows;
303
304         if (count) {
305                 int copysize;
306
307                 int diff = c->vc_rows - count;
308                 void *d = (void *) c->vc_origin;
309                 void *s = (void *) c->vc_screenbuf;
310
311                 count *= c->vc_size_row;
312                 /* how much memory to end of buffer left? */
313                 copysize = min(count, vgacon_scrollback_size - soff);
314                 scr_memcpyw(d, vgacon_scrollback + soff, copysize);
315                 d += copysize;
316                 count -= copysize;
317
318                 if (count) {
319                         scr_memcpyw(d, vgacon_scrollback, count);
320                         d += count;
321                 }
322
323                 if (diff)
324                         scr_memcpyw(d, s, diff * c->vc_size_row);
325         } else
326                 vgacon_cursor(c, CM_MOVE);
327
328         return 1;
329 }
330 #else
331 #define vgacon_scrollback_startup(...) do { } while (0)
332 #define vgacon_scrollback_init(...)    do { } while (0)
333 #define vgacon_scrollback_update(...)  do { } while (0)
334
335 static void vgacon_restore_screen(struct vc_data *c)
336 {
337         if (c->vc_origin != c->vc_visible_origin)
338                 vgacon_scrolldelta(c, 0);
339 }
340
341 static int vgacon_scrolldelta(struct vc_data *c, int lines)
342 {
343         if (!lines)             /* Turn scrollback off */
344                 c->vc_visible_origin = c->vc_origin;
345         else {
346                 int margin = c->vc_size_row * 4;
347                 int ul, we, p, st;
348
349                 if (vga_rolled_over >
350                     (c->vc_scr_end - vga_vram_base) + margin) {
351                         ul = c->vc_scr_end - vga_vram_base;
352                         we = vga_rolled_over + c->vc_size_row;
353                 } else {
354                         ul = 0;
355                         we = vga_vram_size;
356                 }
357                 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
358                     lines * c->vc_size_row;
359                 st = (c->vc_origin - vga_vram_base - ul + we) % we;
360                 if (st < 2 * margin)
361                         margin = 0;
362                 if (p < margin)
363                         p = 0;
364                 if (p > st - margin)
365                         p = st;
366                 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
367         }
368         vga_set_mem_top(c);
369         return 1;
370 }
371 #endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
372
373 static const char *vgacon_startup(void)
374 {
375         const char *display_desc = NULL;
376         u16 saved1, saved2;
377         volatile u16 *p;
378
379         if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) {
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
590 static void vgacon_deinit(struct vc_data *c)
591 {
592         /* When closing the last console, reset video origin */
593         if (!--vgacon_uni_pagedir[1]) {
594                 c->vc_visible_origin = vga_vram_base;
595                 vga_set_mem_top(c);
596                 con_free_unimap(c);
597         }
598         c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
599         con_set_default_unimap(c);
600 }
601
602 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
603                             u8 blink, u8 underline, u8 reverse, u8 italic)
604 {
605         u8 attr = color;
606
607         if (vga_can_do_color) {
608                 if (italic)
609                         attr = (attr & 0xF0) | c->vc_itcolor;
610                 else if (underline)
611                         attr = (attr & 0xf0) | c->vc_ulcolor;
612                 else if (intensity == 0)
613                         attr = (attr & 0xf0) | c->vc_halfcolor;
614         }
615         if (reverse)
616                 attr =
617                     ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
618                                        0x77);
619         if (blink)
620                 attr ^= 0x80;
621         if (intensity == 2)
622                 attr ^= 0x08;
623         if (!vga_can_do_color) {
624                 if (italic)
625                         attr = (attr & 0xF8) | 0x02;
626                 else if (underline)
627                         attr = (attr & 0xf8) | 0x01;
628                 else if (intensity == 0)
629                         attr = (attr & 0xf0) | 0x08;
630         }
631         return attr;
632 }
633
634 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
635 {
636         int col = vga_can_do_color;
637
638         while (count--) {
639                 u16 a = scr_readw(p);
640                 if (col)
641                         a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
642                             (((a) & 0x0700) << 4);
643                 else
644                         a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
645                 scr_writew(a, p++);
646         }
647 }
648
649 static void vgacon_set_cursor_size(int xpos, int from, int to)
650 {
651         unsigned long flags;
652         int curs, cure;
653
654 #ifdef TRIDENT_GLITCH
655         if (xpos < 16)
656                 from--, to--;
657 #endif
658
659         if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
660                 return;
661         cursor_size_lastfrom = from;
662         cursor_size_lastto = to;
663
664         spin_lock_irqsave(&vga_lock, flags);
665         if (vga_video_type >= VIDEO_TYPE_VGAC) {
666                 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
667                 curs = inb_p(vga_video_port_val);
668                 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
669                 cure = inb_p(vga_video_port_val);
670         } else {
671                 curs = 0;
672                 cure = 0;
673         }
674
675         curs = (curs & 0xc0) | from;
676         cure = (cure & 0xe0) | to;
677
678         outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
679         outb_p(curs, vga_video_port_val);
680         outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
681         outb_p(cure, vga_video_port_val);
682         spin_unlock_irqrestore(&vga_lock, flags);
683 }
684
685 static void vgacon_cursor(struct vc_data *c, int mode)
686 {
687         if (c->vc_mode != KD_TEXT)
688                 return;
689
690         vgacon_restore_screen(c);
691
692         switch (mode) {
693         case CM_ERASE:
694                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
695                 if (vga_video_type >= VIDEO_TYPE_VGAC)
696                         vgacon_set_cursor_size(c->vc_x, 31, 30);
697                 else
698                         vgacon_set_cursor_size(c->vc_x, 31, 31);
699                 break;
700
701         case CM_MOVE:
702         case CM_DRAW:
703                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
704                 switch (c->vc_cursor_type & 0x0f) {
705                 case CUR_UNDERLINE:
706                         vgacon_set_cursor_size(c->vc_x,
707                                                c->vc_font.height -
708                                                (c->vc_font.height <
709                                                 10 ? 2 : 3),
710                                                c->vc_font.height -
711                                                (c->vc_font.height <
712                                                 10 ? 1 : 2));
713                         break;
714                 case CUR_TWO_THIRDS:
715                         vgacon_set_cursor_size(c->vc_x,
716                                                c->vc_font.height / 3,
717                                                c->vc_font.height -
718                                                (c->vc_font.height <
719                                                 10 ? 1 : 2));
720                         break;
721                 case CUR_LOWER_THIRD:
722                         vgacon_set_cursor_size(c->vc_x,
723                                                (c->vc_font.height * 2) / 3,
724                                                c->vc_font.height -
725                                                (c->vc_font.height <
726                                                 10 ? 1 : 2));
727                         break;
728                 case CUR_LOWER_HALF:
729                         vgacon_set_cursor_size(c->vc_x,
730                                                c->vc_font.height / 2,
731                                                c->vc_font.height -
732                                                (c->vc_font.height <
733                                                 10 ? 1 : 2));
734                         break;
735                 case CUR_NONE:
736                         if (vga_video_type >= VIDEO_TYPE_VGAC)
737                                 vgacon_set_cursor_size(c->vc_x, 31, 30);
738                         else
739                                 vgacon_set_cursor_size(c->vc_x, 31, 31);
740                         break;
741                 default:
742                         vgacon_set_cursor_size(c->vc_x, 1,
743                                                c->vc_font.height);
744                         break;
745                 }
746                 break;
747         }
748 }
749
750 static int vgacon_doresize(struct vc_data *c,
751                 unsigned int width, unsigned int height)
752 {
753         unsigned long flags;
754         unsigned int scanlines = height * c->vc_font.height;
755         u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
756
757         spin_lock_irqsave(&vga_lock, flags);
758
759         vgacon_xres = width * VGA_FONTWIDTH;
760         vgacon_yres = height * c->vc_font.height;
761         if (vga_video_type >= VIDEO_TYPE_VGAC) {
762                 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
763                 max_scan = inb_p(vga_video_port_val);
764
765                 if (max_scan & 0x80)
766                         scanlines <<= 1;
767
768                 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
769                 mode = inb_p(vga_video_port_val);
770
771                 if (mode & 0x04)
772                         scanlines >>= 1;
773
774                 scanlines -= 1;
775                 scanlines_lo = scanlines & 0xff;
776
777                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
778                 r7 = inb_p(vga_video_port_val) & ~0x42;
779
780                 if (scanlines & 0x100)
781                         r7 |= 0x02;
782                 if (scanlines & 0x200)
783                         r7 |= 0x40;
784
785                 /* deprotect registers */
786                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
787                 vsync_end = inb_p(vga_video_port_val);
788                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
789                 outb_p(vsync_end & ~0x80, vga_video_port_val);
790         }
791
792         outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
793         outb_p(width - 1, vga_video_port_val);
794         outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
795         outb_p(width >> 1, vga_video_port_val);
796
797         if (vga_video_type >= VIDEO_TYPE_VGAC) {
798                 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
799                 outb_p(scanlines_lo, vga_video_port_val);
800                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
801                 outb_p(r7,vga_video_port_val);
802
803                 /* reprotect registers */
804                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
805                 outb_p(vsync_end, vga_video_port_val);
806         }
807
808         spin_unlock_irqrestore(&vga_lock, flags);
809         return 0;
810 }
811
812 static int vgacon_switch(struct vc_data *c)
813 {
814         int x = c->vc_cols * VGA_FONTWIDTH;
815         int y = c->vc_rows * c->vc_font.height;
816         int rows = screen_info.orig_video_lines * vga_default_font_height/
817                 c->vc_font.height;
818         /*
819          * We need to save screen size here as it's the only way
820          * we can spot the screen has been resized and we need to
821          * set size of freshly allocated screens ourselves.
822          */
823         vga_video_num_columns = c->vc_cols;
824         vga_video_num_lines = c->vc_rows;
825
826         /* We can only copy out the size of the video buffer here,
827          * otherwise we get into VGA BIOS */
828
829         if (!vga_is_gfx) {
830                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
831                             c->vc_screenbuf_size > vga_vram_size ?
832                                 vga_vram_size : c->vc_screenbuf_size);
833
834                 if ((vgacon_xres != x || vgacon_yres != y) &&
835                     (!(vga_video_num_columns % 2) &&
836                      vga_video_num_columns <= screen_info.orig_video_cols &&
837                      vga_video_num_lines <= rows))
838                         vgacon_doresize(c, c->vc_cols, c->vc_rows);
839         }
840
841         vgacon_scrollback_init(c->vc_size_row);
842         return 0;               /* Redrawing not needed */
843 }
844
845 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
846 {
847         int i, j;
848
849         vga_w(state.vgabase, VGA_PEL_MSK, 0xff);
850         for (i = j = 0; i < 16; i++) {
851                 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
852                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
853                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
854                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
855         }
856 }
857
858 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
859 {
860 #ifdef CAN_LOAD_PALETTE
861         if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
862             || !CON_IS_VISIBLE(vc))
863                 return -EINVAL;
864         vga_set_palette(vc, table);
865         return 0;
866 #else
867         return -EINVAL;
868 #endif
869 }
870
871 /* structure holding original VGA register settings */
872 static struct {
873         unsigned char SeqCtrlIndex;     /* Sequencer Index reg.   */
874         unsigned char CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
875         unsigned char CrtMiscIO;        /* Miscellaneous register */
876         unsigned char HorizontalTotal;  /* CRT-Controller:00h */
877         unsigned char HorizDisplayEnd;  /* CRT-Controller:01h */
878         unsigned char StartHorizRetrace;        /* CRT-Controller:04h */
879         unsigned char EndHorizRetrace;  /* CRT-Controller:05h */
880         unsigned char Overflow; /* CRT-Controller:07h */
881         unsigned char StartVertRetrace; /* CRT-Controller:10h */
882         unsigned char EndVertRetrace;   /* CRT-Controller:11h */
883         unsigned char ModeControl;      /* CRT-Controller:17h */
884         unsigned char ClockingMode;     /* Seq-Controller:01h */
885 } vga_state;
886
887 static void vga_vesa_blank(struct vgastate *state, int mode)
888 {
889         /* save original values of VGA controller registers */
890         if (!vga_vesa_blanked) {
891                 spin_lock_irq(&vga_lock);
892                 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
893                 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
894                 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
895                 spin_unlock_irq(&vga_lock);
896
897                 outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
898                 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
899                 outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
900                 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
901                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
902                 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
903                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
904                 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
905                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
906                 vga_state.Overflow = inb_p(vga_video_port_val);
907                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
908                 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
909                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
910                 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
911                 outb_p(0x17, vga_video_port_reg);       /* ModeControl */
912                 vga_state.ModeControl = inb_p(vga_video_port_val);
913                 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
914         }
915
916         /* assure that video is enabled */
917         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
918         spin_lock_irq(&vga_lock);
919         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
920
921         /* test for vertical retrace in process.... */
922         if ((vga_state.CrtMiscIO & 0x80) == 0x80)
923                 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
924
925         /*
926          * Set <End of vertical retrace> to minimum (0) and
927          * <Start of vertical Retrace> to maximum (incl. overflow)
928          * Result: turn off vertical sync (VSync) pulse.
929          */
930         if (mode & VESA_VSYNC_SUSPEND) {
931                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
932                 outb_p(0xff, vga_video_port_val);       /* maximum value */
933                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
934                 outb_p(0x40, vga_video_port_val);       /* minimum (bits 0..3)  */
935                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
936                 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);  /* bits 9,10 of vert. retrace */
937         }
938
939         if (mode & VESA_HSYNC_SUSPEND) {
940                 /*
941                  * Set <End of horizontal retrace> to minimum (0) and
942                  *  <Start of horizontal Retrace> to maximum
943                  * Result: turn off horizontal sync (HSync) pulse.
944                  */
945                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
946                 outb_p(0xff, vga_video_port_val);       /* maximum */
947                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
948                 outb_p(0x00, vga_video_port_val);       /* minimum (0) */
949         }
950
951         /* restore both index registers */
952         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
953         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
954         spin_unlock_irq(&vga_lock);
955 }
956
957 static void vga_vesa_unblank(struct vgastate *state)
958 {
959         /* restore original values of VGA controller registers */
960         spin_lock_irq(&vga_lock);
961         vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
962
963         outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
964         outb_p(vga_state.HorizontalTotal, vga_video_port_val);
965         outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
966         outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
967         outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
968         outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
969         outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
970         outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
971         outb_p(0x07, vga_video_port_reg);       /* Overflow */
972         outb_p(vga_state.Overflow, vga_video_port_val);
973         outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
974         outb_p(vga_state.StartVertRetrace, vga_video_port_val);
975         outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
976         outb_p(vga_state.EndVertRetrace, vga_video_port_val);
977         outb_p(0x17, vga_video_port_reg);       /* ModeControl */
978         outb_p(vga_state.ModeControl, vga_video_port_val);
979         /* ClockingMode */
980         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
981
982         /* restore index/control registers */
983         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
984         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
985         spin_unlock_irq(&vga_lock);
986 }
987
988 static void vga_pal_blank(struct vgastate *state)
989 {
990         int i;
991
992         vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
993         for (i = 0; i < 16; i++) {
994                 vga_w(state->vgabase, VGA_PEL_IW, i);
995                 vga_w(state->vgabase, VGA_PEL_D, 0);
996                 vga_w(state->vgabase, VGA_PEL_D, 0);
997                 vga_w(state->vgabase, VGA_PEL_D, 0);
998         }
999 }
1000
1001 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
1002 {
1003         switch (blank) {
1004         case 0:         /* Unblank */
1005                 if (vga_vesa_blanked) {
1006                         vga_vesa_unblank(&state);
1007                         vga_vesa_blanked = 0;
1008                 }
1009                 if (vga_palette_blanked) {
1010                         vga_set_palette(c, color_table);
1011                         vga_palette_blanked = 0;
1012                         return 0;
1013                 }
1014                 vga_is_gfx = 0;
1015                 /* Tell console.c that it has to restore the screen itself */
1016                 return 1;
1017         case 1:         /* Normal blanking */
1018         case -1:        /* Obsolete */
1019                 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
1020                         vga_pal_blank(&state);
1021                         vga_palette_blanked = 1;
1022                         return 0;
1023                 }
1024                 vgacon_set_origin(c);
1025                 scr_memsetw((void *) vga_vram_base, BLANK,
1026                             c->vc_screenbuf_size);
1027                 if (mode_switch)
1028                         vga_is_gfx = 1;
1029                 return 1;
1030         default:                /* VESA blanking */
1031                 if (vga_video_type == VIDEO_TYPE_VGAC) {
1032                         vga_vesa_blank(&state, blank - 1);
1033                         vga_vesa_blanked = blank;
1034                 }
1035                 return 0;
1036         }
1037 }
1038
1039 /*
1040  * PIO_FONT support.
1041  *
1042  * The font loading code goes back to the codepage package by
1043  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
1044  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
1045  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
1046  *
1047  * Change for certain monochrome monitors by Yury Shevchuck
1048  * (sizif@botik.yaroslavl.su).
1049  */
1050
1051 #ifdef CAN_LOAD_EGA_FONTS
1052
1053 #define colourmap 0xa0000
1054 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
1055    should use 0xA0000 for the bwmap as well.. */
1056 #define blackwmap 0xa0000
1057 #define cmapsz 8192
1058
1059 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1060 {
1061         unsigned short video_port_status = vga_video_port_reg + 6;
1062         int font_select = 0x00, beg, i;
1063         char *charmap;
1064         
1065         if (vga_video_type != VIDEO_TYPE_EGAM) {
1066                 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
1067                 beg = 0x0e;
1068 #ifdef VGA_CAN_DO_64KB
1069                 if (vga_video_type == VIDEO_TYPE_VGAC)
1070                         beg = 0x06;
1071 #endif
1072         } else {
1073                 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
1074                 beg = 0x0a;
1075         }
1076
1077 #ifdef BROKEN_GRAPHICS_PROGRAMS
1078         /*
1079          * All fonts are loaded in slot 0 (0:1 for 512 ch)
1080          */
1081
1082         if (!arg)
1083                 return -EINVAL; /* Return to default font not supported */
1084
1085         vga_font_is_default = 0;
1086         font_select = ch512 ? 0x04 : 0x00;
1087 #else
1088         /*
1089          * The default font is kept in slot 0 and is never touched.
1090          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
1091          */
1092
1093         if (set) {
1094                 vga_font_is_default = !arg;
1095                 if (!arg)
1096                         ch512 = 0;      /* Default font is always 256 */
1097                 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
1098         }
1099
1100         if (!vga_font_is_default)
1101                 charmap += 4 * cmapsz;
1102 #endif
1103
1104         unlock_kernel();
1105         spin_lock_irq(&vga_lock);
1106         /* First, the Sequencer */
1107         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
1108         /* CPU writes only to map 2 */
1109         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);    
1110         /* Sequential addressing */
1111         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);    
1112         /* Clear synchronous reset */
1113         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1114
1115         /* Now, the graphics controller, select map 2 */
1116         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);             
1117         /* disable odd-even addressing */
1118         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
1119         /* map start at A000:0000 */
1120         vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
1121         spin_unlock_irq(&vga_lock);
1122
1123         if (arg) {
1124                 if (set)
1125                         for (i = 0; i < cmapsz; i++)
1126                                 vga_writeb(arg[i], charmap + i);
1127                 else
1128                         for (i = 0; i < cmapsz; i++)
1129                                 arg[i] = vga_readb(charmap + i);
1130
1131                 /*
1132                  * In 512-character mode, the character map is not contiguous if
1133                  * we want to remain EGA compatible -- which we do
1134                  */
1135
1136                 if (ch512) {
1137                         charmap += 2 * cmapsz;
1138                         arg += cmapsz;
1139                         if (set)
1140                                 for (i = 0; i < cmapsz; i++)
1141                                         vga_writeb(arg[i], charmap + i);
1142                         else
1143                                 for (i = 0; i < cmapsz; i++)
1144                                         arg[i] = vga_readb(charmap + i);
1145                 }
1146         }
1147
1148         spin_lock_irq(&vga_lock);
1149         /* First, the sequencer, Synchronous reset */
1150         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);  
1151         /* CPU writes to maps 0 and 1 */
1152         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1153         /* odd-even addressing */
1154         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1155         /* Character Map Select */
1156         if (set)
1157                 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1158         /* clear synchronous reset */
1159         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1160
1161         /* Now, the graphics controller, select map 0 for CPU */
1162         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1163         /* enable even-odd addressing */
1164         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1165         /* map starts at b800:0 or b000:0 */
1166         vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1167
1168         /* if 512 char mode is already enabled don't re-enable it. */
1169         if ((set) && (ch512 != vga_512_chars)) {
1170                 /* attribute controller */
1171                 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1172                         struct vc_data *c = vc_cons[i].d;
1173                         if (c && c->vc_sw == &vga_con)
1174                                 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1175                 }
1176                 vga_512_chars = ch512;
1177                 /* 256-char: enable intensity bit
1178                    512-char: disable intensity bit */
1179                 inb_p(video_port_status);       /* clear address flip-flop */
1180                 /* color plane enable register */
1181                 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1182                 /* Wilton (1987) mentions the following; I don't know what
1183                    it means, but it works, and it appears necessary */
1184                 inb_p(video_port_status);
1185                 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);    
1186         }
1187         spin_unlock_irq(&vga_lock);
1188         lock_kernel();
1189         return 0;
1190 }
1191
1192 /*
1193  * Adjust the screen to fit a font of a certain height
1194  */
1195 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1196 {
1197         unsigned char ovr, vde, fsr;
1198         int rows, maxscan, i;
1199
1200         rows = vc->vc_scan_lines / fontheight;  /* Number of video rows we end up with */
1201         maxscan = rows * fontheight - 1;        /* Scan lines to actually display-1 */
1202
1203         /* Reprogram the CRTC for the new font size
1204            Note: the attempt to read the overflow register will fail
1205            on an EGA, but using 0xff for the previous value appears to
1206            be OK for EGA text modes in the range 257-512 scan lines, so I
1207            guess we don't need to worry about it.
1208
1209            The same applies for the spill bits in the font size and cursor
1210            registers; they are write-only on EGA, but it appears that they
1211            are all don't care bits on EGA, so I guess it doesn't matter. */
1212
1213         spin_lock_irq(&vga_lock);
1214         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1215         ovr = inb_p(vga_video_port_val);
1216         outb_p(0x09, vga_video_port_reg);       /* Font size register */
1217         fsr = inb_p(vga_video_port_val);
1218         spin_unlock_irq(&vga_lock);
1219
1220         vde = maxscan & 0xff;   /* Vertical display end reg */
1221         ovr = (ovr & 0xbd) +    /* Overflow register */
1222             ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1223         fsr = (fsr & 0xe0) + (fontheight - 1);  /*  Font size register */
1224
1225         spin_lock_irq(&vga_lock);
1226         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1227         outb_p(ovr, vga_video_port_val);
1228         outb_p(0x09, vga_video_port_reg);       /* Font size */
1229         outb_p(fsr, vga_video_port_val);
1230         outb_p(0x12, vga_video_port_reg);       /* Vertical display limit */
1231         outb_p(vde, vga_video_port_val);
1232         spin_unlock_irq(&vga_lock);
1233         vga_video_font_height = fontheight;
1234
1235         for (i = 0; i < MAX_NR_CONSOLES; i++) {
1236                 struct vc_data *c = vc_cons[i].d;
1237
1238                 if (c && c->vc_sw == &vga_con) {
1239                         if (CON_IS_VISIBLE(c)) {
1240                                 /* void size to cause regs to be rewritten */
1241                                 cursor_size_lastfrom = 0;
1242                                 cursor_size_lastto = 0;
1243                                 c->vc_sw->con_cursor(c, CM_DRAW);
1244                         }
1245                         c->vc_font.height = fontheight;
1246                         vc_resize(c, 0, rows);  /* Adjust console size */
1247                 }
1248         }
1249         return 0;
1250 }
1251
1252 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1253 {
1254         unsigned charcount = font->charcount;
1255         int rc;
1256
1257         if (vga_video_type < VIDEO_TYPE_EGAM)
1258                 return -EINVAL;
1259
1260         if (font->width != VGA_FONTWIDTH ||
1261             (charcount != 256 && charcount != 512))
1262                 return -EINVAL;
1263
1264         rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
1265         if (rc)
1266                 return rc;
1267
1268         if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1269                 rc = vgacon_adjust_height(c, font->height);
1270         return rc;
1271 }
1272
1273 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1274 {
1275         if (vga_video_type < VIDEO_TYPE_EGAM)
1276                 return -EINVAL;
1277
1278         font->width = VGA_FONTWIDTH;
1279         font->height = c->vc_font.height;
1280         font->charcount = vga_512_chars ? 512 : 256;
1281         if (!font->data)
1282                 return 0;
1283         return vgacon_do_font_op(&state, font->data, 0, vga_512_chars);
1284 }
1285
1286 #else
1287
1288 #define vgacon_font_set NULL
1289 #define vgacon_font_get NULL
1290
1291 #endif
1292
1293 static int vgacon_resize(struct vc_data *c, unsigned int width,
1294                          unsigned int height, unsigned int user)
1295 {
1296         if (width % 2 || width > screen_info.orig_video_cols ||
1297             height > (screen_info.orig_video_lines * vga_default_font_height)/
1298             c->vc_font.height)
1299                 /* let svgatextmode tinker with video timings and
1300                    return success */
1301                 return (user) ? 0 : -EINVAL;
1302
1303         if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
1304                 vgacon_doresize(c, width, height);
1305         return 0;
1306 }
1307
1308 static int vgacon_set_origin(struct vc_data *c)
1309 {
1310         if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
1311             (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
1312                 return 0;
1313         c->vc_origin = c->vc_visible_origin = vga_vram_base;
1314         vga_set_mem_top(c);
1315         vga_rolled_over = 0;
1316         return 1;
1317 }
1318
1319 static void vgacon_save_screen(struct vc_data *c)
1320 {
1321         static int vga_bootup_console = 0;
1322
1323         if (!vga_bootup_console) {
1324                 /* This is a gross hack, but here is the only place we can
1325                  * set bootup console parameters without messing up generic
1326                  * console initialization routines.
1327                  */
1328                 vga_bootup_console = 1;
1329                 c->vc_x = screen_info.orig_x;
1330                 c->vc_y = screen_info.orig_y;
1331         }
1332
1333         /* We can't copy in more than the size of the video buffer,
1334          * or we'll be copying in VGA BIOS */
1335
1336         if (!vga_is_gfx)
1337                 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1338                             c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1339 }
1340
1341 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1342                          int lines)
1343 {
1344         unsigned long oldo;
1345         unsigned int delta;
1346
1347         if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1348                 return 0;
1349
1350         if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1351                 return 0;
1352
1353         vgacon_restore_screen(c);
1354         oldo = c->vc_origin;
1355         delta = lines * c->vc_size_row;
1356         if (dir == SM_UP) {
1357                 vgacon_scrollback_update(c, t, lines);
1358                 if (c->vc_scr_end + delta >= vga_vram_end) {
1359                         scr_memcpyw((u16 *) vga_vram_base,
1360                                     (u16 *) (oldo + delta),
1361                                     c->vc_screenbuf_size - delta);
1362                         c->vc_origin = vga_vram_base;
1363                         vga_rolled_over = oldo - vga_vram_base;
1364                 } else
1365                         c->vc_origin += delta;
1366                 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1367                                      delta), c->vc_video_erase_char,
1368                             delta);
1369         } else {
1370                 if (oldo - delta < vga_vram_base) {
1371                         scr_memmovew((u16 *) (vga_vram_end -
1372                                               c->vc_screenbuf_size +
1373                                               delta), (u16 *) oldo,
1374                                      c->vc_screenbuf_size - delta);
1375                         c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1376                         vga_rolled_over = 0;
1377                 } else
1378                         c->vc_origin -= delta;
1379                 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1380                 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1381                             delta);
1382         }
1383         c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1384         c->vc_visible_origin = c->vc_origin;
1385         vga_set_mem_top(c);
1386         c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1387         return 1;
1388 }
1389
1390
1391 /*
1392  *  The console `switch' structure for the VGA based console
1393  */
1394
1395 static int vgacon_dummy(struct vc_data *c)
1396 {
1397         return 0;
1398 }
1399
1400 #define DUMMY (void *) vgacon_dummy
1401
1402 const struct consw vga_con = {
1403         .owner = THIS_MODULE,
1404         .con_startup = vgacon_startup,
1405         .con_init = vgacon_init,
1406         .con_deinit = vgacon_deinit,
1407         .con_clear = DUMMY,
1408         .con_putc = DUMMY,
1409         .con_putcs = DUMMY,
1410         .con_cursor = vgacon_cursor,
1411         .con_scroll = vgacon_scroll,
1412         .con_bmove = DUMMY,
1413         .con_switch = vgacon_switch,
1414         .con_blank = vgacon_blank,
1415         .con_font_set = vgacon_font_set,
1416         .con_font_get = vgacon_font_get,
1417         .con_resize = vgacon_resize,
1418         .con_set_palette = vgacon_set_palette,
1419         .con_scrolldelta = vgacon_scrolldelta,
1420         .con_set_origin = vgacon_set_origin,
1421         .con_save_screen = vgacon_save_screen,
1422         .con_build_attr = vgacon_build_attr,
1423         .con_invert_region = vgacon_invert_region,
1424 };
1425
1426 MODULE_LICENSE("GPL");