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