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
)
141 v1
= reg
+ (val
& 0xff00);
142 v2
= reg
+ 1 + ((val
<< 8) & 0xff00);
143 outw(v1
, vga_video_port_reg
);
144 outw(v2
, vga_video_port_reg
);
146 outb_p(reg
, vga_video_port_reg
);
147 outb_p(val
>> 8, vga_video_port_val
);
148 outb_p(reg
+1, vga_video_port_reg
);
149 outb_p(val
& 0xff, vga_video_port_val
);
153 __initfunc(static const char *vgacon_startup(void))
155 const char *display_desc
= NULL
;
159 if (ORIG_VIDEO_ISVGA
== VIDEO_TYPE_VLFB
) {
161 #ifdef CONFIG_DUMMY_CONSOLE
162 conswitchp
= &dummy_con
;
163 return conswitchp
->con_startup();
170 vga_video_num_lines
= ORIG_VIDEO_LINES
;
171 vga_video_num_columns
= ORIG_VIDEO_COLS
;
173 if (ORIG_VIDEO_MODE
== 7) /* Is this a monochrome display? */
175 vga_vram_base
= 0xb0000;
176 vga_video_port_reg
= 0x3b4;
177 vga_video_port_val
= 0x3b5;
178 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
180 vga_video_type
= VIDEO_TYPE_EGAM
;
181 vga_vram_end
= 0xb8000;
182 display_desc
= "EGA+";
183 request_region(0x3b0,16,"ega");
187 vga_video_type
= VIDEO_TYPE_MDA
;
188 vga_vram_end
= 0xb2000;
189 display_desc
= "*MDA";
190 request_region(0x3b0,12,"mda");
191 request_region(0x3bf, 1,"mda");
192 vga_video_font_height
= 14;
195 else /* If not, it is color. */
197 vga_can_do_color
= 1;
198 vga_vram_base
= 0xb8000;
199 vga_video_port_reg
= 0x3d4;
200 vga_video_port_val
= 0x3d5;
201 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
205 vga_vram_end
= 0xc0000;
207 if (!ORIG_VIDEO_ISVGA
) {
208 vga_video_type
= VIDEO_TYPE_EGAC
;
209 display_desc
= "EGA";
210 request_region(0x3c0,32,"ega");
212 vga_video_type
= VIDEO_TYPE_VGAC
;
213 display_desc
= "VGA+";
214 request_region(0x3c0,32,"vga+");
216 #ifdef VGA_CAN_DO_64KB
218 * get 64K rather than 32K of video RAM.
219 * This doesn't actually work on all "VGA"
220 * controllers (it seems like setting MM=01
221 * and COE=1 isn't necessarily a good idea)
223 vga_vram_base
= 0xa0000;
224 vga_vram_end
= 0xb0000;
230 * Normalise the palette registers, to point
231 * the 16 screen colours to the first 16
235 for (i
=0; i
<16; i
++) {
240 outb_p (0x20, 0x3c0) ;
242 /* now set the DAC registers back to their
245 for (i
=0; i
<16; i
++) {
246 outb_p (color_table
[i
], 0x3c8) ;
247 outb_p (default_red
[i
], 0x3c9) ;
248 outb_p (default_grn
[i
], 0x3c9) ;
249 outb_p (default_blu
[i
], 0x3c9) ;
255 vga_video_type
= VIDEO_TYPE_CGA
;
256 vga_vram_end
= 0xba000;
257 display_desc
= "*CGA";
258 request_region(0x3d4,2,"cga");
259 vga_video_font_height
= 8;
262 vga_vram_base
= VGA_MAP_MEM(vga_vram_base
);
263 vga_vram_end
= VGA_MAP_MEM(vga_vram_end
);
266 * Find out if there is a graphics card present.
267 * Are there smarter methods around?
269 p
= (u16
*)vga_vram_base
;
270 saved1
= scr_readw(p
);
271 saved2
= scr_readw(p
+ 1);
272 scr_writew(0xAA55, p
);
273 scr_writew(0x55AA, p
+ 1);
274 if (scr_readw(p
) != 0xAA55 || scr_readw(p
+ 1) != 0x55AA) {
275 scr_writew(saved1
, p
);
276 scr_writew(saved2
, p
+ 1);
279 scr_writew(0x55AA, p
);
280 scr_writew(0xAA55, p
+ 1);
281 if (scr_readw(p
) != 0x55AA || scr_readw(p
+ 1) != 0xAA55) {
282 scr_writew(saved1
, p
);
283 scr_writew(saved2
, p
+ 1);
286 scr_writew(saved1
, p
);
287 scr_writew(saved2
, p
+ 1);
289 if (vga_video_type
== VIDEO_TYPE_EGAC
290 || vga_video_type
== VIDEO_TYPE_VGAC
291 || vga_video_type
== VIDEO_TYPE_EGAM
) {
292 vga_hardscroll_enabled
= vga_hardscroll_user_enable
;
293 vga_default_font_height
= ORIG_VIDEO_POINTS
;
294 vga_video_font_height
= ORIG_VIDEO_POINTS
;
295 /* This may be suboptimal but is a safe bet - go with it */
297 vga_video_font_height
* vga_video_num_lines
;
299 video_font_height
= vga_video_font_height
;
304 static void vgacon_init(struct vc_data
*c
, int init
)
308 /* We cannot be loaded as a module, therefore init is always 1 */
309 c
->vc_can_do_color
= vga_can_do_color
;
310 c
->vc_cols
= vga_video_num_columns
;
311 c
->vc_rows
= vga_video_num_lines
;
312 c
->vc_complement_mask
= 0x7700;
313 p
= *c
->vc_uni_pagedir_loc
;
314 if (c
->vc_uni_pagedir_loc
== &c
->vc_uni_pagedir
||
315 !--c
->vc_uni_pagedir_loc
[1])
316 con_free_unimap(c
->vc_num
);
317 c
->vc_uni_pagedir_loc
= vgacon_uni_pagedir
;
318 vgacon_uni_pagedir
[1]++;
319 if (!vgacon_uni_pagedir
[0] && p
)
320 con_set_default_unimap(c
->vc_num
);
323 static inline void vga_set_mem_top(struct vc_data
*c
)
325 write_vga(12, (c
->vc_visible_origin
-vga_vram_base
)/2);
328 static void vgacon_deinit(struct vc_data
*c
)
330 /* When closing the last console, reset video origin */
331 if (!--vgacon_uni_pagedir
[1]) {
332 c
->vc_visible_origin
= vga_vram_base
;
334 con_free_unimap(c
->vc_num
);
336 c
->vc_uni_pagedir_loc
= &c
->vc_uni_pagedir
;
337 con_set_default_unimap(c
->vc_num
);
340 static u8
vgacon_build_attr(struct vc_data
*c
, u8 color
, u8 intensity
, u8 blink
, u8 underline
, u8 reverse
)
344 if (vga_can_do_color
) {
346 attr
= (attr
& 0xf0) | c
->vc_ulcolor
;
347 else if (intensity
== 0)
348 attr
= (attr
& 0xf0) | c
->vc_halfcolor
;
351 attr
= ((attr
) & 0x88) | ((((attr
) >> 4) | ((attr
) << 4)) & 0x77);
356 if (!vga_can_do_color
) {
358 attr
= (attr
& 0xf8) | 0x01;
359 else if (intensity
== 0)
360 attr
= (attr
& 0xf0) | 0x08;
365 static void vgacon_invert_region(struct vc_data
*c
, u16
*p
, int count
)
367 int col
= vga_can_do_color
;
370 u16 a
= scr_readw(p
);
372 a
= ((a
) & 0x88ff) | (((a
) & 0x7000) >> 4) | (((a
) & 0x0700) << 4);
374 a
^= ((a
& 0x0700) == 0x0100) ? 0x7000 : 0x7700;
379 static void vgacon_set_cursor_size(int xpos
, int from
, int to
)
383 static int lastfrom
, lastto
;
385 #ifdef TRIDENT_GLITCH
386 if (xpos
<16) from
--, to
--;
389 if ((from
== lastfrom
) && (to
== lastto
)) return;
390 lastfrom
= from
; lastto
= to
;
392 save_flags(flags
); cli();
393 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
394 curs
= inb_p(vga_video_port_val
);
395 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
396 cure
= inb_p(vga_video_port_val
);
398 curs
= (curs
& 0xc0) | from
;
399 cure
= (cure
& 0xe0) | to
;
401 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
402 outb_p(curs
, vga_video_port_val
);
403 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
404 outb_p(cure
, vga_video_port_val
);
405 restore_flags(flags
);
408 static void vgacon_cursor(struct vc_data
*c
, int mode
)
410 if (c
->vc_origin
!= c
->vc_visible_origin
)
411 vgacon_scrolldelta(c
, 0);
414 write_vga(14, (vga_vram_end
- vga_vram_base
- 1)/2);
419 write_vga(14, (c
->vc_pos
-vga_vram_base
)/2);
420 switch (c
->vc_cursor_type
& 0x0f) {
422 vgacon_set_cursor_size(c
->vc_x
,
423 video_font_height
- (video_font_height
< 10 ? 2 : 3),
424 video_font_height
- (video_font_height
< 10 ? 1 : 2));
427 vgacon_set_cursor_size(c
->vc_x
,
428 video_font_height
/ 3,
429 video_font_height
- (video_font_height
< 10 ? 1 : 2));
431 case CUR_LOWER_THIRD
:
432 vgacon_set_cursor_size(c
->vc_x
,
433 (video_font_height
*2) / 3,
434 video_font_height
- (video_font_height
< 10 ? 1 : 2));
437 vgacon_set_cursor_size(c
->vc_x
,
438 video_font_height
/ 2,
439 video_font_height
- (video_font_height
< 10 ? 1 : 2));
442 vgacon_set_cursor_size(c
->vc_x
, 31, 30);
445 vgacon_set_cursor_size(c
->vc_x
, 1, video_font_height
);
452 static int vgacon_switch(struct vc_data
*c
)
455 * We need to save screen size here as it's the only way
456 * we can spot the screen has been resized and we need to
457 * set size of freshly allocated screens ourselves.
459 vga_video_num_columns
= c
->vc_cols
;
460 vga_video_num_lines
= c
->vc_rows
;
462 scr_memcpyw_to((u16
*) c
->vc_origin
, (u16
*) c
->vc_screenbuf
, c
->vc_screenbuf_size
);
463 return 0; /* Redrawing not needed */
466 static void vga_set_palette(struct vc_data
*c
, unsigned char *table
)
470 for (i
=j
=0; i
<16; i
++) {
471 outb_p (table
[i
], dac_reg
) ;
472 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
473 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
474 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
478 static int vgacon_set_palette(struct vc_data
*c
, unsigned char *table
)
480 #ifdef CAN_LOAD_PALETTE
481 if (vga_video_type
!= VIDEO_TYPE_VGAC
|| vga_palette_blanked
|| !CON_IS_VISIBLE(c
))
483 vga_set_palette(c
, table
);
490 /* structure holding original VGA register settings */
492 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
493 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
494 unsigned char CrtMiscIO
; /* Miscellaneous register */
495 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
496 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
497 unsigned char StartHorizRetrace
; /* CRT-Controller:04h */
498 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
499 unsigned char Overflow
; /* CRT-Controller:07h */
500 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
501 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
502 unsigned char ModeControl
; /* CRT-Controller:17h */
503 unsigned char ClockingMode
; /* Seq-Controller:01h */
506 static void vga_vesa_blank(int mode
)
508 /* save original values of VGA controller registers */
509 if(!vga_vesa_blanked
) {
511 vga_state
.SeqCtrlIndex
= inb_p(seq_port_reg
);
512 vga_state
.CrtCtrlIndex
= inb_p(vga_video_port_reg
);
513 vga_state
.CrtMiscIO
= inb_p(video_misc_rd
);
516 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
517 vga_state
.HorizontalTotal
= inb_p(vga_video_port_val
);
518 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
519 vga_state
.HorizDisplayEnd
= inb_p(vga_video_port_val
);
520 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
521 vga_state
.StartHorizRetrace
= inb_p(vga_video_port_val
);
522 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
523 vga_state
.EndHorizRetrace
= inb_p(vga_video_port_val
);
524 outb_p(0x07,vga_video_port_reg
); /* Overflow */
525 vga_state
.Overflow
= inb_p(vga_video_port_val
);
526 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
527 vga_state
.StartVertRetrace
= inb_p(vga_video_port_val
);
528 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
529 vga_state
.EndVertRetrace
= inb_p(vga_video_port_val
);
530 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
531 vga_state
.ModeControl
= inb_p(vga_video_port_val
);
532 outb_p(0x01,seq_port_reg
); /* ClockingMode */
533 vga_state
.ClockingMode
= inb_p(seq_port_val
);
536 /* assure that video is enabled */
537 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
539 outb_p(0x01,seq_port_reg
);
540 outb_p(vga_state
.ClockingMode
| 0x20,seq_port_val
);
542 /* test for vertical retrace in process.... */
543 if ((vga_state
.CrtMiscIO
& 0x80) == 0x80)
544 outb_p(vga_state
.CrtMiscIO
& 0xef,video_misc_wr
);
547 * Set <End of vertical retrace> to minimum (0) and
548 * <Start of vertical Retrace> to maximum (incl. overflow)
549 * Result: turn off vertical sync (VSync) pulse.
551 if (mode
& VESA_VSYNC_SUSPEND
) {
552 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
553 outb_p(0xff,vga_video_port_val
); /* maximum value */
554 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
555 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
556 outb_p(0x07,vga_video_port_reg
); /* Overflow */
557 outb_p(vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
560 if (mode
& VESA_HSYNC_SUSPEND
) {
562 * Set <End of horizontal retrace> to minimum (0) and
563 * <Start of horizontal Retrace> to maximum
564 * Result: turn off horizontal sync (HSync) pulse.
566 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
567 outb_p(0xff,vga_video_port_val
); /* maximum */
568 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
569 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
572 /* restore both index registers */
573 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
574 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
578 static void vga_vesa_unblank(void)
580 /* restore original values of VGA controller registers */
582 outb_p(vga_state
.CrtMiscIO
,video_misc_wr
);
584 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
585 outb_p(vga_state
.HorizontalTotal
,vga_video_port_val
);
586 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
587 outb_p(vga_state
.HorizDisplayEnd
,vga_video_port_val
);
588 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
589 outb_p(vga_state
.StartHorizRetrace
,vga_video_port_val
);
590 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
591 outb_p(vga_state
.EndHorizRetrace
,vga_video_port_val
);
592 outb_p(0x07,vga_video_port_reg
); /* Overflow */
593 outb_p(vga_state
.Overflow
,vga_video_port_val
);
594 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
595 outb_p(vga_state
.StartVertRetrace
,vga_video_port_val
);
596 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
597 outb_p(vga_state
.EndVertRetrace
,vga_video_port_val
);
598 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
599 outb_p(vga_state
.ModeControl
,vga_video_port_val
);
600 outb_p(0x01,seq_port_reg
); /* ClockingMode */
601 outb_p(vga_state
.ClockingMode
,seq_port_val
);
603 /* restore index/control registers */
604 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
605 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
609 static void vga_pal_blank(void)
613 for (i
=0; i
<16; i
++) {
614 outb_p (i
, dac_reg
) ;
615 outb_p (0, dac_val
) ;
616 outb_p (0, dac_val
) ;
617 outb_p (0, dac_val
) ;
621 static int vgacon_blank(struct vc_data
*c
, int blank
)
624 case 0: /* Unblank */
625 if (vga_vesa_blanked
) {
627 vga_vesa_blanked
= 0;
629 if (vga_palette_blanked
) {
630 vga_set_palette(c
, color_table
);
631 vga_palette_blanked
= 0;
635 /* Tell console.c that it has to restore the screen itself */
637 case 1: /* Normal blanking */
638 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
640 vga_palette_blanked
= 1;
643 vgacon_set_origin(c
);
644 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
646 case -1: /* Entering graphic mode */
647 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
650 default: /* VESA blanking */
651 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
652 vga_vesa_blank(blank
-1);
653 vga_vesa_blanked
= blank
;
662 * The font loading code goes back to the codepage package by
663 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
664 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
665 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
667 * Change for certain monochrome monitors by Yury Shevchuck
668 * (sizif@botik.yaroslavl.su).
671 #ifdef CAN_LOAD_EGA_FONTS
673 #define colourmap 0xa0000
674 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
675 should use 0xA0000 for the bwmap as well.. */
676 #define blackwmap 0xa0000
680 vgacon_do_font_op(char *arg
, int set
, int ch512
)
685 unsigned short video_port_status
= vga_video_port_reg
+ 6;
686 int font_select
= 0x00;
688 if (vga_video_type
!= VIDEO_TYPE_EGAM
) {
689 charmap
= (char *)VGA_MAP_MEM(colourmap
);
691 #ifdef VGA_CAN_DO_64KB
692 if (vga_video_type
== VIDEO_TYPE_VGAC
)
696 charmap
= (char *)VGA_MAP_MEM(blackwmap
);
700 #ifdef BROKEN_GRAPHICS_PROGRAMS
702 * All fonts are loaded in slot 0 (0:1 for 512 ch)
706 return -EINVAL
; /* Return to default font not supported */
708 vga_font_is_default
= 0;
709 font_select
= ch512
? 0x04 : 0x00;
712 * The default font is kept in slot 0 and is never touched.
713 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
717 vga_font_is_default
= !arg
;
719 ch512
= 0; /* Default font is always 256 */
720 font_select
= arg
? (ch512
? 0x0e : 0x0a) : 0x00;
723 if ( !vga_font_is_default
)
728 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
729 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
730 outb_p( 0x02, seq_port_reg
);
731 outb_p( 0x04, seq_port_val
); /* CPU writes only to map 2 */
732 outb_p( 0x04, seq_port_reg
);
733 outb_p( 0x07, seq_port_val
); /* Sequential addressing */
734 outb_p( 0x00, seq_port_reg
);
735 outb_p( 0x03, seq_port_val
); /* Clear synchronous reset */
737 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
738 outb_p( 0x02, gr_port_val
); /* select map 2 */
739 outb_p( 0x05, gr_port_reg
);
740 outb_p( 0x00, gr_port_val
); /* disable odd-even addressing */
741 outb_p( 0x06, gr_port_reg
);
742 outb_p( 0x00, gr_port_val
); /* map start at A000:0000 */
747 for (i
=0; i
<cmapsz
; i
++)
748 vga_writeb(arg
[i
], charmap
+ i
);
750 for (i
=0; i
<cmapsz
; i
++)
751 arg
[i
] = vga_readb(charmap
+ i
);
754 * In 512-character mode, the character map is not contiguous if
755 * we want to remain EGA compatible -- which we do
762 for (i
=0; i
<cmapsz
; i
++)
763 vga_writeb(arg
[i
], charmap
+i
);
765 for (i
=0; i
<cmapsz
; i
++)
766 arg
[i
] = vga_readb(charmap
+i
);
771 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
772 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
773 outb_p( 0x02, seq_port_reg
);
774 outb_p( 0x03, seq_port_val
); /* CPU writes to maps 0 and 1 */
775 outb_p( 0x04, seq_port_reg
);
776 outb_p( 0x03, seq_port_val
); /* odd-even addressing */
778 outb_p( 0x03, seq_port_reg
); /* Character Map Select */
779 outb_p( font_select
, seq_port_val
);
781 outb_p( 0x00, seq_port_reg
);
782 outb_p( 0x03, seq_port_val
); /* clear synchronous reset */
784 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
785 outb_p( 0x00, gr_port_val
); /* select map 0 for CPU */
786 outb_p( 0x05, gr_port_reg
);
787 outb_p( 0x10, gr_port_val
); /* enable even-odd addressing */
788 outb_p( 0x06, gr_port_reg
);
789 outb_p( beg
, gr_port_val
); /* map starts at b800:0 or b000:0 */
791 /* if 512 char mode is already enabled don't re-enable it. */
792 if ((set
)&&(ch512
!=vga_512_chars
)) { /* attribute controller */
794 for(i
=0; i
<MAX_NR_CONSOLES
; i
++) {
795 struct vc_data
*c
= vc_cons
[i
].d
;
796 if (c
&& c
->vc_sw
== &vga_con
)
797 c
->vc_hi_font_mask
= ch512
? 0x0800 : 0;
800 /* 256-char: enable intensity bit
801 512-char: disable intensity bit */
802 inb_p( video_port_status
); /* clear address flip-flop */
803 outb_p ( 0x12, attrib_port
); /* color plane enable register */
804 outb_p ( ch512
? 0x07 : 0x0f, attrib_port
);
805 /* Wilton (1987) mentions the following; I don't know what
806 it means, but it works, and it appears necessary */
807 inb_p( video_port_status
);
808 outb_p ( 0x20, attrib_port
);
816 * Adjust the screen to fit a font of a certain height
819 vgacon_adjust_height(unsigned fontheight
)
822 unsigned char ovr
, vde
, fsr
;
824 if (fontheight
== vga_video_font_height
)
827 vga_video_font_height
= video_font_height
= fontheight
;
829 rows
= video_scan_lines
/fontheight
; /* Number of video rows we end up with */
830 maxscan
= rows
*fontheight
- 1; /* Scan lines to actually display-1 */
832 /* Reprogram the CRTC for the new font size
833 Note: the attempt to read the overflow register will fail
834 on an EGA, but using 0xff for the previous value appears to
835 be OK for EGA text modes in the range 257-512 scan lines, so I
836 guess we don't need to worry about it.
838 The same applies for the spill bits in the font size and cursor
839 registers; they are write-only on EGA, but it appears that they
840 are all don't care bits on EGA, so I guess it doesn't matter. */
843 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
844 ovr
= inb_p(vga_video_port_val
);
845 outb_p( 0x09, vga_video_port_reg
); /* Font size register */
846 fsr
= inb_p(vga_video_port_val
);
849 vde
= maxscan
& 0xff; /* Vertical display end reg */
850 ovr
= (ovr
& 0xbd) + /* Overflow register */
851 ((maxscan
& 0x100) >> 7) +
852 ((maxscan
& 0x200) >> 3);
853 fsr
= (fsr
& 0xe0) + (fontheight
-1); /* Font size register */
856 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
857 outb_p( ovr
, vga_video_port_val
);
858 outb_p( 0x09, vga_video_port_reg
); /* Font size */
859 outb_p( fsr
, vga_video_port_val
);
860 outb_p( 0x12, vga_video_port_reg
); /* Vertical display limit */
861 outb_p( vde
, vga_video_port_val
);
864 vc_resize_all(rows
, 0); /* Adjust console size */
868 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
872 if (vga_video_type
< VIDEO_TYPE_EGAM
)
875 if (op
->op
== KD_FONT_OP_SET
) {
876 if (op
->width
!= 8 || (op
->charcount
!= 256 && op
->charcount
!= 512))
878 rc
= vgacon_do_font_op(op
->data
, 1, op
->charcount
== 512);
879 if (!rc
&& !(op
->flags
& KD_FONT_FLAG_DONT_RECALC
))
880 rc
= vgacon_adjust_height(op
->height
);
881 } else if (op
->op
== KD_FONT_OP_GET
) {
883 op
->height
= vga_video_font_height
;
884 op
->charcount
= vga_512_chars
? 512 : 256;
885 if (!op
->data
) return 0;
886 rc
= vgacon_do_font_op(op
->data
, 0, 0);
894 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
901 static int vgacon_scrolldelta(struct vc_data
*c
, int lines
)
903 if (!lines
) /* Turn scrollback off */
904 c
->vc_visible_origin
= c
->vc_origin
;
906 int vram_size
= vga_vram_end
- vga_vram_base
;
907 int margin
= c
->vc_size_row
* 4;
910 if (vga_rolled_over
> (c
->vc_scr_end
- vga_vram_base
) + margin
) {
911 ul
= c
->vc_scr_end
- vga_vram_base
;
912 we
= vga_rolled_over
+ c
->vc_size_row
;
917 p
= (c
->vc_visible_origin
- vga_vram_base
- ul
+ we
) % we
+ lines
* c
->vc_size_row
;
918 st
= (c
->vc_origin
- vga_vram_base
- ul
+ we
) % we
;
923 c
->vc_visible_origin
= vga_vram_base
+ (p
+ ul
) % we
;
929 static int vgacon_set_origin(struct vc_data
*c
)
931 if (vga_is_gfx
|| /* We don't play origin tricks in graphic modes */
932 (console_blanked
&& !vga_palette_blanked
)) /* Nor we write to blanked screens */
934 c
->vc_origin
= c
->vc_visible_origin
= vga_vram_base
;
940 static void vgacon_save_screen(struct vc_data
*c
)
942 static int vga_bootup_console
= 0;
944 if (!vga_bootup_console
) {
945 /* This is a gross hack, but here is the only place we can
946 * set bootup console parameters without messing up generic
947 * console initialization routines.
949 vga_bootup_console
= 1;
954 scr_memcpyw_from((u16
*) c
->vc_screenbuf
, (u16
*) c
->vc_origin
, c
->vc_screenbuf_size
);
957 static int vgacon_scroll(struct vc_data
*c
, int t
, int b
, int dir
, int lines
)
962 if (t
|| b
!= c
->vc_rows
|| vga_is_gfx
)
965 if (c
->vc_origin
!= c
->vc_visible_origin
)
966 vgacon_scrolldelta(c
, 0);
968 if (!vga_hardscroll_enabled
|| lines
>= c
->vc_rows
/2)
972 delta
= lines
* c
->vc_size_row
;
974 if (c
->vc_scr_end
+ delta
>= vga_vram_end
) {
975 scr_memcpyw((u16
*)vga_vram_base
,
976 (u16
*)(oldo
+ delta
),
977 c
->vc_screenbuf_size
- delta
);
978 c
->vc_origin
= vga_vram_base
;
979 vga_rolled_over
= oldo
- vga_vram_base
;
981 c
->vc_origin
+= delta
;
982 scr_memsetw((u16
*)(c
->vc_origin
+ c
->vc_screenbuf_size
- delta
), c
->vc_video_erase_char
, delta
);
984 if (oldo
- delta
< vga_vram_base
) {
985 scr_memmovew((u16
*)(vga_vram_end
- c
->vc_screenbuf_size
+ delta
),
987 c
->vc_screenbuf_size
- delta
);
988 c
->vc_origin
= vga_vram_end
- c
->vc_screenbuf_size
;
991 c
->vc_origin
-= delta
;
992 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
993 scr_memsetw((u16
*)(c
->vc_origin
), c
->vc_video_erase_char
, delta
);
995 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
996 c
->vc_visible_origin
= c
->vc_origin
;
998 c
->vc_pos
= (c
->vc_pos
- oldo
) + c
->vc_origin
;
1004 * The console `switch' structure for the VGA based console
1007 static int vgacon_dummy(struct vc_data
*c
)
1012 #define DUMMY (void *) vgacon_dummy
1014 struct consw vga_con
= {
1018 DUMMY
, /* con_clear */
1019 DUMMY
, /* con_putc */
1020 DUMMY
, /* con_putcs */
1022 vgacon_scroll
, /* con_scroll */
1023 DUMMY
, /* con_bmove */
1032 vgacon_invert_region