Merge remote branch 'alsa/devel' into topic/misc
[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 static int vgacon_text_mode_force;
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         /* Only set the default if the user didn't deliberately override it */
590         if (global_cursor_default == -1)
591                 global_cursor_default =
592                         !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
593 }
594
595 static void vgacon_deinit(struct vc_data *c)
596 {
597         /* When closing the active console, reset video origin */
598         if (CON_IS_VISIBLE(c)) {
599                 c->vc_visible_origin = vga_vram_base;
600                 vga_set_mem_top(c);
601         }
602
603         if (!--vgacon_uni_pagedir[1])
604                 con_free_unimap(c);
605         c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
606         con_set_default_unimap(c);
607 }
608
609 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
610                             u8 blink, u8 underline, u8 reverse, u8 italic)
611 {
612         u8 attr = color;
613
614         if (vga_can_do_color) {
615                 if (italic)
616                         attr = (attr & 0xF0) | c->vc_itcolor;
617                 else if (underline)
618                         attr = (attr & 0xf0) | c->vc_ulcolor;
619                 else if (intensity == 0)
620                         attr = (attr & 0xf0) | c->vc_halfcolor;
621         }
622         if (reverse)
623                 attr =
624                     ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
625                                        0x77);
626         if (blink)
627                 attr ^= 0x80;
628         if (intensity == 2)
629                 attr ^= 0x08;
630         if (!vga_can_do_color) {
631                 if (italic)
632                         attr = (attr & 0xF8) | 0x02;
633                 else if (underline)
634                         attr = (attr & 0xf8) | 0x01;
635                 else if (intensity == 0)
636                         attr = (attr & 0xf0) | 0x08;
637         }
638         return attr;
639 }
640
641 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
642 {
643         int col = vga_can_do_color;
644
645         while (count--) {
646                 u16 a = scr_readw(p);
647                 if (col)
648                         a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
649                             (((a) & 0x0700) << 4);
650                 else
651                         a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
652                 scr_writew(a, p++);
653         }
654 }
655
656 static void vgacon_set_cursor_size(int xpos, int from, int to)
657 {
658         unsigned long flags;
659         int curs, cure;
660
661 #ifdef TRIDENT_GLITCH
662         if (xpos < 16)
663                 from--, to--;
664 #endif
665
666         if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
667                 return;
668         cursor_size_lastfrom = from;
669         cursor_size_lastto = to;
670
671         spin_lock_irqsave(&vga_lock, flags);
672         if (vga_video_type >= VIDEO_TYPE_VGAC) {
673                 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
674                 curs = inb_p(vga_video_port_val);
675                 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
676                 cure = inb_p(vga_video_port_val);
677         } else {
678                 curs = 0;
679                 cure = 0;
680         }
681
682         curs = (curs & 0xc0) | from;
683         cure = (cure & 0xe0) | to;
684
685         outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
686         outb_p(curs, vga_video_port_val);
687         outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
688         outb_p(cure, vga_video_port_val);
689         spin_unlock_irqrestore(&vga_lock, flags);
690 }
691
692 static void vgacon_cursor(struct vc_data *c, int mode)
693 {
694         if (c->vc_mode != KD_TEXT)
695                 return;
696
697         vgacon_restore_screen(c);
698
699         switch (mode) {
700         case CM_ERASE:
701                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
702                 if (vga_video_type >= VIDEO_TYPE_VGAC)
703                         vgacon_set_cursor_size(c->vc_x, 31, 30);
704                 else
705                         vgacon_set_cursor_size(c->vc_x, 31, 31);
706                 break;
707
708         case CM_MOVE:
709         case CM_DRAW:
710                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
711                 switch (c->vc_cursor_type & 0x0f) {
712                 case CUR_UNDERLINE:
713                         vgacon_set_cursor_size(c->vc_x,
714                                                c->vc_font.height -
715                                                (c->vc_font.height <
716                                                 10 ? 2 : 3),
717                                                c->vc_font.height -
718                                                (c->vc_font.height <
719                                                 10 ? 1 : 2));
720                         break;
721                 case CUR_TWO_THIRDS:
722                         vgacon_set_cursor_size(c->vc_x,
723                                                c->vc_font.height / 3,
724                                                c->vc_font.height -
725                                                (c->vc_font.height <
726                                                 10 ? 1 : 2));
727                         break;
728                 case CUR_LOWER_THIRD:
729                         vgacon_set_cursor_size(c->vc_x,
730                                                (c->vc_font.height * 2) / 3,
731                                                c->vc_font.height -
732                                                (c->vc_font.height <
733                                                 10 ? 1 : 2));
734                         break;
735                 case CUR_LOWER_HALF:
736                         vgacon_set_cursor_size(c->vc_x,
737                                                c->vc_font.height / 2,
738                                                c->vc_font.height -
739                                                (c->vc_font.height <
740                                                 10 ? 1 : 2));
741                         break;
742                 case CUR_NONE:
743                         if (vga_video_type >= VIDEO_TYPE_VGAC)
744                                 vgacon_set_cursor_size(c->vc_x, 31, 30);
745                         else
746                                 vgacon_set_cursor_size(c->vc_x, 31, 31);
747                         break;
748                 default:
749                         vgacon_set_cursor_size(c->vc_x, 1,
750                                                c->vc_font.height);
751                         break;
752                 }
753                 break;
754         }
755 }
756
757 static int vgacon_doresize(struct vc_data *c,
758                 unsigned int width, unsigned int height)
759 {
760         unsigned long flags;
761         unsigned int scanlines = height * c->vc_font.height;
762         u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
763
764         spin_lock_irqsave(&vga_lock, flags);
765
766         vgacon_xres = width * VGA_FONTWIDTH;
767         vgacon_yres = height * c->vc_font.height;
768         if (vga_video_type >= VIDEO_TYPE_VGAC) {
769                 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
770                 max_scan = inb_p(vga_video_port_val);
771
772                 if (max_scan & 0x80)
773                         scanlines <<= 1;
774
775                 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
776                 mode = inb_p(vga_video_port_val);
777
778                 if (mode & 0x04)
779                         scanlines >>= 1;
780
781                 scanlines -= 1;
782                 scanlines_lo = scanlines & 0xff;
783
784                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
785                 r7 = inb_p(vga_video_port_val) & ~0x42;
786
787                 if (scanlines & 0x100)
788                         r7 |= 0x02;
789                 if (scanlines & 0x200)
790                         r7 |= 0x40;
791
792                 /* deprotect registers */
793                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
794                 vsync_end = inb_p(vga_video_port_val);
795                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
796                 outb_p(vsync_end & ~0x80, vga_video_port_val);
797         }
798
799         outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
800         outb_p(width - 1, vga_video_port_val);
801         outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
802         outb_p(width >> 1, vga_video_port_val);
803
804         if (vga_video_type >= VIDEO_TYPE_VGAC) {
805                 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
806                 outb_p(scanlines_lo, vga_video_port_val);
807                 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
808                 outb_p(r7,vga_video_port_val);
809
810                 /* reprotect registers */
811                 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
812                 outb_p(vsync_end, vga_video_port_val);
813         }
814
815         spin_unlock_irqrestore(&vga_lock, flags);
816         return 0;
817 }
818
819 static int vgacon_switch(struct vc_data *c)
820 {
821         int x = c->vc_cols * VGA_FONTWIDTH;
822         int y = c->vc_rows * c->vc_font.height;
823         int rows = screen_info.orig_video_lines * vga_default_font_height/
824                 c->vc_font.height;
825         /*
826          * We need to save screen size here as it's the only way
827          * we can spot the screen has been resized and we need to
828          * set size of freshly allocated screens ourselves.
829          */
830         vga_video_num_columns = c->vc_cols;
831         vga_video_num_lines = c->vc_rows;
832
833         /* We can only copy out the size of the video buffer here,
834          * otherwise we get into VGA BIOS */
835
836         if (!vga_is_gfx) {
837                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
838                             c->vc_screenbuf_size > vga_vram_size ?
839                                 vga_vram_size : c->vc_screenbuf_size);
840
841                 if ((vgacon_xres != x || vgacon_yres != y) &&
842                     (!(vga_video_num_columns % 2) &&
843                      vga_video_num_columns <= screen_info.orig_video_cols &&
844                      vga_video_num_lines <= rows))
845                         vgacon_doresize(c, c->vc_cols, c->vc_rows);
846         }
847
848         vgacon_scrollback_init(c->vc_size_row);
849         return 0;               /* Redrawing not needed */
850 }
851
852 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
853 {
854         int i, j;
855
856         vga_w(state.vgabase, VGA_PEL_MSK, 0xff);
857         for (i = j = 0; i < 16; i++) {
858                 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
859                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
860                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
861                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
862         }
863 }
864
865 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
866 {
867 #ifdef CAN_LOAD_PALETTE
868         if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
869             || !CON_IS_VISIBLE(vc))
870                 return -EINVAL;
871         vga_set_palette(vc, table);
872         return 0;
873 #else
874         return -EINVAL;
875 #endif
876 }
877
878 /* structure holding original VGA register settings */
879 static struct {
880         unsigned char SeqCtrlIndex;     /* Sequencer Index reg.   */
881         unsigned char CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
882         unsigned char CrtMiscIO;        /* Miscellaneous register */
883         unsigned char HorizontalTotal;  /* CRT-Controller:00h */
884         unsigned char HorizDisplayEnd;  /* CRT-Controller:01h */
885         unsigned char StartHorizRetrace;        /* CRT-Controller:04h */
886         unsigned char EndHorizRetrace;  /* CRT-Controller:05h */
887         unsigned char Overflow; /* CRT-Controller:07h */
888         unsigned char StartVertRetrace; /* CRT-Controller:10h */
889         unsigned char EndVertRetrace;   /* CRT-Controller:11h */
890         unsigned char ModeControl;      /* CRT-Controller:17h */
891         unsigned char ClockingMode;     /* Seq-Controller:01h */
892 } vga_state;
893
894 static void vga_vesa_blank(struct vgastate *state, int mode)
895 {
896         /* save original values of VGA controller registers */
897         if (!vga_vesa_blanked) {
898                 spin_lock_irq(&vga_lock);
899                 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
900                 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
901                 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
902                 spin_unlock_irq(&vga_lock);
903
904                 outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
905                 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
906                 outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
907                 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
908                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
909                 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
910                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
911                 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
912                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
913                 vga_state.Overflow = inb_p(vga_video_port_val);
914                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
915                 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
916                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
917                 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
918                 outb_p(0x17, vga_video_port_reg);       /* ModeControl */
919                 vga_state.ModeControl = inb_p(vga_video_port_val);
920                 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
921         }
922
923         /* assure that video is enabled */
924         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
925         spin_lock_irq(&vga_lock);
926         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
927
928         /* test for vertical retrace in process.... */
929         if ((vga_state.CrtMiscIO & 0x80) == 0x80)
930                 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
931
932         /*
933          * Set <End of vertical retrace> to minimum (0) and
934          * <Start of vertical Retrace> to maximum (incl. overflow)
935          * Result: turn off vertical sync (VSync) pulse.
936          */
937         if (mode & VESA_VSYNC_SUSPEND) {
938                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
939                 outb_p(0xff, vga_video_port_val);       /* maximum value */
940                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
941                 outb_p(0x40, vga_video_port_val);       /* minimum (bits 0..3)  */
942                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
943                 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);  /* bits 9,10 of vert. retrace */
944         }
945
946         if (mode & VESA_HSYNC_SUSPEND) {
947                 /*
948                  * Set <End of horizontal retrace> to minimum (0) and
949                  *  <Start of horizontal Retrace> to maximum
950                  * Result: turn off horizontal sync (HSync) pulse.
951                  */
952                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
953                 outb_p(0xff, vga_video_port_val);       /* maximum */
954                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
955                 outb_p(0x00, vga_video_port_val);       /* minimum (0) */
956         }
957
958         /* restore both index registers */
959         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
960         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
961         spin_unlock_irq(&vga_lock);
962 }
963
964 static void vga_vesa_unblank(struct vgastate *state)
965 {
966         /* restore original values of VGA controller registers */
967         spin_lock_irq(&vga_lock);
968         vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
969
970         outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
971         outb_p(vga_state.HorizontalTotal, vga_video_port_val);
972         outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
973         outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
974         outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
975         outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
976         outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
977         outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
978         outb_p(0x07, vga_video_port_reg);       /* Overflow */
979         outb_p(vga_state.Overflow, vga_video_port_val);
980         outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
981         outb_p(vga_state.StartVertRetrace, vga_video_port_val);
982         outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
983         outb_p(vga_state.EndVertRetrace, vga_video_port_val);
984         outb_p(0x17, vga_video_port_reg);       /* ModeControl */
985         outb_p(vga_state.ModeControl, vga_video_port_val);
986         /* ClockingMode */
987         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
988
989         /* restore index/control registers */
990         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
991         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
992         spin_unlock_irq(&vga_lock);
993 }
994
995 static void vga_pal_blank(struct vgastate *state)
996 {
997         int i;
998
999         vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
1000         for (i = 0; i < 16; i++) {
1001                 vga_w(state->vgabase, VGA_PEL_IW, i);
1002                 vga_w(state->vgabase, VGA_PEL_D, 0);
1003                 vga_w(state->vgabase, VGA_PEL_D, 0);
1004                 vga_w(state->vgabase, VGA_PEL_D, 0);
1005         }
1006 }
1007
1008 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
1009 {
1010         switch (blank) {
1011         case 0:         /* Unblank */
1012                 if (vga_vesa_blanked) {
1013                         vga_vesa_unblank(&state);
1014                         vga_vesa_blanked = 0;
1015                 }
1016                 if (vga_palette_blanked) {
1017                         vga_set_palette(c, color_table);
1018                         vga_palette_blanked = 0;
1019                         return 0;
1020                 }
1021                 vga_is_gfx = 0;
1022                 /* Tell console.c that it has to restore the screen itself */
1023                 return 1;
1024         case 1:         /* Normal blanking */
1025         case -1:        /* Obsolete */
1026                 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
1027                         vga_pal_blank(&state);
1028                         vga_palette_blanked = 1;
1029                         return 0;
1030                 }
1031                 vgacon_set_origin(c);
1032                 scr_memsetw((void *) vga_vram_base, BLANK,
1033                             c->vc_screenbuf_size);
1034                 if (mode_switch)
1035                         vga_is_gfx = 1;
1036                 return 1;
1037         default:                /* VESA blanking */
1038                 if (vga_video_type == VIDEO_TYPE_VGAC) {
1039                         vga_vesa_blank(&state, blank - 1);
1040                         vga_vesa_blanked = blank;
1041                 }
1042                 return 0;
1043         }
1044 }
1045
1046 /*
1047  * PIO_FONT support.
1048  *
1049  * The font loading code goes back to the codepage package by
1050  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
1051  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
1052  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
1053  *
1054  * Change for certain monochrome monitors by Yury Shevchuck
1055  * (sizif@botik.yaroslavl.su).
1056  */
1057
1058 #ifdef CAN_LOAD_EGA_FONTS
1059
1060 #define colourmap 0xa0000
1061 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
1062    should use 0xA0000 for the bwmap as well.. */
1063 #define blackwmap 0xa0000
1064 #define cmapsz 8192
1065
1066 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
1067 {
1068         unsigned short video_port_status = vga_video_port_reg + 6;
1069         int font_select = 0x00, beg, i;
1070         char *charmap;
1071         
1072         if (vga_video_type != VIDEO_TYPE_EGAM) {
1073                 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
1074                 beg = 0x0e;
1075 #ifdef VGA_CAN_DO_64KB
1076                 if (vga_video_type == VIDEO_TYPE_VGAC)
1077                         beg = 0x06;
1078 #endif
1079         } else {
1080                 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
1081                 beg = 0x0a;
1082         }
1083
1084 #ifdef BROKEN_GRAPHICS_PROGRAMS
1085         /*
1086          * All fonts are loaded in slot 0 (0:1 for 512 ch)
1087          */
1088
1089         if (!arg)
1090                 return -EINVAL; /* Return to default font not supported */
1091
1092         vga_font_is_default = 0;
1093         font_select = ch512 ? 0x04 : 0x00;
1094 #else
1095         /*
1096          * The default font is kept in slot 0 and is never touched.
1097          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
1098          */
1099
1100         if (set) {
1101                 vga_font_is_default = !arg;
1102                 if (!arg)
1103                         ch512 = 0;      /* Default font is always 256 */
1104                 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
1105         }
1106
1107         if (!vga_font_is_default)
1108                 charmap += 4 * cmapsz;
1109 #endif
1110
1111         spin_lock_irq(&vga_lock);
1112         /* First, the Sequencer */
1113         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
1114         /* CPU writes only to map 2 */
1115         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);    
1116         /* Sequential addressing */
1117         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);    
1118         /* Clear synchronous reset */
1119         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1120
1121         /* Now, the graphics controller, select map 2 */
1122         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);             
1123         /* disable odd-even addressing */
1124         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
1125         /* map start at A000:0000 */
1126         vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
1127         spin_unlock_irq(&vga_lock);
1128
1129         if (arg) {
1130                 if (set)
1131                         for (i = 0; i < cmapsz; i++)
1132                                 vga_writeb(arg[i], charmap + i);
1133                 else
1134                         for (i = 0; i < cmapsz; i++)
1135                                 arg[i] = vga_readb(charmap + i);
1136
1137                 /*
1138                  * In 512-character mode, the character map is not contiguous if
1139                  * we want to remain EGA compatible -- which we do
1140                  */
1141
1142                 if (ch512) {
1143                         charmap += 2 * cmapsz;
1144                         arg += cmapsz;
1145                         if (set)
1146                                 for (i = 0; i < cmapsz; i++)
1147                                         vga_writeb(arg[i], charmap + i);
1148                         else
1149                                 for (i = 0; i < cmapsz; i++)
1150                                         arg[i] = vga_readb(charmap + i);
1151                 }
1152         }
1153
1154         spin_lock_irq(&vga_lock);
1155         /* First, the sequencer, Synchronous reset */
1156         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);  
1157         /* CPU writes to maps 0 and 1 */
1158         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1159         /* odd-even addressing */
1160         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1161         /* Character Map Select */
1162         if (set)
1163                 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1164         /* clear synchronous reset */
1165         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1166
1167         /* Now, the graphics controller, select map 0 for CPU */
1168         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1169         /* enable even-odd addressing */
1170         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1171         /* map starts at b800:0 or b000:0 */
1172         vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1173
1174         /* if 512 char mode is already enabled don't re-enable it. */
1175         if ((set) && (ch512 != vga_512_chars)) {
1176                 /* attribute controller */
1177                 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1178                         struct vc_data *c = vc_cons[i].d;
1179                         if (c && c->vc_sw == &vga_con)
1180                                 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1181                 }
1182                 vga_512_chars = ch512;
1183                 /* 256-char: enable intensity bit
1184                    512-char: disable intensity bit */
1185                 inb_p(video_port_status);       /* clear address flip-flop */
1186                 /* color plane enable register */
1187                 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1188                 /* Wilton (1987) mentions the following; I don't know what
1189                    it means, but it works, and it appears necessary */
1190                 inb_p(video_port_status);
1191                 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);    
1192         }
1193         spin_unlock_irq(&vga_lock);
1194         return 0;
1195 }
1196
1197 /*
1198  * Adjust the screen to fit a font of a certain height
1199  */
1200 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1201 {
1202         unsigned char ovr, vde, fsr;
1203         int rows, maxscan, i;
1204
1205         rows = vc->vc_scan_lines / fontheight;  /* Number of video rows we end up with */
1206         maxscan = rows * fontheight - 1;        /* Scan lines to actually display-1 */
1207
1208         /* Reprogram the CRTC for the new font size
1209            Note: the attempt to read the overflow register will fail
1210            on an EGA, but using 0xff for the previous value appears to
1211            be OK for EGA text modes in the range 257-512 scan lines, so I
1212            guess we don't need to worry about it.
1213
1214            The same applies for the spill bits in the font size and cursor
1215            registers; they are write-only on EGA, but it appears that they
1216            are all don't care bits on EGA, so I guess it doesn't matter. */
1217
1218         spin_lock_irq(&vga_lock);
1219         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1220         ovr = inb_p(vga_video_port_val);
1221         outb_p(0x09, vga_video_port_reg);       /* Font size register */
1222         fsr = inb_p(vga_video_port_val);
1223         spin_unlock_irq(&vga_lock);
1224
1225         vde = maxscan & 0xff;   /* Vertical display end reg */
1226         ovr = (ovr & 0xbd) +    /* Overflow register */
1227             ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1228         fsr = (fsr & 0xe0) + (fontheight - 1);  /*  Font size register */
1229
1230         spin_lock_irq(&vga_lock);
1231         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
1232         outb_p(ovr, vga_video_port_val);
1233         outb_p(0x09, vga_video_port_reg);       /* Font size */
1234         outb_p(fsr, vga_video_port_val);
1235         outb_p(0x12, vga_video_port_reg);       /* Vertical display limit */
1236         outb_p(vde, vga_video_port_val);
1237         spin_unlock_irq(&vga_lock);
1238         vga_video_font_height = fontheight;
1239
1240         for (i = 0; i < MAX_NR_CONSOLES; i++) {
1241                 struct vc_data *c = vc_cons[i].d;
1242
1243                 if (c && c->vc_sw == &vga_con) {
1244                         if (CON_IS_VISIBLE(c)) {
1245                                 /* void size to cause regs to be rewritten */
1246                                 cursor_size_lastfrom = 0;
1247                                 cursor_size_lastto = 0;
1248                                 c->vc_sw->con_cursor(c, CM_DRAW);
1249                         }
1250                         c->vc_font.height = fontheight;
1251                         vc_resize(c, 0, rows);  /* Adjust console size */
1252                 }
1253         }
1254         return 0;
1255 }
1256
1257 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1258 {
1259         unsigned charcount = font->charcount;
1260         int rc;
1261
1262         if (vga_video_type < VIDEO_TYPE_EGAM)
1263                 return -EINVAL;
1264
1265         if (font->width != VGA_FONTWIDTH ||
1266             (charcount != 256 && charcount != 512))
1267                 return -EINVAL;
1268
1269         rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
1270         if (rc)
1271                 return rc;
1272
1273         if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1274                 rc = vgacon_adjust_height(c, font->height);
1275         return rc;
1276 }
1277
1278 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1279 {
1280         if (vga_video_type < VIDEO_TYPE_EGAM)
1281                 return -EINVAL;
1282
1283         font->width = VGA_FONTWIDTH;
1284         font->height = c->vc_font.height;
1285         font->charcount = vga_512_chars ? 512 : 256;
1286         if (!font->data)
1287                 return 0;
1288         return vgacon_do_font_op(&state, font->data, 0, vga_512_chars);
1289 }
1290
1291 #else
1292
1293 #define vgacon_font_set NULL
1294 #define vgacon_font_get NULL
1295
1296 #endif
1297
1298 static int vgacon_resize(struct vc_data *c, unsigned int width,
1299                          unsigned int height, unsigned int user)
1300 {
1301         if (width % 2 || width > screen_info.orig_video_cols ||
1302             height > (screen_info.orig_video_lines * vga_default_font_height)/
1303             c->vc_font.height)
1304                 /* let svgatextmode tinker with video timings and
1305                    return success */
1306                 return (user) ? 0 : -EINVAL;
1307
1308         if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
1309                 vgacon_doresize(c, width, height);
1310         return 0;
1311 }
1312
1313 static int vgacon_set_origin(struct vc_data *c)
1314 {
1315         if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
1316             (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
1317                 return 0;
1318         c->vc_origin = c->vc_visible_origin = vga_vram_base;
1319         vga_set_mem_top(c);
1320         vga_rolled_over = 0;
1321         return 1;
1322 }
1323
1324 static void vgacon_save_screen(struct vc_data *c)
1325 {
1326         static int vga_bootup_console = 0;
1327
1328         if (!vga_bootup_console) {
1329                 /* This is a gross hack, but here is the only place we can
1330                  * set bootup console parameters without messing up generic
1331                  * console initialization routines.
1332                  */
1333                 vga_bootup_console = 1;
1334                 c->vc_x = screen_info.orig_x;
1335                 c->vc_y = screen_info.orig_y;
1336         }
1337
1338         /* We can't copy in more than the size of the video buffer,
1339          * or we'll be copying in VGA BIOS */
1340
1341         if (!vga_is_gfx)
1342                 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1343                             c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1344 }
1345
1346 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1347                          int lines)
1348 {
1349         unsigned long oldo;
1350         unsigned int delta;
1351
1352         if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1353                 return 0;
1354
1355         if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1356                 return 0;
1357
1358         vgacon_restore_screen(c);
1359         oldo = c->vc_origin;
1360         delta = lines * c->vc_size_row;
1361         if (dir == SM_UP) {
1362                 vgacon_scrollback_update(c, t, lines);
1363                 if (c->vc_scr_end + delta >= vga_vram_end) {
1364                         scr_memcpyw((u16 *) vga_vram_base,
1365                                     (u16 *) (oldo + delta),
1366                                     c->vc_screenbuf_size - delta);
1367                         c->vc_origin = vga_vram_base;
1368                         vga_rolled_over = oldo - vga_vram_base;
1369                 } else
1370                         c->vc_origin += delta;
1371                 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1372                                      delta), c->vc_video_erase_char,
1373                             delta);
1374         } else {
1375                 if (oldo - delta < vga_vram_base) {
1376                         scr_memmovew((u16 *) (vga_vram_end -
1377                                               c->vc_screenbuf_size +
1378                                               delta), (u16 *) oldo,
1379                                      c->vc_screenbuf_size - delta);
1380                         c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1381                         vga_rolled_over = 0;
1382                 } else
1383                         c->vc_origin -= delta;
1384                 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1385                 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1386                             delta);
1387         }
1388         c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1389         c->vc_visible_origin = c->vc_origin;
1390         vga_set_mem_top(c);
1391         c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1392         return 1;
1393 }
1394
1395
1396 /*
1397  *  The console `switch' structure for the VGA based console
1398  */
1399
1400 static int vgacon_dummy(struct vc_data *c)
1401 {
1402         return 0;
1403 }
1404
1405 #define DUMMY (void *) vgacon_dummy
1406
1407 const struct consw vga_con = {
1408         .owner = THIS_MODULE,
1409         .con_startup = vgacon_startup,
1410         .con_init = vgacon_init,
1411         .con_deinit = vgacon_deinit,
1412         .con_clear = DUMMY,
1413         .con_putc = DUMMY,
1414         .con_putcs = DUMMY,
1415         .con_cursor = vgacon_cursor,
1416         .con_scroll = vgacon_scroll,
1417         .con_bmove = DUMMY,
1418         .con_switch = vgacon_switch,
1419         .con_blank = vgacon_blank,
1420         .con_font_set = vgacon_font_set,
1421         .con_font_get = vgacon_font_get,
1422         .con_resize = vgacon_resize,
1423         .con_set_palette = vgacon_set_palette,
1424         .con_scrolldelta = vgacon_scrolldelta,
1425         .con_set_origin = vgacon_set_origin,
1426         .con_save_screen = vgacon_save_screen,
1427         .con_build_attr = vgacon_build_attr,
1428         .con_invert_region = vgacon_invert_region,
1429 };
1430
1431 MODULE_LICENSE("GPL");