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/module.h>
37 #include <linux/types.h>
39 #include <linux/kernel.h>
40 #include <linux/console.h>
41 #include <linux/string.h>
43 #include <linux/slab.h>
44 #include <linux/vt_kern.h>
45 #include <linux/sched.h>
46 #include <linux/selection.h>
47 #include <linux/spinlock.h>
48 #include <linux/ioport.h>
49 #include <linux/init.h>
50 #include <linux/screen_info.h>
51 #include <video/vga.h>
54 static DEFINE_RAW_SPINLOCK(vga_lock);
55 static int cursor_size_lastfrom;
56 static int cursor_size_lastto;
57 static u32 vgacon_xres;
58 static u32 vgacon_yres;
59 static struct vgastate vgastate;
63 #define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
64 #define CAN_LOAD_PALETTE /* undefine if the user must not do this */
66 /* You really do _NOT_ want to define this, unless you have buggy
67 * Trident VGA which will resize cursor when moving it between column
68 * 15 & 16. If you define this and your VGA is OK, inverse bug will
72 #define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */
74 * Interface used by the world
77 static const char *vgacon_startup(void);
78 static void vgacon_init(struct vc_data *c, int init);
79 static void vgacon_deinit(struct vc_data *c);
80 static void vgacon_cursor(struct vc_data *c, int mode);
81 static int vgacon_switch(struct vc_data *c);
82 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
83 static void vgacon_scrolldelta(struct vc_data *c, int lines);
84 static int vgacon_set_origin(struct vc_data *c);
85 static void vgacon_save_screen(struct vc_data *c);
86 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
88 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
89 static struct uni_pagedir *vgacon_uni_pagedir;
90 static int vgacon_refcount;
92 /* Description of the hardware situation */
93 static int vga_init_done __read_mostly;
94 static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
95 static unsigned long vga_vram_end __read_mostly; /* End of video memory */
96 static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
97 static u16 vga_video_port_reg __read_mostly; /* Video register select port */
98 static u16 vga_video_port_val __read_mostly; /* Video register value port */
99 static unsigned int vga_video_num_columns; /* Number of text columns */
100 static unsigned int vga_video_num_lines; /* Number of text lines */
101 static int vga_can_do_color __read_mostly; /* Do we support colors? */
102 static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
103 static unsigned char vga_video_type __read_mostly; /* Card type */
104 static unsigned char vga_hardscroll_enabled __read_mostly;
105 static unsigned char vga_hardscroll_user_enable __read_mostly = 1;
106 static unsigned char vga_font_is_default = 1;
107 static int vga_vesa_blanked;
108 static int vga_palette_blanked;
109 static int vga_is_gfx;
110 static int vga_512_chars;
111 static int vga_video_font_height;
112 static int vga_scan_lines __read_mostly;
113 static unsigned int vga_rolled_over;
115 static int vgacon_text_mode_force;
117 bool vgacon_text_force(void)
119 return vgacon_text_mode_force ? true : false;
121 EXPORT_SYMBOL(vgacon_text_force);
123 static int __init text_mode(char *str)
125 vgacon_text_mode_force = 1;
129 /* force text mode - used by kernel modesetting */
130 __setup("nomodeset", text_mode);
132 static int __init no_scroll(char *str)
135 * Disabling scrollback is required for the Braillex ib80-piezo
136 * Braille reader made by F.H. Papenmeier (Germany).
137 * Use the "no-scroll" bootflag.
139 vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;
143 __setup("no-scroll", no_scroll);
146 * By replacing the four outb_p with two back to back outw, we can reduce
147 * the window of opportunity to see text mislocated to the RHS of the
148 * console during heavy scrolling activity. However there is the remote
149 * possibility that some pre-dinosaur hardware won't like the back to back
150 * I/O. Since the Xservers get away with it, we should be able to as well.
152 static inline void write_vga(unsigned char reg, unsigned int val)
158 * ddprintk might set the console position from interrupt
159 * handlers, thus the write has to be IRQ-atomic.
161 raw_spin_lock_irqsave(&vga_lock, flags);
164 v1 = reg + (val & 0xff00);
165 v2 = reg + 1 + ((val << 8) & 0xff00);
166 outw(v1, vga_video_port_reg);
167 outw(v2, vga_video_port_reg);
169 outb_p(reg, vga_video_port_reg);
170 outb_p(val >> 8, vga_video_port_val);
171 outb_p(reg + 1, vga_video_port_reg);
172 outb_p(val & 0xff, vga_video_port_val);
174 raw_spin_unlock_irqrestore(&vga_lock, flags);
177 static inline void vga_set_mem_top(struct vc_data *c)
179 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
182 static void vgacon_restore_screen(struct vc_data *c)
184 if (c->vc_origin != c->vc_visible_origin)
185 vgacon_scrolldelta(c, 0);
188 static void vgacon_scrolldelta(struct vc_data *c, int lines)
190 if (!lines) /* Turn scrollback off */
191 c->vc_visible_origin = c->vc_origin;
193 int margin = c->vc_size_row * 4;
196 if (vga_rolled_over >
197 (c->vc_scr_end - vga_vram_base) + margin) {
198 ul = c->vc_scr_end - vga_vram_base;
199 we = vga_rolled_over + c->vc_size_row;
204 p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +
205 lines * c->vc_size_row;
206 st = (c->vc_origin - vga_vram_base - ul + we) % we;
213 c->vc_visible_origin = vga_vram_base + (p + ul) % we;
218 static const char *vgacon_startup(void)
220 const char *display_desc = NULL;
224 if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
225 screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
227 #ifdef CONFIG_DUMMY_CONSOLE
228 conswitchp = &dummy_con;
229 return conswitchp->con_startup();
235 /* boot_params.screen_info initialized? */
236 if ((screen_info.orig_video_mode == 0) &&
237 (screen_info.orig_video_lines == 0) &&
238 (screen_info.orig_video_cols == 0))
241 /* VGA16 modes are not handled by VGACON */
242 if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */
243 (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */
244 (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */
245 (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */
246 (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */
249 vga_video_num_lines = screen_info.orig_video_lines;
250 vga_video_num_columns = screen_info.orig_video_cols;
251 vgastate.vgabase = NULL;
253 if (screen_info.orig_video_mode == 7) {
254 /* Monochrome display */
255 vga_vram_base = 0xb0000;
256 vga_video_port_reg = VGA_CRT_IM;
257 vga_video_port_val = VGA_CRT_DM;
258 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
259 static struct resource ega_console_resource =
261 .flags = IORESOURCE_IO,
264 vga_video_type = VIDEO_TYPE_EGAM;
265 vga_vram_size = 0x8000;
266 display_desc = "EGA+";
267 request_resource(&ioport_resource,
268 &ega_console_resource);
270 static struct resource mda1_console_resource =
272 .flags = IORESOURCE_IO,
275 static struct resource mda2_console_resource =
277 .flags = IORESOURCE_IO,
280 vga_video_type = VIDEO_TYPE_MDA;
281 vga_vram_size = 0x2000;
282 display_desc = "*MDA";
283 request_resource(&ioport_resource,
284 &mda1_console_resource);
285 request_resource(&ioport_resource,
286 &mda2_console_resource);
287 vga_video_font_height = 14;
290 /* If not, it is color. */
291 vga_can_do_color = 1;
292 vga_vram_base = 0xb8000;
293 vga_video_port_reg = VGA_CRT_IC;
294 vga_video_port_val = VGA_CRT_DC;
295 if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
298 vga_vram_size = 0x8000;
300 if (!screen_info.orig_video_isVGA) {
301 static struct resource ega_console_resource =
303 .flags = IORESOURCE_IO,
306 vga_video_type = VIDEO_TYPE_EGAC;
307 display_desc = "EGA";
308 request_resource(&ioport_resource,
309 &ega_console_resource);
311 static struct resource vga_console_resource =
313 .flags = IORESOURCE_IO,
316 vga_video_type = VIDEO_TYPE_VGAC;
317 display_desc = "VGA+";
318 request_resource(&ioport_resource,
319 &vga_console_resource);
321 #ifdef VGA_CAN_DO_64KB
323 * get 64K rather than 32K of video RAM.
324 * This doesn't actually work on all "VGA"
325 * controllers (it seems like setting MM=01
326 * and COE=1 isn't necessarily a good idea)
328 vga_vram_base = 0xa0000;
329 vga_vram_size = 0x10000;
330 outb_p(6, VGA_GFX_I);
331 outb_p(6, VGA_GFX_D);
334 * Normalise the palette registers, to point
335 * the 16 screen colours to the first 16
339 for (i = 0; i < 16; i++) {
341 outb_p(i, VGA_ATT_W);
342 outb_p(i, VGA_ATT_W);
344 outb_p(0x20, VGA_ATT_W);
347 * Now set the DAC registers back to their
350 for (i = 0; i < 16; i++) {
351 outb_p(color_table[i], VGA_PEL_IW);
352 outb_p(default_red[i], VGA_PEL_D);
353 outb_p(default_grn[i], VGA_PEL_D);
354 outb_p(default_blu[i], VGA_PEL_D);
358 static struct resource cga_console_resource =
360 .flags = IORESOURCE_IO,
363 vga_video_type = VIDEO_TYPE_CGA;
364 vga_vram_size = 0x2000;
365 display_desc = "*CGA";
366 request_resource(&ioport_resource,
367 &cga_console_resource);
368 vga_video_font_height = 8;
372 vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
373 vga_vram_end = vga_vram_base + vga_vram_size;
376 * Find out if there is a graphics card present.
377 * Are there smarter methods around?
379 p = (volatile u16 *) vga_vram_base;
380 saved1 = scr_readw(p);
381 saved2 = scr_readw(p + 1);
382 scr_writew(0xAA55, p);
383 scr_writew(0x55AA, p + 1);
384 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
385 scr_writew(saved1, p);
386 scr_writew(saved2, p + 1);
389 scr_writew(0x55AA, p);
390 scr_writew(0xAA55, p + 1);
391 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
392 scr_writew(saved1, p);
393 scr_writew(saved2, p + 1);
396 scr_writew(saved1, p);
397 scr_writew(saved2, p + 1);
399 if (vga_video_type == VIDEO_TYPE_EGAC
400 || vga_video_type == VIDEO_TYPE_VGAC
401 || vga_video_type == VIDEO_TYPE_EGAM) {
402 vga_hardscroll_enabled = vga_hardscroll_user_enable;
403 vga_default_font_height = screen_info.orig_video_points;
404 vga_video_font_height = screen_info.orig_video_points;
405 /* This may be suboptimal but is a safe bet - go with it */
407 vga_video_font_height * vga_video_num_lines;
410 vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
411 vgacon_yres = vga_scan_lines;
418 static void vgacon_init(struct vc_data *c, int init)
420 struct uni_pagedir *p;
423 * We cannot be loaded as a module, therefore init will be 1
424 * if we are the default console, however if we are a fallback
425 * console, for example if fbcon has failed registration, then
426 * init will be 0, so we need to make sure our boot parameters
427 * have been copied to the console structure for vgacon_resize
428 * ultimately called by vc_resize. Any subsequent calls to
429 * vgacon_init init will have init set to 0 too.
431 c->vc_can_do_color = vga_can_do_color;
432 c->vc_scan_lines = vga_scan_lines;
433 c->vc_font.height = c->vc_cell_height = vga_video_font_height;
435 /* set dimensions manually if init != 0 since vc_resize() will fail */
437 c->vc_cols = vga_video_num_columns;
438 c->vc_rows = vga_video_num_lines;
440 vc_resize(c, vga_video_num_columns, vga_video_num_lines);
442 c->vc_complement_mask = 0x7700;
444 c->vc_hi_font_mask = 0x0800;
445 p = *c->vc_uni_pagedir_loc;
446 if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
448 c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
451 if (!vgacon_uni_pagedir && p)
452 con_set_default_unimap(c);
454 /* Only set the default if the user didn't deliberately override it */
455 if (global_cursor_default == -1)
456 global_cursor_default =
457 !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
460 static void vgacon_deinit(struct vc_data *c)
462 /* When closing the active console, reset video origin */
463 if (con_is_visible(c)) {
464 c->vc_visible_origin = vga_vram_base;
468 if (!--vgacon_refcount)
470 c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
471 con_set_default_unimap(c);
474 static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
475 u8 blink, u8 underline, u8 reverse, u8 italic)
479 if (vga_can_do_color) {
481 attr = (attr & 0xF0) | c->vc_itcolor;
483 attr = (attr & 0xf0) | c->vc_ulcolor;
484 else if (intensity == 0)
485 attr = (attr & 0xf0) | c->vc_halfcolor;
489 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
495 if (!vga_can_do_color) {
497 attr = (attr & 0xF8) | 0x02;
499 attr = (attr & 0xf8) | 0x01;
500 else if (intensity == 0)
501 attr = (attr & 0xf0) | 0x08;
506 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
508 int col = vga_can_do_color;
511 u16 a = scr_readw(p);
513 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
514 (((a) & 0x0700) << 4);
516 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
521 static void vgacon_set_cursor_size(int xpos, int from, int to)
526 #ifdef TRIDENT_GLITCH
531 if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
533 cursor_size_lastfrom = from;
534 cursor_size_lastto = to;
536 raw_spin_lock_irqsave(&vga_lock, flags);
537 if (vga_video_type >= VIDEO_TYPE_VGAC) {
538 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
539 curs = inb_p(vga_video_port_val);
540 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
541 cure = inb_p(vga_video_port_val);
547 curs = (curs & 0xc0) | from;
548 cure = (cure & 0xe0) | to;
550 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
551 outb_p(curs, vga_video_port_val);
552 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
553 outb_p(cure, vga_video_port_val);
554 raw_spin_unlock_irqrestore(&vga_lock, flags);
557 static void vgacon_cursor(struct vc_data *c, int mode)
559 if (c->vc_mode != KD_TEXT)
562 vgacon_restore_screen(c);
566 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
567 if (vga_video_type >= VIDEO_TYPE_VGAC)
568 vgacon_set_cursor_size(c->vc_x, 31, 30);
570 vgacon_set_cursor_size(c->vc_x, 31, 31);
575 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
576 switch (c->vc_cursor_type & 0x0f) {
578 vgacon_set_cursor_size(c->vc_x,
587 vgacon_set_cursor_size(c->vc_x,
588 c->vc_cell_height / 3,
593 case CUR_LOWER_THIRD:
594 vgacon_set_cursor_size(c->vc_x,
595 (c->vc_cell_height * 2) / 3,
601 vgacon_set_cursor_size(c->vc_x,
602 c->vc_cell_height / 2,
608 if (vga_video_type >= VIDEO_TYPE_VGAC)
609 vgacon_set_cursor_size(c->vc_x, 31, 30);
611 vgacon_set_cursor_size(c->vc_x, 31, 31);
614 vgacon_set_cursor_size(c->vc_x, 1,
622 static int vgacon_doresize(struct vc_data *c,
623 unsigned int width, unsigned int height)
626 unsigned int scanlines = height * c->vc_cell_height;
627 u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
629 raw_spin_lock_irqsave(&vga_lock, flags);
631 vgacon_xres = width * VGA_FONTWIDTH;
632 vgacon_yres = height * c->vc_cell_height;
633 if (vga_video_type >= VIDEO_TYPE_VGAC) {
634 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
635 max_scan = inb_p(vga_video_port_val);
640 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
641 mode = inb_p(vga_video_port_val);
647 scanlines_lo = scanlines & 0xff;
649 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
650 r7 = inb_p(vga_video_port_val) & ~0x42;
652 if (scanlines & 0x100)
654 if (scanlines & 0x200)
657 /* deprotect registers */
658 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
659 vsync_end = inb_p(vga_video_port_val);
660 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
661 outb_p(vsync_end & ~0x80, vga_video_port_val);
664 outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
665 outb_p(width - 1, vga_video_port_val);
666 outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
667 outb_p(width >> 1, vga_video_port_val);
669 if (vga_video_type >= VIDEO_TYPE_VGAC) {
670 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
671 outb_p(scanlines_lo, vga_video_port_val);
672 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
673 outb_p(r7,vga_video_port_val);
675 /* reprotect registers */
676 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
677 outb_p(vsync_end, vga_video_port_val);
680 raw_spin_unlock_irqrestore(&vga_lock, flags);
684 static int vgacon_switch(struct vc_data *c)
686 int x = c->vc_cols * VGA_FONTWIDTH;
687 int y = c->vc_rows * c->vc_cell_height;
688 int rows = screen_info.orig_video_lines * vga_default_font_height/
691 * We need to save screen size here as it's the only way
692 * we can spot the screen has been resized and we need to
693 * set size of freshly allocated screens ourselves.
695 vga_video_num_columns = c->vc_cols;
696 vga_video_num_lines = c->vc_rows;
698 /* We can only copy out the size of the video buffer here,
699 * otherwise we get into VGA BIOS */
702 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
703 c->vc_screenbuf_size > vga_vram_size ?
704 vga_vram_size : c->vc_screenbuf_size);
706 if ((vgacon_xres != x || vgacon_yres != y) &&
707 (!(vga_video_num_columns % 2) &&
708 vga_video_num_columns <= screen_info.orig_video_cols &&
709 vga_video_num_lines <= rows))
710 vgacon_doresize(c, c->vc_cols, c->vc_rows);
713 return 0; /* Redrawing not needed */
716 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
720 vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
721 for (i = j = 0; i < 16; i++) {
722 vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
723 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
724 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
725 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
729 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
731 #ifdef CAN_LOAD_PALETTE
732 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
733 || !con_is_visible(vc))
735 vga_set_palette(vc, table);
739 /* structure holding original VGA register settings */
741 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
742 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
743 unsigned char CrtMiscIO; /* Miscellaneous register */
744 unsigned char HorizontalTotal; /* CRT-Controller:00h */
745 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
746 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
747 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
748 unsigned char Overflow; /* CRT-Controller:07h */
749 unsigned char StartVertRetrace; /* CRT-Controller:10h */
750 unsigned char EndVertRetrace; /* CRT-Controller:11h */
751 unsigned char ModeControl; /* CRT-Controller:17h */
752 unsigned char ClockingMode; /* Seq-Controller:01h */
755 static void vga_vesa_blank(struct vgastate *state, int mode)
757 /* save original values of VGA controller registers */
758 if (!vga_vesa_blanked) {
759 raw_spin_lock_irq(&vga_lock);
760 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
761 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
762 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
763 raw_spin_unlock_irq(&vga_lock);
765 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
766 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
767 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
768 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
769 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
770 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
771 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
772 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
773 outb_p(0x07, vga_video_port_reg); /* Overflow */
774 vga_state.Overflow = inb_p(vga_video_port_val);
775 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
776 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
777 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
778 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
779 outb_p(0x17, vga_video_port_reg); /* ModeControl */
780 vga_state.ModeControl = inb_p(vga_video_port_val);
781 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
784 /* assure that video is enabled */
785 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
786 raw_spin_lock_irq(&vga_lock);
787 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
789 /* test for vertical retrace in process.... */
790 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
791 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
794 * Set <End of vertical retrace> to minimum (0) and
795 * <Start of vertical Retrace> to maximum (incl. overflow)
796 * Result: turn off vertical sync (VSync) pulse.
798 if (mode & VESA_VSYNC_SUSPEND) {
799 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
800 outb_p(0xff, vga_video_port_val); /* maximum value */
801 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
802 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
803 outb_p(0x07, vga_video_port_reg); /* Overflow */
804 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
807 if (mode & VESA_HSYNC_SUSPEND) {
809 * Set <End of horizontal retrace> to minimum (0) and
810 * <Start of horizontal Retrace> to maximum
811 * Result: turn off horizontal sync (HSync) pulse.
813 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
814 outb_p(0xff, vga_video_port_val); /* maximum */
815 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
816 outb_p(0x00, vga_video_port_val); /* minimum (0) */
819 /* restore both index registers */
820 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
821 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
822 raw_spin_unlock_irq(&vga_lock);
825 static void vga_vesa_unblank(struct vgastate *state)
827 /* restore original values of VGA controller registers */
828 raw_spin_lock_irq(&vga_lock);
829 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
831 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
832 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
833 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
834 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
835 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
836 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
837 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
838 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
839 outb_p(0x07, vga_video_port_reg); /* Overflow */
840 outb_p(vga_state.Overflow, vga_video_port_val);
841 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
842 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
843 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
844 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
845 outb_p(0x17, vga_video_port_reg); /* ModeControl */
846 outb_p(vga_state.ModeControl, vga_video_port_val);
848 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
850 /* restore index/control registers */
851 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
852 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
853 raw_spin_unlock_irq(&vga_lock);
856 static void vga_pal_blank(struct vgastate *state)
860 vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
861 for (i = 0; i < 16; i++) {
862 vga_w(state->vgabase, VGA_PEL_IW, i);
863 vga_w(state->vgabase, VGA_PEL_D, 0);
864 vga_w(state->vgabase, VGA_PEL_D, 0);
865 vga_w(state->vgabase, VGA_PEL_D, 0);
869 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
872 case 0: /* Unblank */
873 if (vga_vesa_blanked) {
874 vga_vesa_unblank(&vgastate);
875 vga_vesa_blanked = 0;
877 if (vga_palette_blanked) {
878 vga_set_palette(c, color_table);
879 vga_palette_blanked = 0;
883 /* Tell console.c that it has to restore the screen itself */
885 case 1: /* Normal blanking */
886 case -1: /* Obsolete */
887 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
888 vga_pal_blank(&vgastate);
889 vga_palette_blanked = 1;
892 vgacon_set_origin(c);
893 scr_memsetw((void *) vga_vram_base, BLANK,
894 c->vc_screenbuf_size);
898 default: /* VESA blanking */
899 if (vga_video_type == VIDEO_TYPE_VGAC) {
900 vga_vesa_blank(&vgastate, blank - 1);
901 vga_vesa_blanked = blank;
910 * The font loading code goes back to the codepage package by
911 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
912 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
913 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
915 * Change for certain monochrome monitors by Yury Shevchuck
916 * (sizif@botik.yaroslavl.su).
919 #ifdef CAN_LOAD_EGA_FONTS
921 #define colourmap 0xa0000
922 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
923 should use 0xA0000 for the bwmap as well.. */
924 #define blackwmap 0xa0000
927 static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
929 unsigned short video_port_status = vga_video_port_reg + 6;
930 int font_select = 0x00, beg, i;
932 bool clear_attribs = false;
933 if (vga_video_type != VIDEO_TYPE_EGAM) {
934 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
936 #ifdef VGA_CAN_DO_64KB
937 if (vga_video_type == VIDEO_TYPE_VGAC)
941 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
945 #ifdef BROKEN_GRAPHICS_PROGRAMS
947 * All fonts are loaded in slot 0 (0:1 for 512 ch)
951 return -EINVAL; /* Return to default font not supported */
953 vga_font_is_default = 0;
954 font_select = ch512 ? 0x04 : 0x00;
957 * The default font is kept in slot 0 and is never touched.
958 * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch)
962 vga_font_is_default = !arg;
964 ch512 = 0; /* Default font is always 256 */
965 font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00;
968 if (!vga_font_is_default)
969 charmap += 4 * cmapsz;
972 raw_spin_lock_irq(&vga_lock);
973 /* First, the Sequencer */
974 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
975 /* CPU writes only to map 2 */
976 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
977 /* Sequential addressing */
978 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
979 /* Clear synchronous reset */
980 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
982 /* Now, the graphics controller, select map 2 */
983 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
984 /* disable odd-even addressing */
985 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
986 /* map start at A000:0000 */
987 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
988 raw_spin_unlock_irq(&vga_lock);
992 for (i = 0; i < cmapsz; i++) {
993 vga_writeb(arg[i], charmap + i);
997 for (i = 0; i < cmapsz; i++) {
998 arg[i] = vga_readb(charmap + i);
1003 * In 512-character mode, the character map is not contiguous if
1004 * we want to remain EGA compatible -- which we do
1008 charmap += 2 * cmapsz;
1011 for (i = 0; i < cmapsz; i++) {
1012 vga_writeb(arg[i], charmap + i);
1016 for (i = 0; i < cmapsz; i++) {
1017 arg[i] = vga_readb(charmap + i);
1023 raw_spin_lock_irq(&vga_lock);
1024 /* First, the sequencer, Synchronous reset */
1025 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
1026 /* CPU writes to maps 0 and 1 */
1027 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
1028 /* odd-even addressing */
1029 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
1030 /* Character Map Select */
1032 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
1033 /* clear synchronous reset */
1034 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
1036 /* Now, the graphics controller, select map 0 for CPU */
1037 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
1038 /* enable even-odd addressing */
1039 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
1040 /* map starts at b800:0 or b000:0 */
1041 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
1043 /* if 512 char mode is already enabled don't re-enable it. */
1044 if ((set) && (ch512 != vga_512_chars)) {
1045 vga_512_chars = ch512;
1046 /* 256-char: enable intensity bit
1047 512-char: disable intensity bit */
1048 inb_p(video_port_status); /* clear address flip-flop */
1049 /* color plane enable register */
1050 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
1051 /* Wilton (1987) mentions the following; I don't know what
1052 it means, but it works, and it appears necessary */
1053 inb_p(video_port_status);
1054 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
1055 clear_attribs = true;
1057 raw_spin_unlock_irq(&vga_lock);
1059 if (clear_attribs) {
1060 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1061 struct vc_data *c = vc_cons[i].d;
1062 if (c && c->vc_sw == &vga_con) {
1063 /* force hi font mask to 0, so we always clear
1064 the bit on either transition */
1065 c->vc_hi_font_mask = 0x00;
1066 clear_buffer_attributes(c);
1067 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
1075 * Adjust the screen to fit a font of a certain height
1077 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
1079 unsigned char ovr, vde, fsr;
1080 int rows, maxscan, i;
1082 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
1083 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
1085 /* Reprogram the CRTC for the new font size
1086 Note: the attempt to read the overflow register will fail
1087 on an EGA, but using 0xff for the previous value appears to
1088 be OK for EGA text modes in the range 257-512 scan lines, so I
1089 guess we don't need to worry about it.
1091 The same applies for the spill bits in the font size and cursor
1092 registers; they are write-only on EGA, but it appears that they
1093 are all don't care bits on EGA, so I guess it doesn't matter. */
1095 raw_spin_lock_irq(&vga_lock);
1096 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
1097 ovr = inb_p(vga_video_port_val);
1098 outb_p(0x09, vga_video_port_reg); /* Font size register */
1099 fsr = inb_p(vga_video_port_val);
1100 raw_spin_unlock_irq(&vga_lock);
1102 vde = maxscan & 0xff; /* Vertical display end reg */
1103 ovr = (ovr & 0xbd) + /* Overflow register */
1104 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
1105 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
1107 raw_spin_lock_irq(&vga_lock);
1108 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
1109 outb_p(ovr, vga_video_port_val);
1110 outb_p(0x09, vga_video_port_reg); /* Font size */
1111 outb_p(fsr, vga_video_port_val);
1112 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
1113 outb_p(vde, vga_video_port_val);
1114 raw_spin_unlock_irq(&vga_lock);
1115 vga_video_font_height = fontheight;
1117 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1118 struct vc_data *c = vc_cons[i].d;
1120 if (c && c->vc_sw == &vga_con) {
1121 if (con_is_visible(c)) {
1122 /* void size to cause regs to be rewritten */
1123 cursor_size_lastfrom = 0;
1124 cursor_size_lastto = 0;
1125 c->vc_sw->con_cursor(c, CM_DRAW);
1127 c->vc_font.height = c->vc_cell_height = fontheight;
1128 vc_resize(c, 0, rows); /* Adjust console size */
1134 static int vgacon_font_set(struct vc_data *c, struct console_font *font, unsigned flags)
1136 unsigned charcount = font->charcount;
1139 if (vga_video_type < VIDEO_TYPE_EGAM)
1142 if (font->width != VGA_FONTWIDTH ||
1143 (charcount != 256 && charcount != 512))
1146 rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1150 if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1151 rc = vgacon_adjust_height(c, font->height);
1155 static int vgacon_font_get(struct vc_data *c, struct console_font *font)
1157 if (vga_video_type < VIDEO_TYPE_EGAM)
1160 font->width = VGA_FONTWIDTH;
1161 font->height = c->vc_font.height;
1162 font->charcount = vga_512_chars ? 512 : 256;
1165 return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1170 #define vgacon_font_set NULL
1171 #define vgacon_font_get NULL
1175 static int vgacon_resize(struct vc_data *c, unsigned int width,
1176 unsigned int height, unsigned int user)
1178 if ((width << 1) * height > vga_vram_size)
1183 * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
1184 * the video mode! Set the new defaults then and go away.
1186 screen_info.orig_video_cols = width;
1187 screen_info.orig_video_lines = height;
1188 vga_default_font_height = c->vc_cell_height;
1191 if (width % 2 || width > screen_info.orig_video_cols ||
1192 height > (screen_info.orig_video_lines * vga_default_font_height)/
1196 if (con_is_visible(c) && !vga_is_gfx) /* who knows */
1197 vgacon_doresize(c, width, height);
1201 static int vgacon_set_origin(struct vc_data *c)
1203 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
1204 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
1206 c->vc_origin = c->vc_visible_origin = vga_vram_base;
1208 vga_rolled_over = 0;
1212 static void vgacon_save_screen(struct vc_data *c)
1214 static int vga_bootup_console = 0;
1216 if (!vga_bootup_console) {
1217 /* This is a gross hack, but here is the only place we can
1218 * set bootup console parameters without messing up generic
1219 * console initialization routines.
1221 vga_bootup_console = 1;
1222 c->vc_x = screen_info.orig_x;
1223 c->vc_y = screen_info.orig_y;
1226 /* We can't copy in more than the size of the video buffer,
1227 * or we'll be copying in VGA BIOS */
1230 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1231 c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1234 static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
1240 if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1243 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1246 vgacon_restore_screen(c);
1247 oldo = c->vc_origin;
1248 delta = lines * c->vc_size_row;
1250 if (c->vc_scr_end + delta >= vga_vram_end) {
1251 scr_memcpyw((u16 *) vga_vram_base,
1252 (u16 *) (oldo + delta),
1253 c->vc_screenbuf_size - delta);
1254 c->vc_origin = vga_vram_base;
1255 vga_rolled_over = oldo - vga_vram_base;
1257 c->vc_origin += delta;
1258 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1259 delta), c->vc_video_erase_char,
1262 if (oldo - delta < vga_vram_base) {
1263 scr_memmovew((u16 *) (vga_vram_end -
1264 c->vc_screenbuf_size +
1265 delta), (u16 *) oldo,
1266 c->vc_screenbuf_size - delta);
1267 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1268 vga_rolled_over = 0;
1270 c->vc_origin -= delta;
1271 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1272 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1275 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1276 c->vc_visible_origin = c->vc_origin;
1278 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1284 * The console `switch' structure for the VGA based console
1287 static int vgacon_dummy(struct vc_data *c)
1292 #define DUMMY (void *) vgacon_dummy
1294 const struct consw vga_con = {
1295 .owner = THIS_MODULE,
1296 .con_startup = vgacon_startup,
1297 .con_init = vgacon_init,
1298 .con_deinit = vgacon_deinit,
1302 .con_cursor = vgacon_cursor,
1303 .con_scroll = vgacon_scroll,
1304 .con_switch = vgacon_switch,
1305 .con_blank = vgacon_blank,
1306 .con_font_set = vgacon_font_set,
1307 .con_font_get = vgacon_font_get,
1308 .con_resize = vgacon_resize,
1309 .con_set_palette = vgacon_set_palette,
1310 .con_scrolldelta = vgacon_scrolldelta,
1311 .con_set_origin = vgacon_set_origin,
1312 .con_save_screen = vgacon_save_screen,
1313 .con_build_attr = vgacon_build_attr,
1314 .con_invert_region = vgacon_invert_region,
1316 EXPORT_SYMBOL(vga_con);
1318 MODULE_LICENSE("GPL");