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