2 * linux/drivers/video/vgacon.c -- Low level VGA based console driver
4 * Created 28 Sep 1997 by Geert Uytterhoeven
6 * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
8 * This file is based on the old console.c, vga.c and vesa_blank.c drivers.
10 * Copyright (C) 1991, 1992 Linus Torvalds
13 * User definable mapping table and font loading by Eugene G. Crosser,
14 * <crosser@pccross.msk.su>
16 * Improved loadable font/UTF-8 support by H. Peter Anvin
17 * Feb-Sep 1995 <peter.anvin@linux.org>
19 * Colour palette handling, by Simon Tatham
20 * 17-Jun-95 <sgt20@cam.ac.uk>
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>
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.
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
36 #include <linux/config.h>
37 #include <linux/types.h>
38 #include <linux/sched.h>
40 #include <linux/kernel.h>
41 #include <linux/tty.h>
42 #include <linux/console.h>
43 #include <linux/console_struct.h>
44 #include <linux/string.h>
46 #include <linux/malloc.h>
47 #include <linux/vt_kern.h>
48 #include <linux/selection.h>
49 #include <linux/ioport.h>
50 #include <linux/init.h>
57 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
58 #define CAN_LOAD_PALETTE /* undefine if the user must not do this */
60 /* You really do _NOT_ want to define this, unless you have buggy
61 * Trident VGA which will resize cursor when moving it between column
62 * 15 & 16. If you define this and your VGA is OK, inverse bug will
69 #define attrib_port 0x3c0
70 #define seq_port_reg 0x3c4
71 #define seq_port_val 0x3c5
72 #define gr_port_reg 0x3ce
73 #define gr_port_val 0x3cf
74 #define video_misc_rd 0x3cc
75 #define video_misc_wr 0x3c2
78 * Interface used by the world
81 static const char *vgacon_startup(void);
82 static void vgacon_init(struct vc_data
*c
, int init
);
83 static void vgacon_deinit(struct vc_data
*c
);
84 static void vgacon_cursor(struct vc_data
*c
, int mode
);
85 static int vgacon_switch(struct vc_data
*c
);
86 static int vgacon_blank(struct vc_data
*c
, int blank
);
87 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
);
88 static int vgacon_set_palette(struct vc_data
*c
, unsigned char *table
);
89 static int vgacon_scrolldelta(struct vc_data
*c
, int lines
);
90 static int vgacon_set_origin(struct vc_data
*c
);
91 static void vgacon_save_screen(struct vc_data
*c
);
92 static int vgacon_scroll(struct vc_data
*c
, int t
, int b
, int dir
, int lines
);
93 static u8
vgacon_build_attr(struct vc_data
*c
, u8 color
, u8 intensity
, u8 blink
, u8 underline
, u8 reverse
);
94 static void vgacon_invert_region(struct vc_data
*c
, u16
*p
, int count
);
95 static unsigned long vgacon_uni_pagedir
[2];
98 /* Description of the hardware situation */
99 static unsigned long vga_vram_base
; /* Base of video memory */
100 static unsigned long vga_vram_end
; /* End of video memory */
101 static u16 vga_video_port_reg
; /* Video register select port */
102 static u16 vga_video_port_val
; /* Video register value port */
103 static unsigned int vga_video_num_columns
; /* Number of text columns */
104 static unsigned int vga_video_num_lines
; /* Number of text lines */
105 static int vga_can_do_color
= 0; /* Do we support colors? */
106 static unsigned int vga_default_font_height
; /* Height of default screen font */
107 static unsigned char vga_video_type
; /* Card type */
108 static unsigned char vga_hardscroll_enabled
;
109 static unsigned char vga_hardscroll_user_enable
= 1;
110 static unsigned char vga_font_is_default
= 1;
111 static int vga_vesa_blanked
;
112 static int vga_palette_blanked
;
113 static int vga_is_gfx
;
114 static int vga_512_chars
;
115 static int vga_video_font_height
;
116 static unsigned int vga_rolled_over
= 0;
119 void no_scroll(char *str
, int *ints
)
122 * Disabling scrollback is required for the Braillex ib80-piezo
123 * Braille reader made by F.H. Papenmeier (Germany).
124 * Use the "no-scroll" bootflag.
126 vga_hardscroll_user_enable
= vga_hardscroll_enabled
= 0;
130 * By replacing the four outb_p with two back to back outw, we can reduce
131 * the window of opportunity to see text mislocated to the RHS of the
132 * console during heavy scrolling activity. However there is the remote
133 * possibility that some pre-dinosaur hardware won't like the back to back
134 * I/O. Since the Xservers get away with it, we should be able to as well.
136 static inline void write_vga(unsigned char reg
, unsigned int val
)
142 * ddprintk might set the console position from interrupt
143 * handlers, thus the write has to be IRQ-atomic.
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
);
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
);
159 restore_flags(flags
);
162 __initfunc(static const char *vgacon_startup(void))
164 const char *display_desc
= NULL
;
168 if (ORIG_VIDEO_ISVGA
== VIDEO_TYPE_VLFB
) {
170 #ifdef CONFIG_DUMMY_CONSOLE
171 conswitchp
= &dummy_con
;
172 return conswitchp
->con_startup();
179 vga_video_num_lines
= ORIG_VIDEO_LINES
;
180 vga_video_num_columns
= ORIG_VIDEO_COLS
;
182 if (ORIG_VIDEO_MODE
== 7) /* Is this a monochrome display? */
184 vga_vram_base
= 0xb0000;
185 vga_video_port_reg
= 0x3b4;
186 vga_video_port_val
= 0x3b5;
187 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
189 vga_video_type
= VIDEO_TYPE_EGAM
;
190 vga_vram_end
= 0xb8000;
191 display_desc
= "EGA+";
192 request_region(0x3b0,16,"ega");
196 vga_video_type
= VIDEO_TYPE_MDA
;
197 vga_vram_end
= 0xb2000;
198 display_desc
= "*MDA";
199 request_region(0x3b0,12,"mda");
200 request_region(0x3bf, 1,"mda");
201 vga_video_font_height
= 14;
204 else /* If not, it is color. */
206 vga_can_do_color
= 1;
207 vga_vram_base
= 0xb8000;
208 vga_video_port_reg
= 0x3d4;
209 vga_video_port_val
= 0x3d5;
210 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
214 vga_vram_end
= 0xc0000;
216 if (!ORIG_VIDEO_ISVGA
) {
217 vga_video_type
= VIDEO_TYPE_EGAC
;
218 display_desc
= "EGA";
219 request_region(0x3c0,32,"ega");
221 vga_video_type
= VIDEO_TYPE_VGAC
;
222 display_desc
= "VGA+";
223 request_region(0x3c0,32,"vga+");
225 #ifdef VGA_CAN_DO_64KB
227 * get 64K rather than 32K of video RAM.
228 * This doesn't actually work on all "VGA"
229 * controllers (it seems like setting MM=01
230 * and COE=1 isn't necessarily a good idea)
232 vga_vram_base
= 0xa0000;
233 vga_vram_end
= 0xb0000;
239 * Normalise the palette registers, to point
240 * the 16 screen colours to the first 16
244 for (i
=0; i
<16; i
++) {
249 outb_p (0x20, 0x3c0) ;
251 /* now set the DAC registers back to their
254 for (i
=0; i
<16; i
++) {
255 outb_p (color_table
[i
], 0x3c8) ;
256 outb_p (default_red
[i
], 0x3c9) ;
257 outb_p (default_grn
[i
], 0x3c9) ;
258 outb_p (default_blu
[i
], 0x3c9) ;
264 vga_video_type
= VIDEO_TYPE_CGA
;
265 vga_vram_end
= 0xba000;
266 display_desc
= "*CGA";
267 request_region(0x3d4,2,"cga");
268 vga_video_font_height
= 8;
271 vga_vram_base
= VGA_MAP_MEM(vga_vram_base
);
272 vga_vram_end
= VGA_MAP_MEM(vga_vram_end
);
275 * Find out if there is a graphics card present.
276 * Are there smarter methods around?
278 p
= (u16
*)vga_vram_base
;
279 saved1
= scr_readw(p
);
280 saved2
= scr_readw(p
+ 1);
281 scr_writew(0xAA55, p
);
282 scr_writew(0x55AA, p
+ 1);
283 if (scr_readw(p
) != 0xAA55 || scr_readw(p
+ 1) != 0x55AA) {
284 scr_writew(saved1
, p
);
285 scr_writew(saved2
, p
+ 1);
288 scr_writew(0x55AA, p
);
289 scr_writew(0xAA55, p
+ 1);
290 if (scr_readw(p
) != 0x55AA || scr_readw(p
+ 1) != 0xAA55) {
291 scr_writew(saved1
, p
);
292 scr_writew(saved2
, p
+ 1);
295 scr_writew(saved1
, p
);
296 scr_writew(saved2
, p
+ 1);
298 if (vga_video_type
== VIDEO_TYPE_EGAC
299 || vga_video_type
== VIDEO_TYPE_VGAC
300 || vga_video_type
== VIDEO_TYPE_EGAM
) {
301 vga_hardscroll_enabled
= vga_hardscroll_user_enable
;
302 vga_default_font_height
= ORIG_VIDEO_POINTS
;
303 vga_video_font_height
= ORIG_VIDEO_POINTS
;
304 /* This may be suboptimal but is a safe bet - go with it */
306 vga_video_font_height
* vga_video_num_lines
;
308 video_font_height
= vga_video_font_height
;
313 static void vgacon_init(struct vc_data
*c
, int init
)
317 /* We cannot be loaded as a module, therefore init is always 1 */
318 c
->vc_can_do_color
= vga_can_do_color
;
319 c
->vc_cols
= vga_video_num_columns
;
320 c
->vc_rows
= vga_video_num_lines
;
321 c
->vc_complement_mask
= 0x7700;
322 p
= *c
->vc_uni_pagedir_loc
;
323 if (c
->vc_uni_pagedir_loc
== &c
->vc_uni_pagedir
||
324 !--c
->vc_uni_pagedir_loc
[1])
325 con_free_unimap(c
->vc_num
);
326 c
->vc_uni_pagedir_loc
= vgacon_uni_pagedir
;
327 vgacon_uni_pagedir
[1]++;
328 if (!vgacon_uni_pagedir
[0] && p
)
329 con_set_default_unimap(c
->vc_num
);
332 static inline void vga_set_mem_top(struct vc_data
*c
)
334 write_vga(12, (c
->vc_visible_origin
-vga_vram_base
)/2);
337 static void vgacon_deinit(struct vc_data
*c
)
339 /* When closing the last console, reset video origin */
340 if (!--vgacon_uni_pagedir
[1]) {
341 c
->vc_visible_origin
= vga_vram_base
;
343 con_free_unimap(c
->vc_num
);
345 c
->vc_uni_pagedir_loc
= &c
->vc_uni_pagedir
;
346 con_set_default_unimap(c
->vc_num
);
349 static u8
vgacon_build_attr(struct vc_data
*c
, u8 color
, u8 intensity
, u8 blink
, u8 underline
, u8 reverse
)
353 if (vga_can_do_color
) {
355 attr
= (attr
& 0xf0) | c
->vc_ulcolor
;
356 else if (intensity
== 0)
357 attr
= (attr
& 0xf0) | c
->vc_halfcolor
;
360 attr
= ((attr
) & 0x88) | ((((attr
) >> 4) | ((attr
) << 4)) & 0x77);
365 if (!vga_can_do_color
) {
367 attr
= (attr
& 0xf8) | 0x01;
368 else if (intensity
== 0)
369 attr
= (attr
& 0xf0) | 0x08;
374 static void vgacon_invert_region(struct vc_data
*c
, u16
*p
, int count
)
376 int col
= vga_can_do_color
;
379 u16 a
= scr_readw(p
);
381 a
= ((a
) & 0x88ff) | (((a
) & 0x7000) >> 4) | (((a
) & 0x0700) << 4);
383 a
^= ((a
& 0x0700) == 0x0100) ? 0x7000 : 0x7700;
388 static void vgacon_set_cursor_size(int xpos
, int from
, int to
)
392 static int lastfrom
, lastto
;
394 #ifdef TRIDENT_GLITCH
395 if (xpos
<16) from
--, to
--;
398 if ((from
== lastfrom
) && (to
== lastto
)) return;
399 lastfrom
= from
; lastto
= to
;
401 save_flags(flags
); cli();
402 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
403 curs
= inb_p(vga_video_port_val
);
404 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
405 cure
= inb_p(vga_video_port_val
);
407 curs
= (curs
& 0xc0) | from
;
408 cure
= (cure
& 0xe0) | to
;
410 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
411 outb_p(curs
, vga_video_port_val
);
412 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
413 outb_p(cure
, vga_video_port_val
);
414 restore_flags(flags
);
417 static void vgacon_cursor(struct vc_data
*c
, int mode
)
419 if (c
->vc_origin
!= c
->vc_visible_origin
)
420 vgacon_scrolldelta(c
, 0);
423 write_vga(14, (vga_vram_end
- vga_vram_base
- 1)/2);
428 write_vga(14, (c
->vc_pos
-vga_vram_base
)/2);
429 switch (c
->vc_cursor_type
& 0x0f) {
431 vgacon_set_cursor_size(c
->vc_x
,
432 video_font_height
- (video_font_height
< 10 ? 2 : 3),
433 video_font_height
- (video_font_height
< 10 ? 1 : 2));
436 vgacon_set_cursor_size(c
->vc_x
,
437 video_font_height
/ 3,
438 video_font_height
- (video_font_height
< 10 ? 1 : 2));
440 case CUR_LOWER_THIRD
:
441 vgacon_set_cursor_size(c
->vc_x
,
442 (video_font_height
*2) / 3,
443 video_font_height
- (video_font_height
< 10 ? 1 : 2));
446 vgacon_set_cursor_size(c
->vc_x
,
447 video_font_height
/ 2,
448 video_font_height
- (video_font_height
< 10 ? 1 : 2));
451 vgacon_set_cursor_size(c
->vc_x
, 31, 30);
454 vgacon_set_cursor_size(c
->vc_x
, 1, video_font_height
);
461 static int vgacon_switch(struct vc_data
*c
)
464 * We need to save screen size here as it's the only way
465 * we can spot the screen has been resized and we need to
466 * set size of freshly allocated screens ourselves.
468 vga_video_num_columns
= c
->vc_cols
;
469 vga_video_num_lines
= c
->vc_rows
;
471 scr_memcpyw_to((u16
*) c
->vc_origin
, (u16
*) c
->vc_screenbuf
, c
->vc_screenbuf_size
);
472 return 0; /* Redrawing not needed */
475 static void vga_set_palette(struct vc_data
*c
, unsigned char *table
)
479 for (i
=j
=0; i
<16; i
++) {
480 outb_p (table
[i
], dac_reg
) ;
481 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
482 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
483 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
487 static int vgacon_set_palette(struct vc_data
*c
, unsigned char *table
)
489 #ifdef CAN_LOAD_PALETTE
490 if (vga_video_type
!= VIDEO_TYPE_VGAC
|| vga_palette_blanked
|| !CON_IS_VISIBLE(c
))
492 vga_set_palette(c
, table
);
499 /* structure holding original VGA register settings */
501 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
502 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
503 unsigned char CrtMiscIO
; /* Miscellaneous register */
504 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
505 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
506 unsigned char StartHorizRetrace
; /* CRT-Controller:04h */
507 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
508 unsigned char Overflow
; /* CRT-Controller:07h */
509 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
510 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
511 unsigned char ModeControl
; /* CRT-Controller:17h */
512 unsigned char ClockingMode
; /* Seq-Controller:01h */
515 static void vga_vesa_blank(int mode
)
517 /* save original values of VGA controller registers */
518 if(!vga_vesa_blanked
) {
520 vga_state
.SeqCtrlIndex
= inb_p(seq_port_reg
);
521 vga_state
.CrtCtrlIndex
= inb_p(vga_video_port_reg
);
522 vga_state
.CrtMiscIO
= inb_p(video_misc_rd
);
525 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
526 vga_state
.HorizontalTotal
= inb_p(vga_video_port_val
);
527 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
528 vga_state
.HorizDisplayEnd
= inb_p(vga_video_port_val
);
529 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
530 vga_state
.StartHorizRetrace
= inb_p(vga_video_port_val
);
531 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
532 vga_state
.EndHorizRetrace
= inb_p(vga_video_port_val
);
533 outb_p(0x07,vga_video_port_reg
); /* Overflow */
534 vga_state
.Overflow
= inb_p(vga_video_port_val
);
535 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
536 vga_state
.StartVertRetrace
= inb_p(vga_video_port_val
);
537 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
538 vga_state
.EndVertRetrace
= inb_p(vga_video_port_val
);
539 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
540 vga_state
.ModeControl
= inb_p(vga_video_port_val
);
541 outb_p(0x01,seq_port_reg
); /* ClockingMode */
542 vga_state
.ClockingMode
= inb_p(seq_port_val
);
545 /* assure that video is enabled */
546 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
548 outb_p(0x01,seq_port_reg
);
549 outb_p(vga_state
.ClockingMode
| 0x20,seq_port_val
);
551 /* test for vertical retrace in process.... */
552 if ((vga_state
.CrtMiscIO
& 0x80) == 0x80)
553 outb_p(vga_state
.CrtMiscIO
& 0xef,video_misc_wr
);
556 * Set <End of vertical retrace> to minimum (0) and
557 * <Start of vertical Retrace> to maximum (incl. overflow)
558 * Result: turn off vertical sync (VSync) pulse.
560 if (mode
& VESA_VSYNC_SUSPEND
) {
561 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
562 outb_p(0xff,vga_video_port_val
); /* maximum value */
563 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
564 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
565 outb_p(0x07,vga_video_port_reg
); /* Overflow */
566 outb_p(vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
569 if (mode
& VESA_HSYNC_SUSPEND
) {
571 * Set <End of horizontal retrace> to minimum (0) and
572 * <Start of horizontal Retrace> to maximum
573 * Result: turn off horizontal sync (HSync) pulse.
575 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
576 outb_p(0xff,vga_video_port_val
); /* maximum */
577 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
578 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
581 /* restore both index registers */
582 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
583 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
587 static void vga_vesa_unblank(void)
589 /* restore original values of VGA controller registers */
591 outb_p(vga_state
.CrtMiscIO
,video_misc_wr
);
593 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
594 outb_p(vga_state
.HorizontalTotal
,vga_video_port_val
);
595 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
596 outb_p(vga_state
.HorizDisplayEnd
,vga_video_port_val
);
597 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
598 outb_p(vga_state
.StartHorizRetrace
,vga_video_port_val
);
599 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
600 outb_p(vga_state
.EndHorizRetrace
,vga_video_port_val
);
601 outb_p(0x07,vga_video_port_reg
); /* Overflow */
602 outb_p(vga_state
.Overflow
,vga_video_port_val
);
603 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
604 outb_p(vga_state
.StartVertRetrace
,vga_video_port_val
);
605 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
606 outb_p(vga_state
.EndVertRetrace
,vga_video_port_val
);
607 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
608 outb_p(vga_state
.ModeControl
,vga_video_port_val
);
609 outb_p(0x01,seq_port_reg
); /* ClockingMode */
610 outb_p(vga_state
.ClockingMode
,seq_port_val
);
612 /* restore index/control registers */
613 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
614 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
618 static void vga_pal_blank(void)
622 for (i
=0; i
<16; i
++) {
623 outb_p (i
, dac_reg
) ;
624 outb_p (0, dac_val
) ;
625 outb_p (0, dac_val
) ;
626 outb_p (0, dac_val
) ;
630 static int vgacon_blank(struct vc_data
*c
, int blank
)
633 case 0: /* Unblank */
634 if (vga_vesa_blanked
) {
636 vga_vesa_blanked
= 0;
638 if (vga_palette_blanked
) {
639 vga_set_palette(c
, color_table
);
640 vga_palette_blanked
= 0;
644 /* Tell console.c that it has to restore the screen itself */
646 case 1: /* Normal blanking */
647 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
649 vga_palette_blanked
= 1;
652 vgacon_set_origin(c
);
653 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
655 case -1: /* Entering graphic mode */
656 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
659 default: /* VESA blanking */
660 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
661 vga_vesa_blank(blank
-1);
662 vga_vesa_blanked
= blank
;
671 * The font loading code goes back to the codepage package by
672 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
673 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
674 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
676 * Change for certain monochrome monitors by Yury Shevchuck
677 * (sizif@botik.yaroslavl.su).
680 #ifdef CAN_LOAD_EGA_FONTS
682 #define colourmap 0xa0000
683 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
684 should use 0xA0000 for the bwmap as well.. */
685 #define blackwmap 0xa0000
689 vgacon_do_font_op(char *arg
, int set
, int ch512
)
694 unsigned short video_port_status
= vga_video_port_reg
+ 6;
695 int font_select
= 0x00;
697 if (vga_video_type
!= VIDEO_TYPE_EGAM
) {
698 charmap
= (char *)VGA_MAP_MEM(colourmap
);
700 #ifdef VGA_CAN_DO_64KB
701 if (vga_video_type
== VIDEO_TYPE_VGAC
)
705 charmap
= (char *)VGA_MAP_MEM(blackwmap
);
709 #ifdef BROKEN_GRAPHICS_PROGRAMS
711 * All fonts are loaded in slot 0 (0:1 for 512 ch)
715 return -EINVAL
; /* Return to default font not supported */
717 vga_font_is_default
= 0;
718 font_select
= ch512
? 0x04 : 0x00;
721 * The default font is kept in slot 0 and is never touched.
722 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
726 vga_font_is_default
= !arg
;
728 ch512
= 0; /* Default font is always 256 */
729 font_select
= arg
? (ch512
? 0x0e : 0x0a) : 0x00;
732 if ( !vga_font_is_default
)
737 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
738 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
739 outb_p( 0x02, seq_port_reg
);
740 outb_p( 0x04, seq_port_val
); /* CPU writes only to map 2 */
741 outb_p( 0x04, seq_port_reg
);
742 outb_p( 0x07, seq_port_val
); /* Sequential addressing */
743 outb_p( 0x00, seq_port_reg
);
744 outb_p( 0x03, seq_port_val
); /* Clear synchronous reset */
746 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
747 outb_p( 0x02, gr_port_val
); /* select map 2 */
748 outb_p( 0x05, gr_port_reg
);
749 outb_p( 0x00, gr_port_val
); /* disable odd-even addressing */
750 outb_p( 0x06, gr_port_reg
);
751 outb_p( 0x00, gr_port_val
); /* map start at A000:0000 */
756 for (i
=0; i
<cmapsz
; i
++)
757 vga_writeb(arg
[i
], charmap
+ i
);
759 for (i
=0; i
<cmapsz
; i
++)
760 arg
[i
] = vga_readb(charmap
+ i
);
763 * In 512-character mode, the character map is not contiguous if
764 * we want to remain EGA compatible -- which we do
771 for (i
=0; i
<cmapsz
; i
++)
772 vga_writeb(arg
[i
], charmap
+i
);
774 for (i
=0; i
<cmapsz
; i
++)
775 arg
[i
] = vga_readb(charmap
+i
);
780 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
781 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
782 outb_p( 0x02, seq_port_reg
);
783 outb_p( 0x03, seq_port_val
); /* CPU writes to maps 0 and 1 */
784 outb_p( 0x04, seq_port_reg
);
785 outb_p( 0x03, seq_port_val
); /* odd-even addressing */
787 outb_p( 0x03, seq_port_reg
); /* Character Map Select */
788 outb_p( font_select
, seq_port_val
);
790 outb_p( 0x00, seq_port_reg
);
791 outb_p( 0x03, seq_port_val
); /* clear synchronous reset */
793 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
794 outb_p( 0x00, gr_port_val
); /* select map 0 for CPU */
795 outb_p( 0x05, gr_port_reg
);
796 outb_p( 0x10, gr_port_val
); /* enable even-odd addressing */
797 outb_p( 0x06, gr_port_reg
);
798 outb_p( beg
, gr_port_val
); /* map starts at b800:0 or b000:0 */
800 /* if 512 char mode is already enabled don't re-enable it. */
801 if ((set
)&&(ch512
!=vga_512_chars
)) { /* attribute controller */
803 for(i
=0; i
<MAX_NR_CONSOLES
; i
++) {
804 struct vc_data
*c
= vc_cons
[i
].d
;
805 if (c
&& c
->vc_sw
== &vga_con
)
806 c
->vc_hi_font_mask
= ch512
? 0x0800 : 0;
809 /* 256-char: enable intensity bit
810 512-char: disable intensity bit */
811 inb_p( video_port_status
); /* clear address flip-flop */
812 outb_p ( 0x12, attrib_port
); /* color plane enable register */
813 outb_p ( ch512
? 0x07 : 0x0f, attrib_port
);
814 /* Wilton (1987) mentions the following; I don't know what
815 it means, but it works, and it appears necessary */
816 inb_p( video_port_status
);
817 outb_p ( 0x20, attrib_port
);
825 * Adjust the screen to fit a font of a certain height
828 vgacon_adjust_height(unsigned fontheight
)
831 unsigned char ovr
, vde
, fsr
;
833 if (fontheight
== vga_video_font_height
)
836 vga_video_font_height
= video_font_height
= fontheight
;
838 rows
= video_scan_lines
/fontheight
; /* Number of video rows we end up with */
839 maxscan
= rows
*fontheight
- 1; /* Scan lines to actually display-1 */
841 /* Reprogram the CRTC for the new font size
842 Note: the attempt to read the overflow register will fail
843 on an EGA, but using 0xff for the previous value appears to
844 be OK for EGA text modes in the range 257-512 scan lines, so I
845 guess we don't need to worry about it.
847 The same applies for the spill bits in the font size and cursor
848 registers; they are write-only on EGA, but it appears that they
849 are all don't care bits on EGA, so I guess it doesn't matter. */
852 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
853 ovr
= inb_p(vga_video_port_val
);
854 outb_p( 0x09, vga_video_port_reg
); /* Font size register */
855 fsr
= inb_p(vga_video_port_val
);
858 vde
= maxscan
& 0xff; /* Vertical display end reg */
859 ovr
= (ovr
& 0xbd) + /* Overflow register */
860 ((maxscan
& 0x100) >> 7) +
861 ((maxscan
& 0x200) >> 3);
862 fsr
= (fsr
& 0xe0) + (fontheight
-1); /* Font size register */
865 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
866 outb_p( ovr
, vga_video_port_val
);
867 outb_p( 0x09, vga_video_port_reg
); /* Font size */
868 outb_p( fsr
, vga_video_port_val
);
869 outb_p( 0x12, vga_video_port_reg
); /* Vertical display limit */
870 outb_p( vde
, vga_video_port_val
);
873 vc_resize_all(rows
, 0); /* Adjust console size */
877 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
881 if (vga_video_type
< VIDEO_TYPE_EGAM
)
884 if (op
->op
== KD_FONT_OP_SET
) {
885 if (op
->width
!= 8 || (op
->charcount
!= 256 && op
->charcount
!= 512))
887 rc
= vgacon_do_font_op(op
->data
, 1, op
->charcount
== 512);
888 if (!rc
&& !(op
->flags
& KD_FONT_FLAG_DONT_RECALC
))
889 rc
= vgacon_adjust_height(op
->height
);
890 } else if (op
->op
== KD_FONT_OP_GET
) {
892 op
->height
= vga_video_font_height
;
893 op
->charcount
= vga_512_chars
? 512 : 256;
894 if (!op
->data
) return 0;
895 rc
= vgacon_do_font_op(op
->data
, 0, 0);
903 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
910 static int vgacon_scrolldelta(struct vc_data
*c
, int lines
)
912 if (!lines
) /* Turn scrollback off */
913 c
->vc_visible_origin
= c
->vc_origin
;
915 int vram_size
= vga_vram_end
- vga_vram_base
;
916 int margin
= c
->vc_size_row
* 4;
919 if (vga_rolled_over
> (c
->vc_scr_end
- vga_vram_base
) + margin
) {
920 ul
= c
->vc_scr_end
- vga_vram_base
;
921 we
= vga_rolled_over
+ c
->vc_size_row
;
926 p
= (c
->vc_visible_origin
- vga_vram_base
- ul
+ we
) % we
+ lines
* c
->vc_size_row
;
927 st
= (c
->vc_origin
- vga_vram_base
- ul
+ we
) % we
;
932 c
->vc_visible_origin
= vga_vram_base
+ (p
+ ul
) % we
;
938 static int vgacon_set_origin(struct vc_data
*c
)
940 if (vga_is_gfx
|| /* We don't play origin tricks in graphic modes */
941 (console_blanked
&& !vga_palette_blanked
)) /* Nor we write to blanked screens */
943 c
->vc_origin
= c
->vc_visible_origin
= vga_vram_base
;
949 static void vgacon_save_screen(struct vc_data
*c
)
951 static int vga_bootup_console
= 0;
953 if (!vga_bootup_console
) {
954 /* This is a gross hack, but here is the only place we can
955 * set bootup console parameters without messing up generic
956 * console initialization routines.
958 vga_bootup_console
= 1;
963 scr_memcpyw_from((u16
*) c
->vc_screenbuf
, (u16
*) c
->vc_origin
, c
->vc_screenbuf_size
);
966 static int vgacon_scroll(struct vc_data
*c
, int t
, int b
, int dir
, int lines
)
971 if (t
|| b
!= c
->vc_rows
|| vga_is_gfx
)
974 if (c
->vc_origin
!= c
->vc_visible_origin
)
975 vgacon_scrolldelta(c
, 0);
977 if (!vga_hardscroll_enabled
|| lines
>= c
->vc_rows
/2)
981 delta
= lines
* c
->vc_size_row
;
983 if (c
->vc_scr_end
+ delta
>= vga_vram_end
) {
984 scr_memcpyw((u16
*)vga_vram_base
,
985 (u16
*)(oldo
+ delta
),
986 c
->vc_screenbuf_size
- delta
);
987 c
->vc_origin
= vga_vram_base
;
988 vga_rolled_over
= oldo
- vga_vram_base
;
990 c
->vc_origin
+= delta
;
991 scr_memsetw((u16
*)(c
->vc_origin
+ c
->vc_screenbuf_size
- delta
), c
->vc_video_erase_char
, delta
);
993 if (oldo
- delta
< vga_vram_base
) {
994 scr_memmovew((u16
*)(vga_vram_end
- c
->vc_screenbuf_size
+ delta
),
996 c
->vc_screenbuf_size
- delta
);
997 c
->vc_origin
= vga_vram_end
- c
->vc_screenbuf_size
;
1000 c
->vc_origin
-= delta
;
1001 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
1002 scr_memsetw((u16
*)(c
->vc_origin
), c
->vc_video_erase_char
, delta
);
1004 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
1005 c
->vc_visible_origin
= c
->vc_origin
;
1007 c
->vc_pos
= (c
->vc_pos
- oldo
) + c
->vc_origin
;
1013 * The console `switch' structure for the VGA based console
1016 static int vgacon_dummy(struct vc_data
*c
)
1021 #define DUMMY (void *) vgacon_dummy
1023 struct consw vga_con
= {
1027 DUMMY
, /* con_clear */
1028 DUMMY
, /* con_putc */
1029 DUMMY
, /* con_putcs */
1031 vgacon_scroll
, /* con_scroll */
1032 DUMMY
, /* con_bmove */
1041 vgacon_invert_region