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 static int __init
no_scroll(char *str
)
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 __setup("no-scroll", no_scroll
);
133 * By replacing the four outb_p with two back to back outw, we can reduce
134 * the window of opportunity to see text mislocated to the RHS of the
135 * console during heavy scrolling activity. However there is the remote
136 * possibility that some pre-dinosaur hardware won't like the back to back
137 * I/O. Since the Xservers get away with it, we should be able to as well.
139 static inline void write_vga(unsigned char reg
, unsigned int val
)
145 * ddprintk might set the console position from interrupt
146 * handlers, thus the write has to be IRQ-atomic.
152 v1
= reg
+ (val
& 0xff00);
153 v2
= reg
+ 1 + ((val
<< 8) & 0xff00);
154 outw(v1
, vga_video_port_reg
);
155 outw(v2
, vga_video_port_reg
);
157 outb_p(reg
, vga_video_port_reg
);
158 outb_p(val
>> 8, vga_video_port_val
);
159 outb_p(reg
+1, vga_video_port_reg
);
160 outb_p(val
& 0xff, vga_video_port_val
);
162 restore_flags(flags
);
165 static const char __init
*vgacon_startup(void)
167 const char *display_desc
= NULL
;
171 if (ORIG_VIDEO_ISVGA
== VIDEO_TYPE_VLFB
) {
173 #ifdef CONFIG_DUMMY_CONSOLE
174 conswitchp
= &dummy_con
;
175 return conswitchp
->con_startup();
182 vga_video_num_lines
= ORIG_VIDEO_LINES
;
183 vga_video_num_columns
= ORIG_VIDEO_COLS
;
185 if (ORIG_VIDEO_MODE
== 7) /* Is this a monochrome display? */
187 vga_vram_base
= 0xb0000;
188 vga_video_port_reg
= 0x3b4;
189 vga_video_port_val
= 0x3b5;
190 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
192 static struct resource ega_console_resource
= { "ega", 0x3B0, 0x3BF };
193 vga_video_type
= VIDEO_TYPE_EGAM
;
194 vga_vram_end
= 0xb8000;
195 display_desc
= "EGA+";
196 request_resource(&ioport_resource
, &ega_console_resource
);
200 static struct resource mda1_console_resource
= { "mda", 0x3B0, 0x3BB };
201 static struct resource mda2_console_resource
= { "mda", 0x3BF, 0x3BF };
202 vga_video_type
= VIDEO_TYPE_MDA
;
203 vga_vram_end
= 0xb2000;
204 display_desc
= "*MDA";
205 request_resource(&ioport_resource
, &mda1_console_resource
);
206 request_resource(&ioport_resource
, &mda2_console_resource
);
207 vga_video_font_height
= 14;
210 else /* If not, it is color. */
212 vga_can_do_color
= 1;
213 vga_vram_base
= 0xb8000;
214 vga_video_port_reg
= 0x3d4;
215 vga_video_port_val
= 0x3d5;
216 if ((ORIG_VIDEO_EGA_BX
& 0xff) != 0x10)
220 vga_vram_end
= 0xc0000;
222 if (!ORIG_VIDEO_ISVGA
) {
223 static struct resource ega_console_resource
= { "ega", 0x3C0, 0x3DF };
224 vga_video_type
= VIDEO_TYPE_EGAC
;
225 display_desc
= "EGA";
226 request_resource(&ioport_resource
, &ega_console_resource
);
228 static struct resource vga_console_resource
= { "vga+", 0x3C0, 0x3DF };
229 vga_video_type
= VIDEO_TYPE_VGAC
;
230 display_desc
= "VGA+";
231 request_resource(&ioport_resource
, &vga_console_resource
);
233 #ifdef VGA_CAN_DO_64KB
235 * get 64K rather than 32K of video RAM.
236 * This doesn't actually work on all "VGA"
237 * controllers (it seems like setting MM=01
238 * and COE=1 isn't necessarily a good idea)
240 vga_vram_base
= 0xa0000;
241 vga_vram_end
= 0xb0000;
247 * Normalise the palette registers, to point
248 * the 16 screen colours to the first 16
252 for (i
=0; i
<16; i
++) {
257 outb_p (0x20, 0x3c0) ;
259 /* now set the DAC registers back to their
262 for (i
=0; i
<16; i
++) {
263 outb_p (color_table
[i
], 0x3c8) ;
264 outb_p (default_red
[i
], 0x3c9) ;
265 outb_p (default_grn
[i
], 0x3c9) ;
266 outb_p (default_blu
[i
], 0x3c9) ;
272 static struct resource cga_console_resource
= { "cga", 0x3D4, 0x3D5 };
273 vga_video_type
= VIDEO_TYPE_CGA
;
274 vga_vram_end
= 0xba000;
275 display_desc
= "*CGA";
276 request_resource(&ioport_resource
, &cga_console_resource
);
277 vga_video_font_height
= 8;
281 vga_vram_base
= VGA_MAP_MEM(vga_vram_base
);
282 vga_vram_end
= VGA_MAP_MEM(vga_vram_end
);
285 * Find out if there is a graphics card present.
286 * Are there smarter methods around?
288 p
= (u16
*)vga_vram_base
;
289 saved1
= scr_readw(p
);
290 saved2
= scr_readw(p
+ 1);
291 scr_writew(0xAA55, p
);
292 scr_writew(0x55AA, p
+ 1);
293 if (scr_readw(p
) != 0xAA55 || scr_readw(p
+ 1) != 0x55AA) {
294 scr_writew(saved1
, p
);
295 scr_writew(saved2
, p
+ 1);
298 scr_writew(0x55AA, p
);
299 scr_writew(0xAA55, p
+ 1);
300 if (scr_readw(p
) != 0x55AA || scr_readw(p
+ 1) != 0xAA55) {
301 scr_writew(saved1
, p
);
302 scr_writew(saved2
, p
+ 1);
305 scr_writew(saved1
, p
);
306 scr_writew(saved2
, p
+ 1);
308 if (vga_video_type
== VIDEO_TYPE_EGAC
309 || vga_video_type
== VIDEO_TYPE_VGAC
310 || vga_video_type
== VIDEO_TYPE_EGAM
) {
311 vga_hardscroll_enabled
= vga_hardscroll_user_enable
;
312 vga_default_font_height
= ORIG_VIDEO_POINTS
;
313 vga_video_font_height
= ORIG_VIDEO_POINTS
;
314 /* This may be suboptimal but is a safe bet - go with it */
316 vga_video_font_height
* vga_video_num_lines
;
318 video_font_height
= vga_video_font_height
;
323 static void vgacon_init(struct vc_data
*c
, int init
)
327 /* We cannot be loaded as a module, therefore init is always 1 */
328 c
->vc_can_do_color
= vga_can_do_color
;
329 c
->vc_cols
= vga_video_num_columns
;
330 c
->vc_rows
= vga_video_num_lines
;
331 c
->vc_complement_mask
= 0x7700;
332 p
= *c
->vc_uni_pagedir_loc
;
333 if (c
->vc_uni_pagedir_loc
== &c
->vc_uni_pagedir
||
334 !--c
->vc_uni_pagedir_loc
[1])
335 con_free_unimap(c
->vc_num
);
336 c
->vc_uni_pagedir_loc
= vgacon_uni_pagedir
;
337 vgacon_uni_pagedir
[1]++;
338 if (!vgacon_uni_pagedir
[0] && p
)
339 con_set_default_unimap(c
->vc_num
);
342 static inline void vga_set_mem_top(struct vc_data
*c
)
344 write_vga(12, (c
->vc_visible_origin
-vga_vram_base
)/2);
347 static void vgacon_deinit(struct vc_data
*c
)
349 /* When closing the last console, reset video origin */
350 if (!--vgacon_uni_pagedir
[1]) {
351 c
->vc_visible_origin
= vga_vram_base
;
353 con_free_unimap(c
->vc_num
);
355 c
->vc_uni_pagedir_loc
= &c
->vc_uni_pagedir
;
356 con_set_default_unimap(c
->vc_num
);
359 static u8
vgacon_build_attr(struct vc_data
*c
, u8 color
, u8 intensity
, u8 blink
, u8 underline
, u8 reverse
)
363 if (vga_can_do_color
) {
365 attr
= (attr
& 0xf0) | c
->vc_ulcolor
;
366 else if (intensity
== 0)
367 attr
= (attr
& 0xf0) | c
->vc_halfcolor
;
370 attr
= ((attr
) & 0x88) | ((((attr
) >> 4) | ((attr
) << 4)) & 0x77);
375 if (!vga_can_do_color
) {
377 attr
= (attr
& 0xf8) | 0x01;
378 else if (intensity
== 0)
379 attr
= (attr
& 0xf0) | 0x08;
384 static void vgacon_invert_region(struct vc_data
*c
, u16
*p
, int count
)
386 int col
= vga_can_do_color
;
389 u16 a
= scr_readw(p
);
391 a
= ((a
) & 0x88ff) | (((a
) & 0x7000) >> 4) | (((a
) & 0x0700) << 4);
393 a
^= ((a
& 0x0700) == 0x0100) ? 0x7000 : 0x7700;
398 static void vgacon_set_cursor_size(int xpos
, int from
, int to
)
402 static int lastfrom
, lastto
;
404 #ifdef TRIDENT_GLITCH
405 if (xpos
<16) from
--, to
--;
408 if ((from
== lastfrom
) && (to
== lastto
)) return;
409 lastfrom
= from
; lastto
= to
;
411 save_flags(flags
); cli();
412 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
413 curs
= inb_p(vga_video_port_val
);
414 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
415 cure
= inb_p(vga_video_port_val
);
417 curs
= (curs
& 0xc0) | from
;
418 cure
= (cure
& 0xe0) | to
;
420 outb_p(0x0a, vga_video_port_reg
); /* Cursor start */
421 outb_p(curs
, vga_video_port_val
);
422 outb_p(0x0b, vga_video_port_reg
); /* Cursor end */
423 outb_p(cure
, vga_video_port_val
);
424 restore_flags(flags
);
427 static void vgacon_cursor(struct vc_data
*c
, int mode
)
429 if (c
->vc_origin
!= c
->vc_visible_origin
)
430 vgacon_scrolldelta(c
, 0);
433 write_vga(14, (vga_vram_end
- vga_vram_base
- 1)/2);
438 write_vga(14, (c
->vc_pos
-vga_vram_base
)/2);
439 switch (c
->vc_cursor_type
& 0x0f) {
441 vgacon_set_cursor_size(c
->vc_x
,
442 video_font_height
- (video_font_height
< 10 ? 2 : 3),
443 video_font_height
- (video_font_height
< 10 ? 1 : 2));
446 vgacon_set_cursor_size(c
->vc_x
,
447 video_font_height
/ 3,
448 video_font_height
- (video_font_height
< 10 ? 1 : 2));
450 case CUR_LOWER_THIRD
:
451 vgacon_set_cursor_size(c
->vc_x
,
452 (video_font_height
*2) / 3,
453 video_font_height
- (video_font_height
< 10 ? 1 : 2));
456 vgacon_set_cursor_size(c
->vc_x
,
457 video_font_height
/ 2,
458 video_font_height
- (video_font_height
< 10 ? 1 : 2));
461 vgacon_set_cursor_size(c
->vc_x
, 31, 30);
464 vgacon_set_cursor_size(c
->vc_x
, 1, video_font_height
);
471 static int vgacon_switch(struct vc_data
*c
)
474 * We need to save screen size here as it's the only way
475 * we can spot the screen has been resized and we need to
476 * set size of freshly allocated screens ourselves.
478 vga_video_num_columns
= c
->vc_cols
;
479 vga_video_num_lines
= c
->vc_rows
;
481 scr_memcpyw_to((u16
*) c
->vc_origin
, (u16
*) c
->vc_screenbuf
, c
->vc_screenbuf_size
);
482 return 0; /* Redrawing not needed */
485 static void vga_set_palette(struct vc_data
*c
, unsigned char *table
)
489 for (i
=j
=0; i
<16; i
++) {
490 outb_p (table
[i
], dac_reg
) ;
491 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
492 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
493 outb_p (c
->vc_palette
[j
++]>>2, dac_val
) ;
497 static int vgacon_set_palette(struct vc_data
*c
, unsigned char *table
)
499 #ifdef CAN_LOAD_PALETTE
500 if (vga_video_type
!= VIDEO_TYPE_VGAC
|| vga_palette_blanked
|| !CON_IS_VISIBLE(c
))
502 vga_set_palette(c
, table
);
509 /* structure holding original VGA register settings */
511 unsigned char SeqCtrlIndex
; /* Sequencer Index reg. */
512 unsigned char CrtCtrlIndex
; /* CRT-Contr. Index reg. */
513 unsigned char CrtMiscIO
; /* Miscellaneous register */
514 unsigned char HorizontalTotal
; /* CRT-Controller:00h */
515 unsigned char HorizDisplayEnd
; /* CRT-Controller:01h */
516 unsigned char StartHorizRetrace
; /* CRT-Controller:04h */
517 unsigned char EndHorizRetrace
; /* CRT-Controller:05h */
518 unsigned char Overflow
; /* CRT-Controller:07h */
519 unsigned char StartVertRetrace
; /* CRT-Controller:10h */
520 unsigned char EndVertRetrace
; /* CRT-Controller:11h */
521 unsigned char ModeControl
; /* CRT-Controller:17h */
522 unsigned char ClockingMode
; /* Seq-Controller:01h */
525 static void vga_vesa_blank(int mode
)
527 /* save original values of VGA controller registers */
528 if(!vga_vesa_blanked
) {
530 vga_state
.SeqCtrlIndex
= inb_p(seq_port_reg
);
531 vga_state
.CrtCtrlIndex
= inb_p(vga_video_port_reg
);
532 vga_state
.CrtMiscIO
= inb_p(video_misc_rd
);
535 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
536 vga_state
.HorizontalTotal
= inb_p(vga_video_port_val
);
537 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
538 vga_state
.HorizDisplayEnd
= inb_p(vga_video_port_val
);
539 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
540 vga_state
.StartHorizRetrace
= inb_p(vga_video_port_val
);
541 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
542 vga_state
.EndHorizRetrace
= inb_p(vga_video_port_val
);
543 outb_p(0x07,vga_video_port_reg
); /* Overflow */
544 vga_state
.Overflow
= inb_p(vga_video_port_val
);
545 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
546 vga_state
.StartVertRetrace
= inb_p(vga_video_port_val
);
547 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
548 vga_state
.EndVertRetrace
= inb_p(vga_video_port_val
);
549 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
550 vga_state
.ModeControl
= inb_p(vga_video_port_val
);
551 outb_p(0x01,seq_port_reg
); /* ClockingMode */
552 vga_state
.ClockingMode
= inb_p(seq_port_val
);
555 /* assure that video is enabled */
556 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
558 outb_p(0x01,seq_port_reg
);
559 outb_p(vga_state
.ClockingMode
| 0x20,seq_port_val
);
561 /* test for vertical retrace in process.... */
562 if ((vga_state
.CrtMiscIO
& 0x80) == 0x80)
563 outb_p(vga_state
.CrtMiscIO
& 0xef,video_misc_wr
);
566 * Set <End of vertical retrace> to minimum (0) and
567 * <Start of vertical Retrace> to maximum (incl. overflow)
568 * Result: turn off vertical sync (VSync) pulse.
570 if (mode
& VESA_VSYNC_SUSPEND
) {
571 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
572 outb_p(0xff,vga_video_port_val
); /* maximum value */
573 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
574 outb_p(0x40,vga_video_port_val
); /* minimum (bits 0..3) */
575 outb_p(0x07,vga_video_port_reg
); /* Overflow */
576 outb_p(vga_state
.Overflow
| 0x84,vga_video_port_val
); /* bits 9,10 of vert. retrace */
579 if (mode
& VESA_HSYNC_SUSPEND
) {
581 * Set <End of horizontal retrace> to minimum (0) and
582 * <Start of horizontal Retrace> to maximum
583 * Result: turn off horizontal sync (HSync) pulse.
585 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
586 outb_p(0xff,vga_video_port_val
); /* maximum */
587 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
588 outb_p(0x00,vga_video_port_val
); /* minimum (0) */
591 /* restore both index registers */
592 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
593 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
597 static void vga_vesa_unblank(void)
599 /* restore original values of VGA controller registers */
601 outb_p(vga_state
.CrtMiscIO
,video_misc_wr
);
603 outb_p(0x00,vga_video_port_reg
); /* HorizontalTotal */
604 outb_p(vga_state
.HorizontalTotal
,vga_video_port_val
);
605 outb_p(0x01,vga_video_port_reg
); /* HorizDisplayEnd */
606 outb_p(vga_state
.HorizDisplayEnd
,vga_video_port_val
);
607 outb_p(0x04,vga_video_port_reg
); /* StartHorizRetrace */
608 outb_p(vga_state
.StartHorizRetrace
,vga_video_port_val
);
609 outb_p(0x05,vga_video_port_reg
); /* EndHorizRetrace */
610 outb_p(vga_state
.EndHorizRetrace
,vga_video_port_val
);
611 outb_p(0x07,vga_video_port_reg
); /* Overflow */
612 outb_p(vga_state
.Overflow
,vga_video_port_val
);
613 outb_p(0x10,vga_video_port_reg
); /* StartVertRetrace */
614 outb_p(vga_state
.StartVertRetrace
,vga_video_port_val
);
615 outb_p(0x11,vga_video_port_reg
); /* EndVertRetrace */
616 outb_p(vga_state
.EndVertRetrace
,vga_video_port_val
);
617 outb_p(0x17,vga_video_port_reg
); /* ModeControl */
618 outb_p(vga_state
.ModeControl
,vga_video_port_val
);
619 outb_p(0x01,seq_port_reg
); /* ClockingMode */
620 outb_p(vga_state
.ClockingMode
,seq_port_val
);
622 /* restore index/control registers */
623 outb_p(vga_state
.SeqCtrlIndex
,seq_port_reg
);
624 outb_p(vga_state
.CrtCtrlIndex
,vga_video_port_reg
);
628 static void vga_pal_blank(void)
632 for (i
=0; i
<16; i
++) {
633 outb_p (i
, dac_reg
) ;
634 outb_p (0, dac_val
) ;
635 outb_p (0, dac_val
) ;
636 outb_p (0, dac_val
) ;
640 static int vgacon_blank(struct vc_data
*c
, int blank
)
643 case 0: /* Unblank */
644 if (vga_vesa_blanked
) {
646 vga_vesa_blanked
= 0;
648 if (vga_palette_blanked
) {
649 vga_set_palette(c
, color_table
);
650 vga_palette_blanked
= 0;
654 /* Tell console.c that it has to restore the screen itself */
656 case 1: /* Normal blanking */
657 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
659 vga_palette_blanked
= 1;
662 vgacon_set_origin(c
);
663 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
665 case -1: /* Entering graphic mode */
666 scr_memsetw((void *)vga_vram_base
, BLANK
, c
->vc_screenbuf_size
);
669 default: /* VESA blanking */
670 if (vga_video_type
== VIDEO_TYPE_VGAC
) {
671 vga_vesa_blank(blank
-1);
672 vga_vesa_blanked
= blank
;
681 * The font loading code goes back to the codepage package by
682 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
683 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
684 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
686 * Change for certain monochrome monitors by Yury Shevchuck
687 * (sizif@botik.yaroslavl.su).
690 #ifdef CAN_LOAD_EGA_FONTS
692 #define colourmap 0xa0000
693 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
694 should use 0xA0000 for the bwmap as well.. */
695 #define blackwmap 0xa0000
699 vgacon_do_font_op(char *arg
, int set
, int ch512
)
704 unsigned short video_port_status
= vga_video_port_reg
+ 6;
705 int font_select
= 0x00;
707 if (vga_video_type
!= VIDEO_TYPE_EGAM
) {
708 charmap
= (char *)VGA_MAP_MEM(colourmap
);
710 #ifdef VGA_CAN_DO_64KB
711 if (vga_video_type
== VIDEO_TYPE_VGAC
)
715 charmap
= (char *)VGA_MAP_MEM(blackwmap
);
719 #ifdef BROKEN_GRAPHICS_PROGRAMS
721 * All fonts are loaded in slot 0 (0:1 for 512 ch)
725 return -EINVAL
; /* Return to default font not supported */
727 vga_font_is_default
= 0;
728 font_select
= ch512
? 0x04 : 0x00;
731 * The default font is kept in slot 0 and is never touched.
732 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
736 vga_font_is_default
= !arg
;
738 ch512
= 0; /* Default font is always 256 */
739 font_select
= arg
? (ch512
? 0x0e : 0x0a) : 0x00;
742 if ( !vga_font_is_default
)
747 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
748 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
749 outb_p( 0x02, seq_port_reg
);
750 outb_p( 0x04, seq_port_val
); /* CPU writes only to map 2 */
751 outb_p( 0x04, seq_port_reg
);
752 outb_p( 0x07, seq_port_val
); /* Sequential addressing */
753 outb_p( 0x00, seq_port_reg
);
754 outb_p( 0x03, seq_port_val
); /* Clear synchronous reset */
756 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
757 outb_p( 0x02, gr_port_val
); /* select map 2 */
758 outb_p( 0x05, gr_port_reg
);
759 outb_p( 0x00, gr_port_val
); /* disable odd-even addressing */
760 outb_p( 0x06, gr_port_reg
);
761 outb_p( 0x00, gr_port_val
); /* map start at A000:0000 */
766 for (i
=0; i
<cmapsz
; i
++)
767 vga_writeb(arg
[i
], charmap
+ i
);
769 for (i
=0; i
<cmapsz
; i
++)
770 arg
[i
] = vga_readb(charmap
+ i
);
773 * In 512-character mode, the character map is not contiguous if
774 * we want to remain EGA compatible -- which we do
781 for (i
=0; i
<cmapsz
; i
++)
782 vga_writeb(arg
[i
], charmap
+i
);
784 for (i
=0; i
<cmapsz
; i
++)
785 arg
[i
] = vga_readb(charmap
+i
);
790 outb_p( 0x00, seq_port_reg
); /* First, the sequencer */
791 outb_p( 0x01, seq_port_val
); /* Synchronous reset */
792 outb_p( 0x02, seq_port_reg
);
793 outb_p( 0x03, seq_port_val
); /* CPU writes to maps 0 and 1 */
794 outb_p( 0x04, seq_port_reg
);
795 outb_p( 0x03, seq_port_val
); /* odd-even addressing */
797 outb_p( 0x03, seq_port_reg
); /* Character Map Select */
798 outb_p( font_select
, seq_port_val
);
800 outb_p( 0x00, seq_port_reg
);
801 outb_p( 0x03, seq_port_val
); /* clear synchronous reset */
803 outb_p( 0x04, gr_port_reg
); /* Now, the graphics controller */
804 outb_p( 0x00, gr_port_val
); /* select map 0 for CPU */
805 outb_p( 0x05, gr_port_reg
);
806 outb_p( 0x10, gr_port_val
); /* enable even-odd addressing */
807 outb_p( 0x06, gr_port_reg
);
808 outb_p( beg
, gr_port_val
); /* map starts at b800:0 or b000:0 */
810 /* if 512 char mode is already enabled don't re-enable it. */
811 if ((set
)&&(ch512
!=vga_512_chars
)) { /* attribute controller */
813 for(i
=0; i
<MAX_NR_CONSOLES
; i
++) {
814 struct vc_data
*c
= vc_cons
[i
].d
;
815 if (c
&& c
->vc_sw
== &vga_con
)
816 c
->vc_hi_font_mask
= ch512
? 0x0800 : 0;
819 /* 256-char: enable intensity bit
820 512-char: disable intensity bit */
821 inb_p( video_port_status
); /* clear address flip-flop */
822 outb_p ( 0x12, attrib_port
); /* color plane enable register */
823 outb_p ( ch512
? 0x07 : 0x0f, attrib_port
);
824 /* Wilton (1987) mentions the following; I don't know what
825 it means, but it works, and it appears necessary */
826 inb_p( video_port_status
);
827 outb_p ( 0x20, attrib_port
);
835 * Adjust the screen to fit a font of a certain height
838 vgacon_adjust_height(unsigned fontheight
)
841 unsigned char ovr
, vde
, fsr
;
843 if (fontheight
== vga_video_font_height
)
846 vga_video_font_height
= video_font_height
= fontheight
;
848 rows
= video_scan_lines
/fontheight
; /* Number of video rows we end up with */
849 maxscan
= rows
*fontheight
- 1; /* Scan lines to actually display-1 */
851 /* Reprogram the CRTC for the new font size
852 Note: the attempt to read the overflow register will fail
853 on an EGA, but using 0xff for the previous value appears to
854 be OK for EGA text modes in the range 257-512 scan lines, so I
855 guess we don't need to worry about it.
857 The same applies for the spill bits in the font size and cursor
858 registers; they are write-only on EGA, but it appears that they
859 are all don't care bits on EGA, so I guess it doesn't matter. */
862 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
863 ovr
= inb_p(vga_video_port_val
);
864 outb_p( 0x09, vga_video_port_reg
); /* Font size register */
865 fsr
= inb_p(vga_video_port_val
);
868 vde
= maxscan
& 0xff; /* Vertical display end reg */
869 ovr
= (ovr
& 0xbd) + /* Overflow register */
870 ((maxscan
& 0x100) >> 7) +
871 ((maxscan
& 0x200) >> 3);
872 fsr
= (fsr
& 0xe0) + (fontheight
-1); /* Font size register */
875 outb_p( 0x07, vga_video_port_reg
); /* CRTC overflow register */
876 outb_p( ovr
, vga_video_port_val
);
877 outb_p( 0x09, vga_video_port_reg
); /* Font size */
878 outb_p( fsr
, vga_video_port_val
);
879 outb_p( 0x12, vga_video_port_reg
); /* Vertical display limit */
880 outb_p( vde
, vga_video_port_val
);
883 vc_resize_all(rows
, 0); /* Adjust console size */
887 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
891 if (vga_video_type
< VIDEO_TYPE_EGAM
)
894 if (op
->op
== KD_FONT_OP_SET
) {
895 if (op
->width
!= 8 || (op
->charcount
!= 256 && op
->charcount
!= 512))
897 rc
= vgacon_do_font_op(op
->data
, 1, op
->charcount
== 512);
898 if (!rc
&& !(op
->flags
& KD_FONT_FLAG_DONT_RECALC
))
899 rc
= vgacon_adjust_height(op
->height
);
900 } else if (op
->op
== KD_FONT_OP_GET
) {
902 op
->height
= vga_video_font_height
;
903 op
->charcount
= vga_512_chars
? 512 : 256;
904 if (!op
->data
) return 0;
905 rc
= vgacon_do_font_op(op
->data
, 0, 0);
913 static int vgacon_font_op(struct vc_data
*c
, struct console_font_op
*op
)
920 static int vgacon_scrolldelta(struct vc_data
*c
, int lines
)
922 if (!lines
) /* Turn scrollback off */
923 c
->vc_visible_origin
= c
->vc_origin
;
925 int vram_size
= vga_vram_end
- vga_vram_base
;
926 int margin
= c
->vc_size_row
* 4;
929 if (vga_rolled_over
> (c
->vc_scr_end
- vga_vram_base
) + margin
) {
930 ul
= c
->vc_scr_end
- vga_vram_base
;
931 we
= vga_rolled_over
+ c
->vc_size_row
;
936 p
= (c
->vc_visible_origin
- vga_vram_base
- ul
+ we
) % we
+ lines
* c
->vc_size_row
;
937 st
= (c
->vc_origin
- vga_vram_base
- ul
+ we
) % we
;
942 c
->vc_visible_origin
= vga_vram_base
+ (p
+ ul
) % we
;
948 static int vgacon_set_origin(struct vc_data
*c
)
950 if (vga_is_gfx
|| /* We don't play origin tricks in graphic modes */
951 (console_blanked
&& !vga_palette_blanked
)) /* Nor we write to blanked screens */
953 c
->vc_origin
= c
->vc_visible_origin
= vga_vram_base
;
959 static void vgacon_save_screen(struct vc_data
*c
)
961 static int vga_bootup_console
= 0;
963 if (!vga_bootup_console
) {
964 /* This is a gross hack, but here is the only place we can
965 * set bootup console parameters without messing up generic
966 * console initialization routines.
968 vga_bootup_console
= 1;
973 scr_memcpyw_from((u16
*) c
->vc_screenbuf
, (u16
*) c
->vc_origin
, c
->vc_screenbuf_size
);
976 static int vgacon_scroll(struct vc_data
*c
, int t
, int b
, int dir
, int lines
)
981 if (t
|| b
!= c
->vc_rows
|| vga_is_gfx
)
984 if (c
->vc_origin
!= c
->vc_visible_origin
)
985 vgacon_scrolldelta(c
, 0);
987 if (!vga_hardscroll_enabled
|| lines
>= c
->vc_rows
/2)
991 delta
= lines
* c
->vc_size_row
;
993 if (c
->vc_scr_end
+ delta
>= vga_vram_end
) {
994 scr_memcpyw((u16
*)vga_vram_base
,
995 (u16
*)(oldo
+ delta
),
996 c
->vc_screenbuf_size
- delta
);
997 c
->vc_origin
= vga_vram_base
;
998 vga_rolled_over
= oldo
- vga_vram_base
;
1000 c
->vc_origin
+= delta
;
1001 scr_memsetw((u16
*)(c
->vc_origin
+ c
->vc_screenbuf_size
- delta
), c
->vc_video_erase_char
, delta
);
1003 if (oldo
- delta
< vga_vram_base
) {
1004 scr_memmovew((u16
*)(vga_vram_end
- c
->vc_screenbuf_size
+ delta
),
1006 c
->vc_screenbuf_size
- delta
);
1007 c
->vc_origin
= vga_vram_end
- c
->vc_screenbuf_size
;
1008 vga_rolled_over
= 0;
1010 c
->vc_origin
-= delta
;
1011 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
1012 scr_memsetw((u16
*)(c
->vc_origin
), c
->vc_video_erase_char
, delta
);
1014 c
->vc_scr_end
= c
->vc_origin
+ c
->vc_screenbuf_size
;
1015 c
->vc_visible_origin
= c
->vc_origin
;
1017 c
->vc_pos
= (c
->vc_pos
- oldo
) + c
->vc_origin
;
1023 * The console `switch' structure for the VGA based console
1026 static int vgacon_dummy(struct vc_data
*c
)
1031 #define DUMMY (void *) vgacon_dummy
1033 struct consw vga_con
= {
1037 DUMMY
, /* con_clear */
1038 DUMMY
, /* con_putc */
1039 DUMMY
, /* con_putcs */
1041 vgacon_scroll
, /* con_scroll */
1042 DUMMY
, /* con_bmove */
1051 vgacon_invert_region