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