fix mismerge in ll_rw_blk.c
[linux-2.6] / drivers / video / console / vgacon.c
1 /*
2  *  linux/drivers/video/vgacon.c -- Low level VGA based console driver
3  *
4  *      Created 28 Sep 1997 by Geert Uytterhoeven
5  *
6  *      Rewritten by Martin Mares <mj@ucw.cz>, July 1998
7  *
8  *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.
9  *
10  *      Copyright (C) 1991, 1992  Linus Torvalds
11  *                          1995  Jay Estabrook
12  *
13  *      User definable mapping table and font loading by Eugene G. Crosser,
14  *      <crosser@average.org>
15  *
16  *      Improved loadable font/UTF-8 support by H. Peter Anvin
17  *      Feb-Sep 1995 <peter.anvin@linux.org>
18  *
19  *      Colour palette handling, by Simon Tatham
20  *      17-Jun-95 <sgt20@cam.ac.uk>
21  *
22  *      if 512 char mode is already enabled don't re-enable it,
23  *      because it causes screen to flicker, by Mitja Horvat
24  *      5-May-96 <mitja.horvat@guest.arnes.si>
25  *
26  *      Use 2 outw instead of 4 outb_p to reduce erroneous text
27  *      flashing on RHS of screen during heavy console scrolling .
28  *      Oct 1996, Paul Gortmaker.
29  *
30  *
31  *  This file is subject to the terms and conditions of the GNU General Public
32  *  License.  See the file COPYING in the main directory of this archive for
33  *  more details.
34  */
35
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/types.h>
39 #include <linux/sched.h>
40 #include <linux/fs.h>
41 #include <linux/kernel.h>
42 #include <linux/tty.h>
43 #include <linux/console.h>
44 #include <linux/string.h>
45 #include <linux/kd.h>
46 #include <linux/slab.h>
47 #include <linux/vt_kern.h>
48 #include <linux/selection.h>
49 #include <linux/spinlock.h>
50 #include <linux/ioport.h>
51 #include <linux/init.h>
52 #include <linux/smp_lock.h>
53 #include <video/vga.h>
54 #include <asm/io.h>
55
56 static DEFINE_SPINLOCK(vga_lock);
57 static int cursor_size_lastfrom;
58 static int cursor_size_lastto;
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
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 u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
90                             u8 blink, u8 underline, u8 reverse);
91 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
92 static unsigned long vgacon_uni_pagedir[2];
93
94
95 /* Description of the hardware situation */
96 static unsigned long    vga_vram_base;          /* Base of video memory */
97 static unsigned long    vga_vram_end;           /* End of video memory */
98 static int              vga_vram_size;          /* Size of video memory */
99 static u16              vga_video_port_reg;     /* Video register select port */
100 static u16              vga_video_port_val;     /* Video register value port */
101 static unsigned int     vga_video_num_columns;  /* Number of text columns */
102 static unsigned int     vga_video_num_lines;    /* Number of text lines */
103 static int              vga_can_do_color = 0;   /* Do we support colors? */
104 static unsigned int     vga_default_font_height;/* Height of default screen font */
105 static unsigned char    vga_video_type;         /* Card type */
106 static unsigned char    vga_hardscroll_enabled;
107 static unsigned char    vga_hardscroll_user_enable = 1;
108 static unsigned char    vga_font_is_default = 1;
109 static int              vga_vesa_blanked;
110 static int              vga_palette_blanked;
111 static int              vga_is_gfx;
112 static int              vga_512_chars;
113 static int              vga_video_font_height;
114 static int              vga_scan_lines;
115 static unsigned int     vga_rolled_over = 0;
116
117 static int __init no_scroll(char *str)
118 {
119         /*
120          * Disabling scrollback is required for the Braillex ib80-piezo
121          * Braille reader made by F.H. Papenmeier (Germany).
122          * Use the "no-scroll" bootflag.
123          */
124         vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
125         return 1;
126 }
127
128 __setup("no-scroll", no_scroll);
129
130 /*
131  * By replacing the four outb_p with two back to back outw, we can reduce
132  * the window of opportunity to see text mislocated to the RHS of the
133  * console during heavy scrolling activity. However there is the remote
134  * possibility that some pre-dinosaur hardware won't like the back to back
135  * I/O. Since the Xservers get away with it, we should be able to as well.
136  */
137 static inline void write_vga(unsigned char reg, unsigned int val)
138 {
139         unsigned int v1, v2;
140         unsigned long flags;
141
142         /*
143          * ddprintk might set the console position from interrupt
144          * handlers, thus the write has to be IRQ-atomic.
145          */
146         spin_lock_irqsave(&vga_lock, flags);
147
148 #ifndef SLOW_VGA
149         v1 = reg + (val & 0xff00);
150         v2 = reg + 1 + ((val << 8) & 0xff00);
151         outw(v1, vga_video_port_reg);
152         outw(v2, vga_video_port_reg);
153 #else
154         outb_p(reg, vga_video_port_reg);
155         outb_p(val >> 8, vga_video_port_val);
156         outb_p(reg + 1, vga_video_port_reg);
157         outb_p(val & 0xff, vga_video_port_val);
158 #endif
159         spin_unlock_irqrestore(&vga_lock, flags);
160 }
161
162 static const char __init *vgacon_startup(void)
163 {
164         const char *display_desc = NULL;
165         u16 saved1, saved2;
166         volatile u16 *p;
167
168         if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
169               no_vga:
170 #ifdef CONFIG_DUMMY_CONSOLE
171                 conswitchp = &dummy_con;
172                 return conswitchp->con_startup();
173 #else
174                 return NULL;
175 #endif
176         }
177
178         /* VGA16 modes are not handled by VGACON */
179         if ((ORIG_VIDEO_MODE == 0x0D) ||        /* 320x200/4 */
180             (ORIG_VIDEO_MODE == 0x0E) ||        /* 640x200/4 */
181             (ORIG_VIDEO_MODE == 0x10) ||        /* 640x350/4 */
182             (ORIG_VIDEO_MODE == 0x12) ||        /* 640x480/4 */
183             (ORIG_VIDEO_MODE == 0x6A))  /* 800x600/4, 0x6A is very common */
184                 goto no_vga;
185
186         vga_video_num_lines = ORIG_VIDEO_LINES;
187         vga_video_num_columns = ORIG_VIDEO_COLS;
188         state.vgabase = NULL;
189
190         if (ORIG_VIDEO_MODE == 7) {     /* Is this a monochrome display? */
191                 vga_vram_base = 0xb0000;
192                 vga_video_port_reg = VGA_CRT_IM;
193                 vga_video_port_val = VGA_CRT_DM;
194                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
195                         static struct resource ega_console_resource =
196                             { "ega", 0x3B0, 0x3BF };
197                         vga_video_type = VIDEO_TYPE_EGAM;
198                         vga_vram_end = 0xb8000;
199                         display_desc = "EGA+";
200                         request_resource(&ioport_resource,
201                                          &ega_console_resource);
202                 } else {
203                         static struct resource mda1_console_resource =
204                             { "mda", 0x3B0, 0x3BB };
205                         static struct resource mda2_console_resource =
206                             { "mda", 0x3BF, 0x3BF };
207                         vga_video_type = VIDEO_TYPE_MDA;
208                         vga_vram_end = 0xb2000;
209                         display_desc = "*MDA";
210                         request_resource(&ioport_resource,
211                                          &mda1_console_resource);
212                         request_resource(&ioport_resource,
213                                          &mda2_console_resource);
214                         vga_video_font_height = 14;
215                 }
216         } else {
217                 /* If not, it is color. */
218                 vga_can_do_color = 1;
219                 vga_vram_base = 0xb8000;
220                 vga_video_port_reg = VGA_CRT_IC;
221                 vga_video_port_val = VGA_CRT_DC;
222                 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
223                         int i;
224
225                         vga_vram_end = 0xc0000;
226
227                         if (!ORIG_VIDEO_ISVGA) {
228                                 static struct resource ega_console_resource
229                                     = { "ega", 0x3C0, 0x3DF };
230                                 vga_video_type = VIDEO_TYPE_EGAC;
231                                 display_desc = "EGA";
232                                 request_resource(&ioport_resource,
233                                                  &ega_console_resource);
234                         } else {
235                                 static struct resource vga_console_resource
236                                     = { "vga+", 0x3C0, 0x3DF };
237                                 vga_video_type = VIDEO_TYPE_VGAC;
238                                 display_desc = "VGA+";
239                                 request_resource(&ioport_resource,
240                                                  &vga_console_resource);
241
242 #ifdef VGA_CAN_DO_64KB
243                                 /*
244                                  * get 64K rather than 32K of video RAM.
245                                  * This doesn't actually work on all "VGA"
246                                  * controllers (it seems like setting MM=01
247                                  * and COE=1 isn't necessarily a good idea)
248                                  */
249                                 vga_vram_base = 0xa0000;
250                                 vga_vram_end = 0xb0000;
251                                 outb_p(6, VGA_GFX_I);
252                                 outb_p(6, VGA_GFX_D);
253 #endif
254                                 /*
255                                  * Normalise the palette registers, to point
256                                  * the 16 screen colours to the first 16
257                                  * DAC entries.
258                                  */
259
260                                 for (i = 0; i < 16; i++) {
261                                         inb_p(VGA_IS1_RC);
262                                         outb_p(i, VGA_ATT_W);
263                                         outb_p(i, VGA_ATT_W);
264                                 }
265                                 outb_p(0x20, VGA_ATT_W);
266
267                                 /*
268                                  * Now set the DAC registers back to their
269                                  * default values
270                                  */
271                                 for (i = 0; i < 16; i++) {
272                                         outb_p(color_table[i], VGA_PEL_IW);
273                                         outb_p(default_red[i], VGA_PEL_D);
274                                         outb_p(default_grn[i], VGA_PEL_D);
275                                         outb_p(default_blu[i], VGA_PEL_D);
276                                 }
277                         }
278                 } else {
279                         static struct resource cga_console_resource =
280                             { "cga", 0x3D4, 0x3D5 };
281                         vga_video_type = VIDEO_TYPE_CGA;
282                         vga_vram_end = 0xba000;
283                         display_desc = "*CGA";
284                         request_resource(&ioport_resource,
285                                          &cga_console_resource);
286                         vga_video_font_height = 8;
287                 }
288         }
289
290         vga_vram_base = VGA_MAP_MEM(vga_vram_base);
291         vga_vram_end = VGA_MAP_MEM(vga_vram_end);
292         vga_vram_size = vga_vram_end - vga_vram_base;
293
294         /*
295          *      Find out if there is a graphics card present.
296          *      Are there smarter methods around?
297          */
298         p = (volatile u16 *) vga_vram_base;
299         saved1 = scr_readw(p);
300         saved2 = scr_readw(p + 1);
301         scr_writew(0xAA55, p);
302         scr_writew(0x55AA, p + 1);
303         if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
304                 scr_writew(saved1, p);
305                 scr_writew(saved2, p + 1);
306                 goto no_vga;
307         }
308         scr_writew(0x55AA, p);
309         scr_writew(0xAA55, p + 1);
310         if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
311                 scr_writew(saved1, p);
312                 scr_writew(saved2, p + 1);
313                 goto no_vga;
314         }
315         scr_writew(saved1, p);
316         scr_writew(saved2, p + 1);
317
318         if (vga_video_type == VIDEO_TYPE_EGAC
319             || vga_video_type == VIDEO_TYPE_VGAC
320             || vga_video_type == VIDEO_TYPE_EGAM) {
321                 vga_hardscroll_enabled = vga_hardscroll_user_enable;
322                 vga_default_font_height = ORIG_VIDEO_POINTS;
323                 vga_video_font_height = ORIG_VIDEO_POINTS;
324                 /* This may be suboptimal but is a safe bet - go with it */
325                 vga_scan_lines =
326                     vga_video_font_height * vga_video_num_lines;
327         }
328         return display_desc;
329 }
330
331 static void vgacon_init(struct vc_data *c, int init)
332 {
333         unsigned long p;
334
335         /* We cannot be loaded as a module, therefore init is always 1 */
336         c->vc_can_do_color = vga_can_do_color;
337         c->vc_cols = vga_video_num_columns;
338         c->vc_rows = vga_video_num_lines;
339         c->vc_scan_lines = vga_scan_lines;
340         c->vc_font.height = vga_video_font_height;
341         c->vc_complement_mask = 0x7700;
342         if (vga_512_chars)
343                 c->vc_hi_font_mask = 0x0800;
344         p = *c->vc_uni_pagedir_loc;
345         if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
346             !--c->vc_uni_pagedir_loc[1])
347                 con_free_unimap(c);
348         c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
349         vgacon_uni_pagedir[1]++;
350         if (!vgacon_uni_pagedir[0] && p)
351                 con_set_default_unimap(c);
352 }
353
354 static inline void vga_set_mem_top(struct vc_data *c)
355 {
356         write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
357 }
358
359 static void vgacon_deinit(struct vc_data *c)
360 {
361         /* When closing the last console, reset video origin */
362         if (!--vgacon_uni_pagedir[1]) {
363                 c->vc_visible_origin = vga_vram_base;
364                 vga_set_mem_top(c);
365                 con_free_unimap(c);
366         }
367         c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
368         con_set_default_unimap(c);
369 }
370
371 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
372                             u8 blink, u8 underline, u8 reverse)
373 {
374         u8 attr = color;
375
376         if (vga_can_do_color) {
377                 if (underline)
378                         attr = (attr & 0xf0) | c->vc_ulcolor;
379                 else if (intensity == 0)
380                         attr = (attr & 0xf0) | c->vc_halfcolor;
381         }
382         if (reverse)
383                 attr =
384                     ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
385                                        0x77);
386         if (blink)
387                 attr ^= 0x80;
388         if (intensity == 2)
389                 attr ^= 0x08;
390         if (!vga_can_do_color) {
391                 if (underline)
392                         attr = (attr & 0xf8) | 0x01;
393                 else if (intensity == 0)
394                         attr = (attr & 0xf0) | 0x08;
395         }
396         return attr;
397 }
398
399 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
400 {
401         int col = vga_can_do_color;
402
403         while (count--) {
404                 u16 a = scr_readw(p);
405                 if (col)
406                         a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
407                             (((a) & 0x0700) << 4);
408                 else
409                         a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
410                 scr_writew(a, p++);
411         }
412 }
413
414 static void vgacon_set_cursor_size(int xpos, int from, int to)
415 {
416         unsigned long flags;
417         int curs, cure;
418
419 #ifdef TRIDENT_GLITCH
420         if (xpos < 16)
421                 from--, to--;
422 #endif
423
424         if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
425                 return;
426         cursor_size_lastfrom = from;
427         cursor_size_lastto = to;
428
429         spin_lock_irqsave(&vga_lock, flags);
430         outb_p(0x0a, vga_video_port_reg);       /* Cursor start */
431         curs = inb_p(vga_video_port_val);
432         outb_p(0x0b, vga_video_port_reg);       /* Cursor end */
433         cure = inb_p(vga_video_port_val);
434
435         curs = (curs & 0xc0) | from;
436         cure = (cure & 0xe0) | to;
437
438         outb_p(0x0a, vga_video_port_reg);       /* Cursor start */
439         outb_p(curs, vga_video_port_val);
440         outb_p(0x0b, vga_video_port_reg);       /* Cursor end */
441         outb_p(cure, vga_video_port_val);
442         spin_unlock_irqrestore(&vga_lock, flags);
443 }
444
445 static void vgacon_cursor(struct vc_data *c, int mode)
446 {
447         if (c->vc_origin != c->vc_visible_origin)
448                 vgacon_scrolldelta(c, 0);
449         switch (mode) {
450         case CM_ERASE:
451                 write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
452                 break;
453
454         case CM_MOVE:
455         case CM_DRAW:
456                 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
457                 switch (c->vc_cursor_type & 0x0f) {
458                 case CUR_UNDERLINE:
459                         vgacon_set_cursor_size(c->vc_x,
460                                                c->vc_font.height -
461                                                (c->vc_font.height <
462                                                 10 ? 2 : 3),
463                                                c->vc_font.height -
464                                                (c->vc_font.height <
465                                                 10 ? 1 : 2));
466                         break;
467                 case CUR_TWO_THIRDS:
468                         vgacon_set_cursor_size(c->vc_x,
469                                                c->vc_font.height / 3,
470                                                c->vc_font.height -
471                                                (c->vc_font.height <
472                                                 10 ? 1 : 2));
473                         break;
474                 case CUR_LOWER_THIRD:
475                         vgacon_set_cursor_size(c->vc_x,
476                                                (c->vc_font.height * 2) / 3,
477                                                c->vc_font.height -
478                                                (c->vc_font.height <
479                                                 10 ? 1 : 2));
480                         break;
481                 case CUR_LOWER_HALF:
482                         vgacon_set_cursor_size(c->vc_x,
483                                                c->vc_font.height / 2,
484                                                c->vc_font.height -
485                                                (c->vc_font.height <
486                                                 10 ? 1 : 2));
487                         break;
488                 case CUR_NONE:
489                         vgacon_set_cursor_size(c->vc_x, 31, 30);
490                         break;
491                 default:
492                         vgacon_set_cursor_size(c->vc_x, 1,
493                                                c->vc_font.height);
494                         break;
495                 }
496                 break;
497         }
498 }
499
500 static int vgacon_switch(struct vc_data *c)
501 {
502         /*
503          * We need to save screen size here as it's the only way
504          * we can spot the screen has been resized and we need to
505          * set size of freshly allocated screens ourselves.
506          */
507         vga_video_num_columns = c->vc_cols;
508         vga_video_num_lines = c->vc_rows;
509
510         /* We can only copy out the size of the video buffer here,
511          * otherwise we get into VGA BIOS */
512
513         if (!vga_is_gfx)
514                 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
515                             c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
516         return 0;               /* Redrawing not needed */
517 }
518
519 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
520 {
521         int i, j;
522
523         for (i = j = 0; i < 16; i++) {
524                 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
525                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
526                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
527                 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
528         }
529 }
530
531 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
532 {
533 #ifdef CAN_LOAD_PALETTE
534         if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
535             || !CON_IS_VISIBLE(vc))
536                 return -EINVAL;
537         vga_set_palette(vc, table);
538         return 0;
539 #else
540         return -EINVAL;
541 #endif
542 }
543
544 /* structure holding original VGA register settings */
545 static struct {
546         unsigned char SeqCtrlIndex;     /* Sequencer Index reg.   */
547         unsigned char CrtCtrlIndex;     /* CRT-Contr. Index reg.  */
548         unsigned char CrtMiscIO;        /* Miscellaneous register */
549         unsigned char HorizontalTotal;  /* CRT-Controller:00h */
550         unsigned char HorizDisplayEnd;  /* CRT-Controller:01h */
551         unsigned char StartHorizRetrace;        /* CRT-Controller:04h */
552         unsigned char EndHorizRetrace;  /* CRT-Controller:05h */
553         unsigned char Overflow; /* CRT-Controller:07h */
554         unsigned char StartVertRetrace; /* CRT-Controller:10h */
555         unsigned char EndVertRetrace;   /* CRT-Controller:11h */
556         unsigned char ModeControl;      /* CRT-Controller:17h */
557         unsigned char ClockingMode;     /* Seq-Controller:01h */
558 } vga_state;
559
560 static void vga_vesa_blank(struct vgastate *state, int mode)
561 {
562         /* save original values of VGA controller registers */
563         if (!vga_vesa_blanked) {
564                 spin_lock_irq(&vga_lock);
565                 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
566                 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
567                 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
568                 spin_unlock_irq(&vga_lock);
569
570                 outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
571                 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
572                 outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
573                 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
574                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
575                 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
576                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
577                 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
578                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
579                 vga_state.Overflow = inb_p(vga_video_port_val);
580                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
581                 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
582                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
583                 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
584                 outb_p(0x17, vga_video_port_reg);       /* ModeControl */
585                 vga_state.ModeControl = inb_p(vga_video_port_val);
586                 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
587         }
588
589         /* assure that video is enabled */
590         /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
591         spin_lock_irq(&vga_lock);
592         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
593
594         /* test for vertical retrace in process.... */
595         if ((vga_state.CrtMiscIO & 0x80) == 0x80)
596                 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
597
598         /*
599          * Set <End of vertical retrace> to minimum (0) and
600          * <Start of vertical Retrace> to maximum (incl. overflow)
601          * Result: turn off vertical sync (VSync) pulse.
602          */
603         if (mode & VESA_VSYNC_SUSPEND) {
604                 outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
605                 outb_p(0xff, vga_video_port_val);       /* maximum value */
606                 outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
607                 outb_p(0x40, vga_video_port_val);       /* minimum (bits 0..3)  */
608                 outb_p(0x07, vga_video_port_reg);       /* Overflow */
609                 outb_p(vga_state.Overflow | 0x84, vga_video_port_val);  /* bits 9,10 of vert. retrace */
610         }
611
612         if (mode & VESA_HSYNC_SUSPEND) {
613                 /*
614                  * Set <End of horizontal retrace> to minimum (0) and
615                  *  <Start of horizontal Retrace> to maximum
616                  * Result: turn off horizontal sync (HSync) pulse.
617                  */
618                 outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
619                 outb_p(0xff, vga_video_port_val);       /* maximum */
620                 outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
621                 outb_p(0x00, vga_video_port_val);       /* minimum (0) */
622         }
623
624         /* restore both index registers */
625         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
626         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
627         spin_unlock_irq(&vga_lock);
628 }
629
630 static void vga_vesa_unblank(struct vgastate *state)
631 {
632         /* restore original values of VGA controller registers */
633         spin_lock_irq(&vga_lock);
634         vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
635
636         outb_p(0x00, vga_video_port_reg);       /* HorizontalTotal */
637         outb_p(vga_state.HorizontalTotal, vga_video_port_val);
638         outb_p(0x01, vga_video_port_reg);       /* HorizDisplayEnd */
639         outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
640         outb_p(0x04, vga_video_port_reg);       /* StartHorizRetrace */
641         outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
642         outb_p(0x05, vga_video_port_reg);       /* EndHorizRetrace */
643         outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
644         outb_p(0x07, vga_video_port_reg);       /* Overflow */
645         outb_p(vga_state.Overflow, vga_video_port_val);
646         outb_p(0x10, vga_video_port_reg);       /* StartVertRetrace */
647         outb_p(vga_state.StartVertRetrace, vga_video_port_val);
648         outb_p(0x11, vga_video_port_reg);       /* EndVertRetrace */
649         outb_p(vga_state.EndVertRetrace, vga_video_port_val);
650         outb_p(0x17, vga_video_port_reg);       /* ModeControl */
651         outb_p(vga_state.ModeControl, vga_video_port_val);
652         /* ClockingMode */
653         vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
654
655         /* restore index/control registers */
656         vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
657         outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
658         spin_unlock_irq(&vga_lock);
659 }
660
661 static void vga_pal_blank(struct vgastate *state)
662 {
663         int i;
664
665         for (i = 0; i < 16; i++) {
666                 vga_w(state->vgabase, VGA_PEL_IW, i);
667                 vga_w(state->vgabase, VGA_PEL_D, 0);
668                 vga_w(state->vgabase, VGA_PEL_D, 0);
669                 vga_w(state->vgabase, VGA_PEL_D, 0);
670         }
671 }
672
673 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
674 {
675         switch (blank) {
676         case 0:         /* Unblank */
677                 if (vga_vesa_blanked) {
678                         vga_vesa_unblank(&state);
679                         vga_vesa_blanked = 0;
680                 }
681                 if (vga_palette_blanked) {
682                         vga_set_palette(c, color_table);
683                         vga_palette_blanked = 0;
684                         return 0;
685                 }
686                 vga_is_gfx = 0;
687                 /* Tell console.c that it has to restore the screen itself */
688                 return 1;
689         case 1:         /* Normal blanking */
690         case -1:        /* Obsolete */
691                 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
692                         vga_pal_blank(&state);
693                         vga_palette_blanked = 1;
694                         return 0;
695                 }
696                 vgacon_set_origin(c);
697                 scr_memsetw((void *) vga_vram_base, BLANK,
698                             c->vc_screenbuf_size);
699                 if (mode_switch)
700                         vga_is_gfx = 1;
701                 return 1;
702         default:                /* VESA blanking */
703                 if (vga_video_type == VIDEO_TYPE_VGAC) {
704                         vga_vesa_blank(&state, blank - 1);
705                         vga_vesa_blanked = blank;
706                 }
707                 return 0;
708         }
709 }
710
711 /*
712  * PIO_FONT support.
713  *
714  * The font loading code goes back to the codepage package by
715  * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
716  * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
717  * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
718  *
719  * Change for certain monochrome monitors by Yury Shevchuck
720  * (sizif@botik.yaroslavl.su).
721  */
722
723 #ifdef CAN_LOAD_EGA_FONTS
724
725 #define colourmap 0xa0000
726 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
727    should use 0xA0000 for the bwmap as well.. */
728 #define blackwmap 0xa0000
729 #define cmapsz 8192
730
731 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
732 {
733         unsigned short video_port_status = vga_video_port_reg + 6;
734         int font_select = 0x00, beg, i;
735         char *charmap;
736         
737         if (vga_video_type != VIDEO_TYPE_EGAM) {
738                 charmap = (char *) VGA_MAP_MEM(colourmap);
739                 beg = 0x0e;
740 #ifdef VGA_CAN_DO_64KB
741                 if (vga_video_type == VIDEO_TYPE_VGAC)
742                         beg = 0x06;
743 #endif
744         } else {
745                 charmap = (char *) VGA_MAP_MEM(blackwmap);
746                 beg = 0x0a;
747         }
748
749 #ifdef BROKEN_GRAPHICS_PROGRAMS
750         /*
751          * All fonts are loaded in slot 0 (0:1 for 512 ch)
752          */
753
754         if (!arg)
755                 return -EINVAL; /* Return to default font not supported */
756
757         vga_font_is_default = 0;
758         font_select = ch512 ? 0x04 : 0x00;
759 #else
760         /*
761          * The default font is kept in slot 0 and is never touched.
762          * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
763          */
764
765         if (set) {
766                 vga_font_is_default = !arg;
767                 if (!arg)
768                         ch512 = 0;      /* Default font is always 256 */
769                 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
770         }
771
772         if (!vga_font_is_default)
773                 charmap += 4 * cmapsz;
774 #endif
775
776         unlock_kernel();
777         spin_lock_irq(&vga_lock);
778         /* First, the Sequencer */
779         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
780         /* CPU writes only to map 2 */
781         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);    
782         /* Sequential addressing */
783         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);    
784         /* Clear synchronous reset */
785         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
786
787         /* Now, the graphics controller, select map 2 */
788         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);             
789         /* disable odd-even addressing */
790         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
791         /* map start at A000:0000 */
792         vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
793         spin_unlock_irq(&vga_lock);
794
795         if (arg) {
796                 if (set)
797                         for (i = 0; i < cmapsz; i++)
798                                 vga_writeb(arg[i], charmap + i);
799                 else
800                         for (i = 0; i < cmapsz; i++)
801                                 arg[i] = vga_readb(charmap + i);
802
803                 /*
804                  * In 512-character mode, the character map is not contiguous if
805                  * we want to remain EGA compatible -- which we do
806                  */
807
808                 if (ch512) {
809                         charmap += 2 * cmapsz;
810                         arg += cmapsz;
811                         if (set)
812                                 for (i = 0; i < cmapsz; i++)
813                                         vga_writeb(arg[i], charmap + i);
814                         else
815                                 for (i = 0; i < cmapsz; i++)
816                                         arg[i] = vga_readb(charmap + i);
817                 }
818         }
819
820         spin_lock_irq(&vga_lock);
821         /* First, the sequencer, Synchronous reset */
822         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);  
823         /* CPU writes to maps 0 and 1 */
824         vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
825         /* odd-even addressing */
826         vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
827         /* Character Map Select */
828         if (set)
829                 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
830         /* clear synchronous reset */
831         vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
832
833         /* Now, the graphics controller, select map 0 for CPU */
834         vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
835         /* enable even-odd addressing */
836         vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
837         /* map starts at b800:0 or b000:0 */
838         vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
839
840         /* if 512 char mode is already enabled don't re-enable it. */
841         if ((set) && (ch512 != vga_512_chars)) {
842                 int i;  
843                 
844                 /* attribute controller */
845                 for (i = 0; i < MAX_NR_CONSOLES; i++) {
846                         struct vc_data *c = vc_cons[i].d;
847                         if (c && c->vc_sw == &vga_con)
848                                 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
849                 }
850                 vga_512_chars = ch512;
851                 /* 256-char: enable intensity bit
852                    512-char: disable intensity bit */
853                 inb_p(video_port_status);       /* clear address flip-flop */
854                 /* color plane enable register */
855                 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
856                 /* Wilton (1987) mentions the following; I don't know what
857                    it means, but it works, and it appears necessary */
858                 inb_p(video_port_status);
859                 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);    
860         }
861         spin_unlock_irq(&vga_lock);
862         lock_kernel();
863         return 0;
864 }
865
866 /*
867  * Adjust the screen to fit a font of a certain height
868  */
869 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
870 {
871         unsigned char ovr, vde, fsr;
872         int rows, maxscan, i;
873
874         rows = vc->vc_scan_lines / fontheight;  /* Number of video rows we end up with */
875         maxscan = rows * fontheight - 1;        /* Scan lines to actually display-1 */
876
877         /* Reprogram the CRTC for the new font size
878            Note: the attempt to read the overflow register will fail
879            on an EGA, but using 0xff for the previous value appears to
880            be OK for EGA text modes in the range 257-512 scan lines, so I
881            guess we don't need to worry about it.
882
883            The same applies for the spill bits in the font size and cursor
884            registers; they are write-only on EGA, but it appears that they
885            are all don't care bits on EGA, so I guess it doesn't matter. */
886
887         spin_lock_irq(&vga_lock);
888         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
889         ovr = inb_p(vga_video_port_val);
890         outb_p(0x09, vga_video_port_reg);       /* Font size register */
891         fsr = inb_p(vga_video_port_val);
892         spin_unlock_irq(&vga_lock);
893
894         vde = maxscan & 0xff;   /* Vertical display end reg */
895         ovr = (ovr & 0xbd) +    /* Overflow register */
896             ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
897         fsr = (fsr & 0xe0) + (fontheight - 1);  /*  Font size register */
898
899         spin_lock_irq(&vga_lock);
900         outb_p(0x07, vga_video_port_reg);       /* CRTC overflow register */
901         outb_p(ovr, vga_video_port_val);
902         outb_p(0x09, vga_video_port_reg);       /* Font size */
903         outb_p(fsr, vga_video_port_val);
904         outb_p(0x12, vga_video_port_reg);       /* Vertical display limit */
905         outb_p(vde, vga_video_port_val);
906         spin_unlock_irq(&vga_lock);
907
908         for (i = 0; i < MAX_NR_CONSOLES; i++) {
909                 struct vc_data *c = vc_cons[i].d;
910
911                 if (c && c->vc_sw == &vga_con) {
912                         if (CON_IS_VISIBLE(c)) {
913                                 /* void size to cause regs to be rewritten */
914                                 cursor_size_lastfrom = 0;
915                                 cursor_size_lastto = 0;
916                                 c->vc_sw->con_cursor(c, CM_DRAW);
917                         }
918                         c->vc_font.height = fontheight;
919                         vc_resize(c, 0, rows);  /* Adjust console size */
920                 }
921         }
922         return 0;
923 }
924
925 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
926 {
927         unsigned charcount = font->charcount;
928         int rc;
929
930         if (vga_video_type < VIDEO_TYPE_EGAM)
931                 return -EINVAL;
932
933         if (font->width != 8 || (charcount != 256 && charcount != 512))
934                 return -EINVAL;
935
936         rc = vgacon_do_font_op(&state, font->data, 1, charcount == 512);
937         if (rc)
938                 return rc;
939
940         if (!(flags & KD_FONT_FLAG_DONT_RECALC))
941                 rc = vgacon_adjust_height(c, font->height);
942         return rc;
943 }
944
945 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
946 {
947         if (vga_video_type < VIDEO_TYPE_EGAM)
948                 return -EINVAL;
949
950         font->width = 8;
951         font->height = c->vc_font.height;
952         font->charcount = vga_512_chars ? 512 : 256;
953         if (!font->data)
954                 return 0;
955         return vgacon_do_font_op(&state, font->data, 0, 0);
956 }
957
958 #else
959
960 #define vgacon_font_set NULL
961 #define vgacon_font_get NULL
962
963 #endif
964
965 static int vgacon_scrolldelta(struct vc_data *c, int lines)
966 {
967         if (!lines)             /* Turn scrollback off */
968                 c->vc_visible_origin = c->vc_origin;
969         else {
970                 int margin = c->vc_size_row * 4;
971                 int ul, we, p, st;
972
973                 if (vga_rolled_over >
974                     (c->vc_scr_end - vga_vram_base) + margin) {
975                         ul = c->vc_scr_end - vga_vram_base;
976                         we = vga_rolled_over + c->vc_size_row;
977                 } else {
978                         ul = 0;
979                         we = vga_vram_size;
980                 }
981                 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
982                     lines * c->vc_size_row;
983                 st = (c->vc_origin - vga_vram_base - ul + we) % we;
984                 if (st < 2 * margin)
985                         margin = 0;
986                 if (p < margin)
987                         p = 0;
988                 if (p > st - margin)
989                         p = st;
990                 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
991         }
992         vga_set_mem_top(c);
993         return 1;
994 }
995
996 static int vgacon_set_origin(struct vc_data *c)
997 {
998         if (vga_is_gfx ||       /* We don't play origin tricks in graphic modes */
999             (console_blanked && !vga_palette_blanked))  /* Nor we write to blanked screens */
1000                 return 0;
1001         c->vc_origin = c->vc_visible_origin = vga_vram_base;
1002         vga_set_mem_top(c);
1003         vga_rolled_over = 0;
1004         return 1;
1005 }
1006
1007 static void vgacon_save_screen(struct vc_data *c)
1008 {
1009         static int vga_bootup_console = 0;
1010
1011         if (!vga_bootup_console) {
1012                 /* This is a gross hack, but here is the only place we can
1013                  * set bootup console parameters without messing up generic
1014                  * console initialization routines.
1015                  */
1016                 vga_bootup_console = 1;
1017                 c->vc_x = ORIG_X;
1018                 c->vc_y = ORIG_Y;
1019         }
1020
1021         /* We can't copy in more then the size of the video buffer,
1022          * or we'll be copying in VGA BIOS */
1023
1024         if (!vga_is_gfx)
1025                 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1026                             c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1027 }
1028
1029 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1030                          int lines)
1031 {
1032         unsigned long oldo;
1033         unsigned int delta;
1034
1035         if (t || b != c->vc_rows || vga_is_gfx)
1036                 return 0;
1037
1038         if (c->vc_origin != c->vc_visible_origin)
1039                 vgacon_scrolldelta(c, 0);
1040
1041         if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1042                 return 0;
1043
1044         oldo = c->vc_origin;
1045         delta = lines * c->vc_size_row;
1046         if (dir == SM_UP) {
1047                 if (c->vc_scr_end + delta >= vga_vram_end) {
1048                         scr_memcpyw((u16 *) vga_vram_base,
1049                                     (u16 *) (oldo + delta),
1050                                     c->vc_screenbuf_size - delta);
1051                         c->vc_origin = vga_vram_base;
1052                         vga_rolled_over = oldo - vga_vram_base;
1053                 } else
1054                         c->vc_origin += delta;
1055                 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1056                                      delta), c->vc_video_erase_char,
1057                             delta);
1058         } else {
1059                 if (oldo - delta < vga_vram_base) {
1060                         scr_memmovew((u16 *) (vga_vram_end -
1061                                               c->vc_screenbuf_size +
1062                                               delta), (u16 *) oldo,
1063                                      c->vc_screenbuf_size - delta);
1064                         c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1065                         vga_rolled_over = 0;
1066                 } else
1067                         c->vc_origin -= delta;
1068                 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1069                 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1070                             delta);
1071         }
1072         c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1073         c->vc_visible_origin = c->vc_origin;
1074         vga_set_mem_top(c);
1075         c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1076         return 1;
1077 }
1078
1079
1080 /*
1081  *  The console `switch' structure for the VGA based console
1082  */
1083
1084 static int vgacon_dummy(struct vc_data *c)
1085 {
1086         return 0;
1087 }
1088
1089 #define DUMMY (void *) vgacon_dummy
1090
1091 const struct consw vga_con = {
1092         .owner = THIS_MODULE,
1093         .con_startup = vgacon_startup,
1094         .con_init = vgacon_init,
1095         .con_deinit = vgacon_deinit,
1096         .con_clear = DUMMY,
1097         .con_putc = DUMMY,
1098         .con_putcs = DUMMY,
1099         .con_cursor = vgacon_cursor,
1100         .con_scroll = vgacon_scroll,
1101         .con_bmove = DUMMY,
1102         .con_switch = vgacon_switch,
1103         .con_blank = vgacon_blank,
1104         .con_font_set = vgacon_font_set,
1105         .con_font_get = vgacon_font_get,
1106         .con_set_palette = vgacon_set_palette,
1107         .con_scrolldelta = vgacon_scrolldelta,
1108         .con_set_origin = vgacon_set_origin,
1109         .con_save_screen = vgacon_save_screen,
1110         .con_build_attr = vgacon_build_attr,
1111         .con_invert_region = vgacon_invert_region,
1112 };
1113
1114 MODULE_LICENSE("GPL");