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@average.org>
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/module.h>
38 #include <linux/types.h>
39 #include <linux/sched.h>
41 #include <linux/kernel.h>
42 #include <linux/tty.h>
43 #include <linux/console.h>
44 #include <linux/string.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 <video/vga.h>
55 static spinlock_t vga_lock = SPIN_LOCK_UNLOCKED;
56 static struct vgastate state;
60 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
61 #define CAN_LOAD_PALETTE /* undefine if the user must not do this */
63 /* You really do _NOT_ want to define this, unless you have buggy
64 * Trident VGA which will resize cursor when moving it between column
65 * 15 & 16. If you define this and your VGA is OK, inverse bug will
71 * Interface used by the world
74 static const char *vgacon_startup(void);
75 static void vgacon_init(struct vc_data *c, int init);
76 static void vgacon_deinit(struct vc_data *c);
77 static void vgacon_cursor(struct vc_data *c, int mode);
78 static int vgacon_switch(struct vc_data *c);
79 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
80 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op);
81 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);
82 static int vgacon_scrolldelta(struct vc_data *c, int lines);
83 static int vgacon_set_origin(struct vc_data *c);
84 static void vgacon_save_screen(struct vc_data *c);
85 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
87 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
88 u8 blink, u8 underline, u8 reverse);
89 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
90 static unsigned long vgacon_uni_pagedir[2];
93 /* Description of the hardware situation */
94 static unsigned long vga_vram_base; /* Base of video memory */
95 static unsigned long vga_vram_end; /* End of video memory */
96 static u16 vga_video_port_reg; /* Video register select port */
97 static u16 vga_video_port_val; /* Video register value port */
98 static unsigned int vga_video_num_columns; /* Number of text columns */
99 static unsigned int vga_video_num_lines; /* Number of text lines */
100 static int vga_can_do_color = 0; /* Do we support colors? */
101 static unsigned int vga_default_font_height;/* Height of default screen font */
102 static unsigned char vga_video_type; /* Card type */
103 static unsigned char vga_hardscroll_enabled;
104 static unsigned char vga_hardscroll_user_enable = 1;
105 static unsigned char vga_font_is_default = 1;
106 static int vga_vesa_blanked;
107 static int vga_palette_blanked;
108 static int vga_is_gfx;
109 static int vga_512_chars;
110 static int vga_video_font_height;
111 static int vga_scan_lines;
112 static unsigned int vga_rolled_over = 0;
114 static int __init no_scroll(char *str)
117 * Disabling scrollback is required for the Braillex ib80-piezo
118 * Braille reader made by F.H. Papenmeier (Germany).
119 * Use the "no-scroll" bootflag.
121 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
125 __setup("no-scroll", no_scroll);
128 * By replacing the four outb_p with two back to back outw, we can reduce
129 * the window of opportunity to see text mislocated to the RHS of the
130 * console during heavy scrolling activity. However there is the remote
131 * possibility that some pre-dinosaur hardware won't like the back to back
132 * I/O. Since the Xservers get away with it, we should be able to as well.
134 static inline void write_vga(unsigned char reg, unsigned int val)
140 * ddprintk might set the console position from interrupt
141 * handlers, thus the write has to be IRQ-atomic.
143 spin_lock_irqsave(&vga_lock, flags);
146 v1 = reg + (val & 0xff00);
147 v2 = reg + 1 + ((val << 8) & 0xff00);
148 outw(v1, vga_video_port_reg);
149 outw(v2, vga_video_port_reg);
151 outb_p(reg, vga_video_port_reg);
152 outb_p(val >> 8, vga_video_port_val);
153 outb_p(reg + 1, vga_video_port_reg);
154 outb_p(val & 0xff, vga_video_port_val);
156 spin_unlock_irqrestore(&vga_lock, flags);
159 static const char __init *vgacon_startup(void)
161 const char *display_desc = NULL;
165 if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
167 #ifdef CONFIG_DUMMY_CONSOLE
168 conswitchp = &dummy_con;
169 return conswitchp->con_startup();
175 /* VGA16 modes are not handled by VGACON */
176 if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */
177 (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */
178 (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */
179 (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */
180 (ORIG_VIDEO_MODE == 0x6A)) /* 800x600/4, 0x6A is very common */
183 vga_video_num_lines = ORIG_VIDEO_LINES;
184 vga_video_num_columns = ORIG_VIDEO_COLS;
185 state.vgabase = NULL;
187 if (ORIG_VIDEO_MODE == 7) { /* Is this a monochrome display? */
188 vga_vram_base = 0xb0000;
189 vga_video_port_reg = VGA_CRT_IM;
190 vga_video_port_val = VGA_CRT_DM;
191 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
192 static struct resource ega_console_resource =
193 { "ega", 0x3B0, 0x3BF };
194 vga_video_type = VIDEO_TYPE_EGAM;
195 vga_vram_end = 0xb8000;
196 display_desc = "EGA+";
197 request_resource(&ioport_resource,
198 &ega_console_resource);
200 static struct resource mda1_console_resource =
201 { "mda", 0x3B0, 0x3BB };
202 static struct resource mda2_console_resource =
203 { "mda", 0x3BF, 0x3BF };
204 vga_video_type = VIDEO_TYPE_MDA;
205 vga_vram_end = 0xb2000;
206 display_desc = "*MDA";
207 request_resource(&ioport_resource,
208 &mda1_console_resource);
209 request_resource(&ioport_resource,
210 &mda2_console_resource);
211 vga_video_font_height = 14;
214 /* If not, it is color. */
215 vga_can_do_color = 1;
216 vga_vram_base = 0xb8000;
217 vga_video_port_reg = VGA_CRT_IC;
218 vga_video_port_val = VGA_CRT_DC;
219 if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
222 vga_vram_end = 0xc0000;
224 if (!ORIG_VIDEO_ISVGA) {
225 static struct resource ega_console_resource
226 = { "ega", 0x3C0, 0x3DF };
227 vga_video_type = VIDEO_TYPE_EGAC;
228 display_desc = "EGA";
229 request_resource(&ioport_resource,
230 &ega_console_resource);
232 static struct resource vga_console_resource
233 = { "vga+", 0x3C0, 0x3DF };
234 vga_video_type = VIDEO_TYPE_VGAC;
235 display_desc = "VGA+";
236 request_resource(&ioport_resource,
237 &vga_console_resource);
239 #ifdef VGA_CAN_DO_64KB
241 * get 64K rather than 32K of video RAM.
242 * This doesn't actually work on all "VGA"
243 * controllers (it seems like setting MM=01
244 * and COE=1 isn't necessarily a good idea)
246 vga_vram_base = 0xa0000;
247 vga_vram_end = 0xb0000;
248 outb_p(6, VGA_GFX_I);
249 outb_p(6, VGA_GFX_D);
252 * Normalise the palette registers, to point
253 * the 16 screen colours to the first 16
257 for (i = 0; i < 16; i++) {
259 outb_p(i, VGA_ATT_W);
260 outb_p(i, VGA_ATT_W);
262 outb_p(0x20, VGA_ATT_W);
265 * Now set the DAC registers back to their
268 for (i = 0; i < 16; i++) {
269 outb_p(color_table[i], VGA_PEL_IW);
270 outb_p(default_red[i], VGA_PEL_D);
271 outb_p(default_grn[i], VGA_PEL_D);
272 outb_p(default_blu[i], VGA_PEL_D);
276 static struct resource cga_console_resource =
277 { "cga", 0x3D4, 0x3D5 };
278 vga_video_type = VIDEO_TYPE_CGA;
279 vga_vram_end = 0xba000;
280 display_desc = "*CGA";
281 request_resource(&ioport_resource,
282 &cga_console_resource);
283 vga_video_font_height = 8;
287 vga_vram_base = VGA_MAP_MEM(vga_vram_base);
288 vga_vram_end = VGA_MAP_MEM(vga_vram_end);
291 * Find out if there is a graphics card present.
292 * Are there smarter methods around?
294 p = (volatile u16 *) vga_vram_base;
295 saved1 = scr_readw(p);
296 saved2 = scr_readw(p + 1);
297 scr_writew(0xAA55, p);
298 scr_writew(0x55AA, p + 1);
299 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
300 scr_writew(saved1, p);
301 scr_writew(saved2, p + 1);
304 scr_writew(0x55AA, p);
305 scr_writew(0xAA55, p + 1);
306 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
307 scr_writew(saved1, p);
308 scr_writew(saved2, p + 1);
311 scr_writew(saved1, p);
312 scr_writew(saved2, p + 1);
314 if (vga_video_type == VIDEO_TYPE_EGAC
315 || vga_video_type == VIDEO_TYPE_VGAC
316 || vga_video_type == VIDEO_TYPE_EGAM) {
317 vga_hardscroll_enabled = vga_hardscroll_user_enable;
318 vga_default_font_height = ORIG_VIDEO_POINTS;
319 vga_video_font_height = ORIG_VIDEO_POINTS;
320 /* This may be suboptimal but is a safe bet - go with it */
322 vga_video_font_height * vga_video_num_lines;
327 static void vgacon_init(struct vc_data *c, int init)
331 /* We cannot be loaded as a module, therefore init is always 1 */
332 c->vc_can_do_color = vga_can_do_color;
333 c->vc_cols = vga_video_num_columns;
334 c->vc_rows = vga_video_num_lines;
335 c->vc_scan_lines = vga_scan_lines;
336 c->vc_font.height = vga_video_font_height;
337 c->vc_complement_mask = 0x7700;
338 p = *c->vc_uni_pagedir_loc;
339 if (c->vc_uni_pagedir_loc == &c->vc_uni_pagedir ||
340 !--c->vc_uni_pagedir_loc[1])
341 con_free_unimap(c->vc_num);
342 c->vc_uni_pagedir_loc = vgacon_uni_pagedir;
343 vgacon_uni_pagedir[1]++;
344 if (!vgacon_uni_pagedir[0] && p)
345 con_set_default_unimap(c->vc_num);
348 static inline void vga_set_mem_top(struct vc_data *c)
350 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
353 static void vgacon_deinit(struct vc_data *c)
355 /* When closing the last console, reset video origin */
356 if (!--vgacon_uni_pagedir[1]) {
357 c->vc_visible_origin = vga_vram_base;
359 con_free_unimap(c->vc_num);
361 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
362 con_set_default_unimap(c->vc_num);
365 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
366 u8 blink, u8 underline, u8 reverse)
370 if (vga_can_do_color) {
372 attr = (attr & 0xf0) | c->vc_ulcolor;
373 else if (intensity == 0)
374 attr = (attr & 0xf0) | c->vc_halfcolor;
378 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
384 if (!vga_can_do_color) {
386 attr = (attr & 0xf8) | 0x01;
387 else if (intensity == 0)
388 attr = (attr & 0xf0) | 0x08;
393 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
395 int col = vga_can_do_color;
398 u16 a = scr_readw(p);
400 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
401 (((a) & 0x0700) << 4);
403 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
408 static void vgacon_set_cursor_size(int xpos, int from, int to)
412 static int lastfrom, lastto;
414 #ifdef TRIDENT_GLITCH
419 if ((from == lastfrom) && (to == lastto))
424 spin_lock_irqsave(&vga_lock, flags);
425 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
426 curs = inb_p(vga_video_port_val);
427 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
428 cure = inb_p(vga_video_port_val);
430 curs = (curs & 0xc0) | from;
431 cure = (cure & 0xe0) | to;
433 outb_p(0x0a, vga_video_port_reg); /* Cursor start */
434 outb_p(curs, vga_video_port_val);
435 outb_p(0x0b, vga_video_port_reg); /* Cursor end */
436 outb_p(cure, vga_video_port_val);
437 spin_unlock_irqrestore(&vga_lock, flags);
440 static void vgacon_cursor(struct vc_data *c, int mode)
442 if (c->vc_origin != c->vc_visible_origin)
443 vgacon_scrolldelta(c, 0);
446 write_vga(14, (vga_vram_end - vga_vram_base - 1) / 2);
451 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
452 switch (c->vc_cursor_type & 0x0f) {
454 vgacon_set_cursor_size(c->vc_x,
463 vgacon_set_cursor_size(c->vc_x,
464 c->vc_font.height / 3,
469 case CUR_LOWER_THIRD:
470 vgacon_set_cursor_size(c->vc_x,
471 (c->vc_font.height * 2) / 3,
477 vgacon_set_cursor_size(c->vc_x,
478 c->vc_font.height / 2,
484 vgacon_set_cursor_size(c->vc_x, 31, 30);
487 vgacon_set_cursor_size(c->vc_x, 1,
495 static int vgacon_switch(struct vc_data *c)
498 * We need to save screen size here as it's the only way
499 * we can spot the screen has been resized and we need to
500 * set size of freshly allocated screens ourselves.
502 vga_video_num_columns = c->vc_cols;
503 vga_video_num_lines = c->vc_rows;
505 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
506 c->vc_screenbuf_size);
507 return 0; /* Redrawing not needed */
510 static void vga_set_palette(struct vc_data *vc, unsigned char *table)
514 for (i = j = 0; i < 16; i++) {
515 vga_w(state.vgabase, VGA_PEL_IW, table[i]);
516 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
517 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
518 vga_w(state.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
522 static int vgacon_set_palette(struct vc_data *vc, unsigned char *table)
524 #ifdef CAN_LOAD_PALETTE
525 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
526 || !CON_IS_VISIBLE(vc))
528 vga_set_palette(vc, table);
535 /* structure holding original VGA register settings */
537 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
538 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
539 unsigned char CrtMiscIO; /* Miscellaneous register */
540 unsigned char HorizontalTotal; /* CRT-Controller:00h */
541 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
542 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
543 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
544 unsigned char Overflow; /* CRT-Controller:07h */
545 unsigned char StartVertRetrace; /* CRT-Controller:10h */
546 unsigned char EndVertRetrace; /* CRT-Controller:11h */
547 unsigned char ModeControl; /* CRT-Controller:17h */
548 unsigned char ClockingMode; /* Seq-Controller:01h */
551 static void vga_vesa_blank(struct vgastate *state, int mode)
553 /* save original values of VGA controller registers */
554 if (!vga_vesa_blanked) {
555 spin_lock_irq(&vga_lock);
556 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
557 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
558 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
559 spin_unlock_irq(&vga_lock);
561 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
562 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
563 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
564 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
565 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
566 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
567 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
568 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
569 outb_p(0x07, vga_video_port_reg); /* Overflow */
570 vga_state.Overflow = inb_p(vga_video_port_val);
571 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
572 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
573 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
574 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
575 outb_p(0x17, vga_video_port_reg); /* ModeControl */
576 vga_state.ModeControl = inb_p(vga_video_port_val);
577 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
580 /* assure that video is enabled */
581 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
582 spin_lock_irq(&vga_lock);
583 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
585 /* test for vertical retrace in process.... */
586 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
587 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
590 * Set <End of vertical retrace> to minimum (0) and
591 * <Start of vertical Retrace> to maximum (incl. overflow)
592 * Result: turn off vertical sync (VSync) pulse.
594 if (mode & VESA_VSYNC_SUSPEND) {
595 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
596 outb_p(0xff, vga_video_port_val); /* maximum value */
597 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
598 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
599 outb_p(0x07, vga_video_port_reg); /* Overflow */
600 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
603 if (mode & VESA_HSYNC_SUSPEND) {
605 * Set <End of horizontal retrace> to minimum (0) and
606 * <Start of horizontal Retrace> to maximum
607 * Result: turn off horizontal sync (HSync) pulse.
609 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
610 outb_p(0xff, vga_video_port_val); /* maximum */
611 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
612 outb_p(0x00, vga_video_port_val); /* minimum (0) */
615 /* restore both index registers */
616 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
617 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
618 spin_unlock_irq(&vga_lock);
621 static void vga_vesa_unblank(struct vgastate *state)
623 /* restore original values of VGA controller registers */
624 spin_lock_irq(&vga_lock);
625 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
627 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
628 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
629 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
630 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
631 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
632 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
633 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
634 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
635 outb_p(0x07, vga_video_port_reg); /* Overflow */
636 outb_p(vga_state.Overflow, vga_video_port_val);
637 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
638 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
639 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
640 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
641 outb_p(0x17, vga_video_port_reg); /* ModeControl */
642 outb_p(vga_state.ModeControl, vga_video_port_val);
644 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
646 /* restore index/control registers */
647 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
648 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
649 spin_unlock_irq(&vga_lock);
652 static void vga_pal_blank(struct vgastate *state)
656 for (i = 0; i < 16; i++) {
657 vga_w(state->vgabase, VGA_PEL_IW, i);
658 vga_w(state->vgabase, VGA_PEL_D, 0);
659 vga_w(state->vgabase, VGA_PEL_D, 0);
660 vga_w(state->vgabase, VGA_PEL_D, 0);
664 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
667 case 0: /* Unblank */
668 if (vga_vesa_blanked) {
669 vga_vesa_unblank(&state);
670 vga_vesa_blanked = 0;
672 if (vga_palette_blanked) {
673 vga_set_palette(c, color_table);
674 vga_palette_blanked = 0;
678 /* Tell console.c that it has to restore the screen itself */
680 case 1: /* Normal blanking */
681 case -1: /* Obsolete */
682 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
683 vga_pal_blank(&state);
684 vga_palette_blanked = 1;
687 vgacon_set_origin(c);
688 scr_memsetw((void *) vga_vram_base, BLANK,
689 c->vc_screenbuf_size);
693 default: /* VESA blanking */
694 if (vga_video_type == VIDEO_TYPE_VGAC) {
695 vga_vesa_blank(&state, blank - 1);
696 vga_vesa_blanked = blank;
705 * The font loading code goes back to the codepage package by
706 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
707 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
708 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
710 * Change for certain monochrome monitors by Yury Shevchuck
711 * (sizif@botik.yaroslavl.su).
714 #ifdef CAN_LOAD_EGA_FONTS
716 #define colourmap 0xa0000
717 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
718 should use 0xA0000 for the bwmap as well.. */
719 #define blackwmap 0xa0000
722 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
724 unsigned short video_port_status = vga_video_port_reg + 6;
725 int font_select = 0x00, beg, i;
728 if (vga_video_type != VIDEO_TYPE_EGAM) {
729 charmap = (char *) VGA_MAP_MEM(colourmap);
731 #ifdef VGA_CAN_DO_64KB
732 if (vga_video_type == VIDEO_TYPE_VGAC)
736 charmap = (char *) VGA_MAP_MEM(blackwmap);
740 #ifdef BROKEN_GRAPHICS_PROGRAMS
742 * All fonts are loaded in slot 0 (0:1 for 512 ch)
746 return -EINVAL; /* Return to default font not supported */
748 vga_font_is_default = 0;
749 font_select = ch512 ? 0x04 : 0x00;
752 * The default font is kept in slot 0 and is never touched.
753 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
757 vga_font_is_default = !arg;
759 ch512 = 0; /* Default font is always 256 */
760 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
763 if (!vga_font_is_default)
764 charmap += 4 * cmapsz;
767 spin_lock_irq(&vga_lock);
768 /* First, the Sequencer */
769 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
770 /* CPU writes only to map 2 */
771 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
772 /* Sequential addressing */
773 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
774 /* Clear synchronous reset */
775 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
777 /* Now, the graphics controller, select map 2 */
778 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
779 /* disable odd-even addressing */
780 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
781 /* map start at A000:0000 */
782 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
783 spin_unlock_irq(&vga_lock);
787 for (i = 0; i < cmapsz; i++)
788 vga_writeb(arg[i], charmap + i);
790 for (i = 0; i < cmapsz; i++)
791 arg[i] = vga_readb(charmap + i);
794 * In 512-character mode, the character map is not contiguous if
795 * we want to remain EGA compatible -- which we do
799 charmap += 2 * cmapsz;
802 for (i = 0; i < cmapsz; i++)
803 vga_writeb(arg[i], charmap + i);
805 for (i = 0; i < cmapsz; i++)
806 arg[i] = vga_readb(charmap + i);
810 spin_lock_irq(&vga_lock);
811 /* First, the sequencer, Synchronous reset */
812 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
813 /* CPU writes to maps 0 and 1 */
814 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
815 /* odd-even addressing */
816 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
817 /* Character Map Select */
819 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
820 /* clear synchronous reset */
821 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
823 /* Now, the graphics controller, select map 0 for CPU */
824 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
825 /* enable even-odd addressing */
826 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
827 /* map starts at b800:0 or b000:0 */
828 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
830 /* if 512 char mode is already enabled don't re-enable it. */
831 if ((set) && (ch512 != vga_512_chars)) {
834 /* attribute controller */
835 for (i = 0; i < MAX_NR_CONSOLES; i++) {
836 struct vc_data *c = vc_cons[i].d;
837 if (c && c->vc_sw == &vga_con)
838 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
840 vga_512_chars = ch512;
841 /* 256-char: enable intensity bit
842 512-char: disable intensity bit */
843 inb_p(video_port_status); /* clear address flip-flop */
844 /* color plane enable register */
845 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
846 /* Wilton (1987) mentions the following; I don't know what
847 it means, but it works, and it appears necessary */
848 inb_p(video_port_status);
849 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
851 spin_unlock_irq(&vga_lock);
856 * Adjust the screen to fit a font of a certain height
858 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
860 unsigned char ovr, vde, fsr;
861 int rows, maxscan, i;
863 if (fontheight == vc->vc_font.height)
866 vc->vc_font.height = fontheight;
868 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
869 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
871 /* Reprogram the CRTC for the new font size
872 Note: the attempt to read the overflow register will fail
873 on an EGA, but using 0xff for the previous value appears to
874 be OK for EGA text modes in the range 257-512 scan lines, so I
875 guess we don't need to worry about it.
877 The same applies for the spill bits in the font size and cursor
878 registers; they are write-only on EGA, but it appears that they
879 are all don't care bits on EGA, so I guess it doesn't matter. */
881 spin_lock_irq(&vga_lock);
882 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
883 ovr = inb_p(vga_video_port_val);
884 outb_p(0x09, vga_video_port_reg); /* Font size register */
885 fsr = inb_p(vga_video_port_val);
886 spin_unlock_irq(&vga_lock);
888 vde = maxscan & 0xff; /* Vertical display end reg */
889 ovr = (ovr & 0xbd) + /* Overflow register */
890 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
891 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
893 spin_lock_irq(&vga_lock);
894 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
895 outb_p(ovr, vga_video_port_val);
896 outb_p(0x09, vga_video_port_reg); /* Font size */
897 outb_p(fsr, vga_video_port_val);
898 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
899 outb_p(vde, vga_video_port_val);
900 spin_unlock_irq(&vga_lock);
902 for (i = 0; i < MAX_NR_CONSOLES; i++) {
903 struct vc_data *c = vc_cons[i].d;
905 if (c && c->vc_sw == &vga_con)
906 vc_resize(c->vc_num, 0, rows); /* Adjust console size */
911 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
915 if (vga_video_type < VIDEO_TYPE_EGAM)
918 if (op->op == KD_FONT_OP_SET) {
920 || (op->charcount != 256 && op->charcount != 512))
922 rc = vgacon_do_font_op(&state, op->data, 1, op->charcount == 512);
923 if (!rc && !(op->flags & KD_FONT_FLAG_DONT_RECALC))
924 rc = vgacon_adjust_height(c, op->height);
925 } else if (op->op == KD_FONT_OP_GET) {
927 op->height = c->vc_font.height;
928 op->charcount = vga_512_chars ? 512 : 256;
931 rc = vgacon_do_font_op(&state, op->data, 0, 0);
939 static int vgacon_font_op(struct vc_data *c, struct console_font_op *op)
946 static int vgacon_scrolldelta(struct vc_data *c, int lines)
948 if (!lines) /* Turn scrollback off */
949 c->vc_visible_origin = c->vc_origin;
951 int vram_size = vga_vram_end - vga_vram_base;
952 int margin = c->vc_size_row * 4;
955 if (vga_rolled_over >
956 (c->vc_scr_end - vga_vram_base) + margin) {
957 ul = c->vc_scr_end - vga_vram_base;
958 we = vga_rolled_over + c->vc_size_row;
963 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
964 lines * c->vc_size_row;
965 st = (c->vc_origin - vga_vram_base - ul + we) % we;
970 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
976 static int vgacon_set_origin(struct vc_data *c)
978 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
979 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
981 c->vc_origin = c->vc_visible_origin = vga_vram_base;
987 static void vgacon_save_screen(struct vc_data *c)
989 static int vga_bootup_console = 0;
991 if (!vga_bootup_console) {
992 /* This is a gross hack, but here is the only place we can
993 * set bootup console parameters without messing up generic
994 * console initialization routines.
996 vga_bootup_console = 1;
1001 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1002 c->vc_screenbuf_size);
1005 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1011 if (t || b != c->vc_rows || vga_is_gfx)
1014 if (c->vc_origin != c->vc_visible_origin)
1015 vgacon_scrolldelta(c, 0);
1017 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1020 oldo = c->vc_origin;
1021 delta = lines * c->vc_size_row;
1023 if (c->vc_scr_end + delta >= vga_vram_end) {
1024 scr_memcpyw((u16 *) vga_vram_base,
1025 (u16 *) (oldo + delta),
1026 c->vc_screenbuf_size - delta);
1027 c->vc_origin = vga_vram_base;
1028 vga_rolled_over = oldo - vga_vram_base;
1030 c->vc_origin += delta;
1031 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1032 delta), c->vc_video_erase_char,
1035 if (oldo - delta < vga_vram_base) {
1036 scr_memmovew((u16 *) (vga_vram_end -
1037 c->vc_screenbuf_size +
1038 delta), (u16 *) oldo,
1039 c->vc_screenbuf_size - delta);
1040 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1041 vga_rolled_over = 0;
1043 c->vc_origin -= delta;
1044 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1045 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1048 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1049 c->vc_visible_origin = c->vc_origin;
1051 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1057 * The console `switch' structure for the VGA based console
1060 static int vgacon_dummy(struct vc_data *c)
1065 #define DUMMY (void *) vgacon_dummy
1067 const struct consw vga_con = {
1068 .owner = THIS_MODULE,
1069 .con_startup = vgacon_startup,
1070 .con_init = vgacon_init,
1071 .con_deinit = vgacon_deinit,
1075 .con_cursor = vgacon_cursor,
1076 .con_scroll = vgacon_scroll,
1078 .con_switch = vgacon_switch,
1079 .con_blank = vgacon_blank,
1080 .con_font_op = vgacon_font_op,
1081 .con_set_palette = vgacon_set_palette,
1082 .con_scrolldelta = vgacon_scrolldelta,
1083 .con_set_origin = vgacon_set_origin,
1084 .con_save_screen = vgacon_save_screen,
1085 .con_build_attr = vgacon_build_attr,
1086 .con_invert_region = vgacon_invert_region,
1089 MODULE_LICENSE("GPL");