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 VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */
65 * Interface used by the world
68 static int vgacon_set_origin(struct vc_data *c);
70 static struct uni_pagedict *vgacon_uni_pagedir;
71 static int vgacon_refcount;
73 /* Description of the hardware situation */
74 static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
75 static unsigned long vga_vram_end __read_mostly; /* End of video memory */
76 static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
77 static u16 vga_video_port_reg __read_mostly; /* Video register select port */
78 static u16 vga_video_port_val __read_mostly; /* Video register value port */
79 static unsigned int vga_video_num_columns; /* Number of text columns */
80 static unsigned int vga_video_num_lines; /* Number of text lines */
81 static bool vga_can_do_color; /* Do we support colors? */
82 static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
83 static unsigned char vga_video_type __read_mostly; /* Card type */
84 static int vga_vesa_blanked;
85 static bool vga_palette_blanked;
86 static bool vga_is_gfx;
87 static bool vga_512_chars;
88 static int vga_video_font_height;
89 static int vga_scan_lines __read_mostly;
90 static unsigned int vga_rolled_over; /* last vc_origin offset before wrap */
92 static struct screen_info *vga_si;
94 static bool vga_hardscroll_enabled;
95 static bool vga_hardscroll_user_enable = true;
97 static int __init no_scroll(char *str)
100 * Disabling scrollback is required for the Braillex ib80-piezo
101 * Braille reader made by F.H. Papenmeier (Germany).
102 * Use the "no-scroll" bootflag.
104 vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
108 __setup("no-scroll", no_scroll);
111 * By replacing the four outb_p with two back to back outw, we can reduce
112 * the window of opportunity to see text mislocated to the RHS of the
113 * console during heavy scrolling activity. However there is the remote
114 * possibility that some pre-dinosaur hardware won't like the back to back
115 * I/O. Since the Xservers get away with it, we should be able to as well.
117 static inline void write_vga(unsigned char reg, unsigned int val)
123 * ddprintk might set the console position from interrupt
124 * handlers, thus the write has to be IRQ-atomic.
126 raw_spin_lock_irqsave(&vga_lock, flags);
127 v1 = reg + (val & 0xff00);
128 v2 = reg + 1 + ((val << 8) & 0xff00);
129 outw(v1, vga_video_port_reg);
130 outw(v2, vga_video_port_reg);
131 raw_spin_unlock_irqrestore(&vga_lock, flags);
134 static inline void vga_set_mem_top(struct vc_data *c)
136 write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
139 static void vgacon_scrolldelta(struct vc_data *c, int lines)
141 vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
146 static void vgacon_restore_screen(struct vc_data *c)
148 if (c->vc_origin != c->vc_visible_origin)
149 vgacon_scrolldelta(c, 0);
152 static const char *vgacon_startup(void)
154 const char *display_desc = NULL;
159 vga_si->orig_video_isVGA == VIDEO_TYPE_VLFB ||
160 vga_si->orig_video_isVGA == VIDEO_TYPE_EFI) {
162 #ifdef CONFIG_DUMMY_CONSOLE
163 conswitchp = &dummy_con;
164 return conswitchp->con_startup();
170 /* vga_si reasonably initialized? */
171 if ((vga_si->orig_video_lines == 0) ||
172 (vga_si->orig_video_cols == 0))
175 /* VGA16 modes are not handled by VGACON */
176 if ((vga_si->orig_video_mode == 0x0D) || /* 320x200/4 */
177 (vga_si->orig_video_mode == 0x0E) || /* 640x200/4 */
178 (vga_si->orig_video_mode == 0x10) || /* 640x350/4 */
179 (vga_si->orig_video_mode == 0x12) || /* 640x480/4 */
180 (vga_si->orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */
183 vga_video_num_lines = vga_si->orig_video_lines;
184 vga_video_num_columns = vga_si->orig_video_cols;
185 vgastate.vgabase = NULL;
187 if (vga_si->orig_video_mode == 7) {
188 /* Monochrome display */
189 vga_vram_base = 0xb0000;
190 vga_video_port_reg = VGA_CRT_IM;
191 vga_video_port_val = VGA_CRT_DM;
192 if ((vga_si->orig_video_ega_bx & 0xff) != 0x10) {
193 static struct resource ega_console_resource =
195 .flags = IORESOURCE_IO,
198 vga_video_type = VIDEO_TYPE_EGAM;
199 vga_vram_size = 0x8000;
200 display_desc = "EGA+";
201 request_resource(&ioport_resource,
202 &ega_console_resource);
204 static struct resource mda1_console_resource =
206 .flags = IORESOURCE_IO,
209 static struct resource mda2_console_resource =
211 .flags = IORESOURCE_IO,
214 vga_video_type = VIDEO_TYPE_MDA;
215 vga_vram_size = 0x2000;
216 display_desc = "*MDA";
217 request_resource(&ioport_resource,
218 &mda1_console_resource);
219 request_resource(&ioport_resource,
220 &mda2_console_resource);
221 vga_video_font_height = 14;
224 /* If not, it is color. */
225 vga_can_do_color = true;
226 vga_vram_base = 0xb8000;
227 vga_video_port_reg = VGA_CRT_IC;
228 vga_video_port_val = VGA_CRT_DC;
229 if ((vga_si->orig_video_ega_bx & 0xff) != 0x10) {
232 vga_vram_size = 0x8000;
234 if (!vga_si->orig_video_isVGA) {
235 static struct resource ega_console_resource =
237 .flags = IORESOURCE_IO,
240 vga_video_type = VIDEO_TYPE_EGAC;
241 display_desc = "EGA";
242 request_resource(&ioport_resource,
243 &ega_console_resource);
245 static struct resource vga_console_resource =
247 .flags = IORESOURCE_IO,
250 vga_video_type = VIDEO_TYPE_VGAC;
251 display_desc = "VGA+";
252 request_resource(&ioport_resource,
253 &vga_console_resource);
256 * Normalise the palette registers, to point
257 * the 16 screen colours to the first 16
261 for (i = 0; i < 16; i++) {
263 outb_p(i, VGA_ATT_W);
264 outb_p(i, VGA_ATT_W);
266 outb_p(0x20, VGA_ATT_W);
269 * Now set the DAC registers back to their
272 for (i = 0; i < 16; i++) {
273 outb_p(color_table[i], VGA_PEL_IW);
274 outb_p(default_red[i], VGA_PEL_D);
275 outb_p(default_grn[i], VGA_PEL_D);
276 outb_p(default_blu[i], VGA_PEL_D);
280 static struct resource cga_console_resource =
282 .flags = IORESOURCE_IO,
285 vga_video_type = VIDEO_TYPE_CGA;
286 vga_vram_size = 0x2000;
287 display_desc = "*CGA";
288 request_resource(&ioport_resource,
289 &cga_console_resource);
290 vga_video_font_height = 8;
294 vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
295 vga_vram_end = vga_vram_base + vga_vram_size;
298 * Find out if there is a graphics card present.
299 * Are there smarter methods around?
301 p = (volatile u16 *) vga_vram_base;
302 saved1 = scr_readw(p);
303 saved2 = scr_readw(p + 1);
304 scr_writew(0xAA55, p);
305 scr_writew(0x55AA, p + 1);
306 if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
307 scr_writew(saved1, p);
308 scr_writew(saved2, p + 1);
311 scr_writew(0x55AA, p);
312 scr_writew(0xAA55, p + 1);
313 if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
314 scr_writew(saved1, p);
315 scr_writew(saved2, p + 1);
318 scr_writew(saved1, p);
319 scr_writew(saved2, p + 1);
321 if (vga_video_type == VIDEO_TYPE_EGAC
322 || vga_video_type == VIDEO_TYPE_VGAC
323 || vga_video_type == VIDEO_TYPE_EGAM) {
324 vga_hardscroll_enabled = vga_hardscroll_user_enable;
325 vga_default_font_height = vga_si->orig_video_points;
326 vga_video_font_height = vga_si->orig_video_points;
327 /* This may be suboptimal but is a safe bet - go with it */
329 vga_video_font_height * vga_video_num_lines;
332 vgacon_xres = vga_si->orig_video_cols * VGA_FONTWIDTH;
333 vgacon_yres = vga_scan_lines;
338 static void vgacon_init(struct vc_data *c, int init)
340 struct uni_pagedict *p;
343 * We cannot be loaded as a module, therefore init will be 1
344 * if we are the default console, however if we are a fallback
345 * console, for example if fbcon has failed registration, then
346 * init will be 0, so we need to make sure our boot parameters
347 * have been copied to the console structure for vgacon_resize
348 * ultimately called by vc_resize. Any subsequent calls to
349 * vgacon_init init will have init set to 0 too.
351 c->vc_can_do_color = vga_can_do_color;
352 c->vc_scan_lines = vga_scan_lines;
353 c->vc_font.height = c->vc_cell_height = vga_video_font_height;
355 /* set dimensions manually if init != 0 since vc_resize() will fail */
357 c->vc_cols = vga_video_num_columns;
358 c->vc_rows = vga_video_num_lines;
360 vc_resize(c, vga_video_num_columns, vga_video_num_lines);
362 c->vc_complement_mask = 0x7700;
364 c->vc_hi_font_mask = 0x0800;
365 p = *c->uni_pagedict_loc;
366 if (c->uni_pagedict_loc != &vgacon_uni_pagedir) {
368 c->uni_pagedict_loc = &vgacon_uni_pagedir;
371 if (!vgacon_uni_pagedir && p)
372 con_set_default_unimap(c);
374 /* Only set the default if the user didn't deliberately override it */
375 if (global_cursor_default == -1)
376 global_cursor_default =
377 !(vga_si->flags & VIDEO_FLAGS_NOCURSOR);
380 static void vgacon_deinit(struct vc_data *c)
382 /* When closing the active console, reset video origin */
383 if (con_is_visible(c)) {
384 c->vc_visible_origin = vga_vram_base;
388 if (!--vgacon_refcount)
390 c->uni_pagedict_loc = &c->uni_pagedict;
391 con_set_default_unimap(c);
394 static u8 vgacon_build_attr(struct vc_data *c, u8 color,
395 enum vc_intensity intensity,
396 bool blink, bool underline, bool reverse,
401 if (vga_can_do_color) {
403 attr = (attr & 0xF0) | c->vc_itcolor;
405 attr = (attr & 0xf0) | c->vc_ulcolor;
406 else if (intensity == VCI_HALF_BRIGHT)
407 attr = (attr & 0xf0) | c->vc_halfcolor;
411 ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
415 if (intensity == VCI_BOLD)
417 if (!vga_can_do_color) {
419 attr = (attr & 0xF8) | 0x02;
421 attr = (attr & 0xf8) | 0x01;
422 else if (intensity == VCI_HALF_BRIGHT)
423 attr = (attr & 0xf0) | 0x08;
428 static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
430 const bool col = vga_can_do_color;
433 u16 a = scr_readw(p);
435 a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
436 (((a) & 0x0700) << 4);
438 a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
443 static void vgacon_set_cursor_size(int from, int to)
448 if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
450 cursor_size_lastfrom = from;
451 cursor_size_lastto = to;
453 raw_spin_lock_irqsave(&vga_lock, flags);
454 if (vga_video_type >= VIDEO_TYPE_VGAC) {
455 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
456 curs = inb_p(vga_video_port_val);
457 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
458 cure = inb_p(vga_video_port_val);
464 curs = (curs & 0xc0) | from;
465 cure = (cure & 0xe0) | to;
467 outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
468 outb_p(curs, vga_video_port_val);
469 outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
470 outb_p(cure, vga_video_port_val);
471 raw_spin_unlock_irqrestore(&vga_lock, flags);
474 static void vgacon_cursor(struct vc_data *c, int mode)
476 unsigned int c_height;
478 if (c->vc_mode != KD_TEXT)
481 vgacon_restore_screen(c);
483 c_height = c->vc_cell_height;
487 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
488 if (vga_video_type >= VIDEO_TYPE_VGAC)
489 vgacon_set_cursor_size(31, 30);
491 vgacon_set_cursor_size(31, 31);
496 write_vga(14, (c->vc_pos - vga_vram_base) / 2);
497 switch (CUR_SIZE(c->vc_cursor_type)) {
499 vgacon_set_cursor_size(c_height -
500 (c_height < 10 ? 2 : 3),
502 (c_height < 10 ? 1 : 2));
505 vgacon_set_cursor_size(c_height / 3, c_height -
506 (c_height < 10 ? 1 : 2));
508 case CUR_LOWER_THIRD:
509 vgacon_set_cursor_size(c_height * 2 / 3, c_height -
510 (c_height < 10 ? 1 : 2));
513 vgacon_set_cursor_size(c_height / 2, c_height -
514 (c_height < 10 ? 1 : 2));
517 if (vga_video_type >= VIDEO_TYPE_VGAC)
518 vgacon_set_cursor_size(31, 30);
520 vgacon_set_cursor_size(31, 31);
523 vgacon_set_cursor_size(1, c_height);
530 static void vgacon_doresize(struct vc_data *c,
531 unsigned int width, unsigned int height)
534 unsigned int scanlines = height * c->vc_cell_height;
535 u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
537 raw_spin_lock_irqsave(&vga_lock, flags);
539 vgacon_xres = width * VGA_FONTWIDTH;
540 vgacon_yres = height * c->vc_cell_height;
541 if (vga_video_type >= VIDEO_TYPE_VGAC) {
542 outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
543 max_scan = inb_p(vga_video_port_val);
548 outb_p(VGA_CRTC_MODE, vga_video_port_reg);
549 mode = inb_p(vga_video_port_val);
555 scanlines_lo = scanlines & 0xff;
557 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
558 r7 = inb_p(vga_video_port_val) & ~0x42;
560 if (scanlines & 0x100)
562 if (scanlines & 0x200)
565 /* deprotect registers */
566 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
567 vsync_end = inb_p(vga_video_port_val);
568 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
569 outb_p(vsync_end & ~0x80, vga_video_port_val);
572 outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
573 outb_p(width - 1, vga_video_port_val);
574 outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
575 outb_p(width >> 1, vga_video_port_val);
577 if (vga_video_type >= VIDEO_TYPE_VGAC) {
578 outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
579 outb_p(scanlines_lo, vga_video_port_val);
580 outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
581 outb_p(r7,vga_video_port_val);
583 /* reprotect registers */
584 outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
585 outb_p(vsync_end, vga_video_port_val);
588 raw_spin_unlock_irqrestore(&vga_lock, flags);
591 static int vgacon_switch(struct vc_data *c)
593 int x = c->vc_cols * VGA_FONTWIDTH;
594 int y = c->vc_rows * c->vc_cell_height;
595 int rows = vga_si->orig_video_lines * vga_default_font_height/
598 * We need to save screen size here as it's the only way
599 * we can spot the screen has been resized and we need to
600 * set size of freshly allocated screens ourselves.
602 vga_video_num_columns = c->vc_cols;
603 vga_video_num_lines = c->vc_rows;
605 /* We can only copy out the size of the video buffer here,
606 * otherwise we get into VGA BIOS */
609 scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
610 c->vc_screenbuf_size > vga_vram_size ?
611 vga_vram_size : c->vc_screenbuf_size);
613 if ((vgacon_xres != x || vgacon_yres != y) &&
614 (!(vga_video_num_columns % 2) &&
615 vga_video_num_columns <= vga_si->orig_video_cols &&
616 vga_video_num_lines <= rows))
617 vgacon_doresize(c, c->vc_cols, c->vc_rows);
620 return 0; /* Redrawing not needed */
623 static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
627 vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
628 for (i = j = 0; i < 16; i++) {
629 vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
630 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
631 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
632 vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
636 static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
638 if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
639 || !con_is_visible(vc))
641 vga_set_palette(vc, table);
644 /* structure holding original VGA register settings */
646 unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
647 unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
648 unsigned char CrtMiscIO; /* Miscellaneous register */
649 unsigned char HorizontalTotal; /* CRT-Controller:00h */
650 unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
651 unsigned char StartHorizRetrace; /* CRT-Controller:04h */
652 unsigned char EndHorizRetrace; /* CRT-Controller:05h */
653 unsigned char Overflow; /* CRT-Controller:07h */
654 unsigned char StartVertRetrace; /* CRT-Controller:10h */
655 unsigned char EndVertRetrace; /* CRT-Controller:11h */
656 unsigned char ModeControl; /* CRT-Controller:17h */
657 unsigned char ClockingMode; /* Seq-Controller:01h */
660 static void vga_vesa_blank(struct vgastate *state, int mode)
662 /* save original values of VGA controller registers */
663 if (!vga_vesa_blanked) {
664 raw_spin_lock_irq(&vga_lock);
665 vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
666 vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
667 vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
668 raw_spin_unlock_irq(&vga_lock);
670 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
671 vga_state.HorizontalTotal = inb_p(vga_video_port_val);
672 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
673 vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
674 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
675 vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
676 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
677 vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
678 outb_p(0x07, vga_video_port_reg); /* Overflow */
679 vga_state.Overflow = inb_p(vga_video_port_val);
680 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
681 vga_state.StartVertRetrace = inb_p(vga_video_port_val);
682 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
683 vga_state.EndVertRetrace = inb_p(vga_video_port_val);
684 outb_p(0x17, vga_video_port_reg); /* ModeControl */
685 vga_state.ModeControl = inb_p(vga_video_port_val);
686 vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
689 /* assure that video is enabled */
690 /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
691 raw_spin_lock_irq(&vga_lock);
692 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
694 /* test for vertical retrace in process.... */
695 if ((vga_state.CrtMiscIO & 0x80) == 0x80)
696 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
699 * Set <End of vertical retrace> to minimum (0) and
700 * <Start of vertical Retrace> to maximum (incl. overflow)
701 * Result: turn off vertical sync (VSync) pulse.
703 if (mode & VESA_VSYNC_SUSPEND) {
704 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
705 outb_p(0xff, vga_video_port_val); /* maximum value */
706 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
707 outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
708 outb_p(0x07, vga_video_port_reg); /* Overflow */
709 outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
712 if (mode & VESA_HSYNC_SUSPEND) {
714 * Set <End of horizontal retrace> to minimum (0) and
715 * <Start of horizontal Retrace> to maximum
716 * Result: turn off horizontal sync (HSync) pulse.
718 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
719 outb_p(0xff, vga_video_port_val); /* maximum */
720 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
721 outb_p(0x00, vga_video_port_val); /* minimum (0) */
724 /* restore both index registers */
725 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
726 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
727 raw_spin_unlock_irq(&vga_lock);
730 static void vga_vesa_unblank(struct vgastate *state)
732 /* restore original values of VGA controller registers */
733 raw_spin_lock_irq(&vga_lock);
734 vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
736 outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
737 outb_p(vga_state.HorizontalTotal, vga_video_port_val);
738 outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
739 outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
740 outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
741 outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
742 outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
743 outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
744 outb_p(0x07, vga_video_port_reg); /* Overflow */
745 outb_p(vga_state.Overflow, vga_video_port_val);
746 outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
747 outb_p(vga_state.StartVertRetrace, vga_video_port_val);
748 outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
749 outb_p(vga_state.EndVertRetrace, vga_video_port_val);
750 outb_p(0x17, vga_video_port_reg); /* ModeControl */
751 outb_p(vga_state.ModeControl, vga_video_port_val);
753 vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
755 /* restore index/control registers */
756 vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
757 outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
758 raw_spin_unlock_irq(&vga_lock);
761 static void vga_pal_blank(struct vgastate *state)
765 vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
766 for (i = 0; i < 16; i++) {
767 vga_w(state->vgabase, VGA_PEL_IW, i);
768 vga_w(state->vgabase, VGA_PEL_D, 0);
769 vga_w(state->vgabase, VGA_PEL_D, 0);
770 vga_w(state->vgabase, VGA_PEL_D, 0);
774 static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
777 case 0: /* Unblank */
778 if (vga_vesa_blanked) {
779 vga_vesa_unblank(&vgastate);
780 vga_vesa_blanked = 0;
782 if (vga_palette_blanked) {
783 vga_set_palette(c, color_table);
784 vga_palette_blanked = false;
788 /* Tell console.c that it has to restore the screen itself */
790 case 1: /* Normal blanking */
791 case -1: /* Obsolete */
792 if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
793 vga_pal_blank(&vgastate);
794 vga_palette_blanked = true;
797 vgacon_set_origin(c);
798 scr_memsetw((void *) vga_vram_base, BLANK,
799 c->vc_screenbuf_size);
803 default: /* VESA blanking */
804 if (vga_video_type == VIDEO_TYPE_VGAC) {
805 vga_vesa_blank(&vgastate, blank - 1);
806 vga_vesa_blanked = blank;
815 * The font loading code goes back to the codepage package by
816 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
817 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
818 * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
820 * Change for certain monochrome monitors by Yury Shevchuck
821 * (sizif@botik.yaroslavl.su).
824 #define colourmap 0xa0000
825 /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
826 should use 0xA0000 for the bwmap as well.. */
827 #define blackwmap 0xa0000
830 static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
833 unsigned short video_port_status = vga_video_port_reg + 6;
834 int font_select = 0x00, beg, i;
836 bool clear_attribs = false;
837 if (vga_video_type != VIDEO_TYPE_EGAM) {
838 charmap = (char *) VGA_MAP_MEM(colourmap, 0);
841 charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
846 * All fonts are loaded in slot 0 (0:1 for 512 ch)
850 return -EINVAL; /* Return to default font not supported */
852 font_select = ch512 ? 0x04 : 0x00;
854 raw_spin_lock_irq(&vga_lock);
855 /* First, the Sequencer */
856 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
857 /* CPU writes only to map 2 */
858 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
859 /* Sequential addressing */
860 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
861 /* Clear synchronous reset */
862 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
864 /* Now, the graphics controller, select map 2 */
865 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
866 /* disable odd-even addressing */
867 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
868 /* map start at A000:0000 */
869 vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
870 raw_spin_unlock_irq(&vga_lock);
874 for (i = 0; i < cmapsz; i++) {
875 vga_writeb(arg[i], charmap + i);
879 for (i = 0; i < cmapsz; i++) {
880 arg[i] = vga_readb(charmap + i);
885 * In 512-character mode, the character map is not contiguous if
886 * we want to remain EGA compatible -- which we do
890 charmap += 2 * cmapsz;
893 for (i = 0; i < cmapsz; i++) {
894 vga_writeb(arg[i], charmap + i);
898 for (i = 0; i < cmapsz; i++) {
899 arg[i] = vga_readb(charmap + i);
905 raw_spin_lock_irq(&vga_lock);
906 /* First, the sequencer, Synchronous reset */
907 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
908 /* CPU writes to maps 0 and 1 */
909 vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
910 /* odd-even addressing */
911 vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
912 /* Character Map Select */
914 vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
915 /* clear synchronous reset */
916 vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
918 /* Now, the graphics controller, select map 0 for CPU */
919 vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
920 /* enable even-odd addressing */
921 vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
922 /* map starts at b800:0 or b000:0 */
923 vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
925 /* if 512 char mode is already enabled don't re-enable it. */
926 if ((set) && (ch512 != vga_512_chars)) {
927 vga_512_chars = ch512;
928 /* 256-char: enable intensity bit
929 512-char: disable intensity bit */
930 inb_p(video_port_status); /* clear address flip-flop */
931 /* color plane enable register */
932 vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
933 /* Wilton (1987) mentions the following; I don't know what
934 it means, but it works, and it appears necessary */
935 inb_p(video_port_status);
936 vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
937 clear_attribs = true;
939 raw_spin_unlock_irq(&vga_lock);
942 for (i = 0; i < MAX_NR_CONSOLES; i++) {
943 struct vc_data *c = vc_cons[i].d;
944 if (c && c->vc_sw == &vga_con) {
945 /* force hi font mask to 0, so we always clear
946 the bit on either transition */
947 c->vc_hi_font_mask = 0x00;
948 clear_buffer_attributes(c);
949 c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
957 * Adjust the screen to fit a font of a certain height
959 static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
961 unsigned char ovr, vde, fsr;
962 int rows, maxscan, i;
964 rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
965 maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
967 /* Reprogram the CRTC for the new font size
968 Note: the attempt to read the overflow register will fail
969 on an EGA, but using 0xff for the previous value appears to
970 be OK for EGA text modes in the range 257-512 scan lines, so I
971 guess we don't need to worry about it.
973 The same applies for the spill bits in the font size and cursor
974 registers; they are write-only on EGA, but it appears that they
975 are all don't care bits on EGA, so I guess it doesn't matter. */
977 raw_spin_lock_irq(&vga_lock);
978 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
979 ovr = inb_p(vga_video_port_val);
980 outb_p(0x09, vga_video_port_reg); /* Font size register */
981 fsr = inb_p(vga_video_port_val);
982 raw_spin_unlock_irq(&vga_lock);
984 vde = maxscan & 0xff; /* Vertical display end reg */
985 ovr = (ovr & 0xbd) + /* Overflow register */
986 ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
987 fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
989 raw_spin_lock_irq(&vga_lock);
990 outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
991 outb_p(ovr, vga_video_port_val);
992 outb_p(0x09, vga_video_port_reg); /* Font size */
993 outb_p(fsr, vga_video_port_val);
994 outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
995 outb_p(vde, vga_video_port_val);
996 raw_spin_unlock_irq(&vga_lock);
997 vga_video_font_height = fontheight;
999 for (i = 0; i < MAX_NR_CONSOLES; i++) {
1000 struct vc_data *c = vc_cons[i].d;
1002 if (c && c->vc_sw == &vga_con) {
1003 if (con_is_visible(c)) {
1004 /* void size to cause regs to be rewritten */
1005 cursor_size_lastfrom = 0;
1006 cursor_size_lastto = 0;
1007 c->vc_sw->con_cursor(c, CM_DRAW);
1009 c->vc_font.height = c->vc_cell_height = fontheight;
1010 vc_resize(c, 0, rows); /* Adjust console size */
1016 static int vgacon_font_set(struct vc_data *c, struct console_font *font,
1017 unsigned int vpitch, unsigned int flags)
1019 unsigned charcount = font->charcount;
1022 if (vga_video_type < VIDEO_TYPE_EGAM)
1025 if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
1026 (charcount != 256 && charcount != 512))
1029 rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
1033 if (!(flags & KD_FONT_FLAG_DONT_RECALC))
1034 rc = vgacon_adjust_height(c, font->height);
1038 static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
1040 if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
1043 font->width = VGA_FONTWIDTH;
1044 font->height = c->vc_font.height;
1045 font->charcount = vga_512_chars ? 512 : 256;
1048 return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
1051 static int vgacon_resize(struct vc_data *c, unsigned int width,
1052 unsigned int height, unsigned int user)
1054 if ((width << 1) * height > vga_vram_size)
1059 * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
1060 * the video mode! Set the new defaults then and go away.
1062 vga_si->orig_video_cols = width;
1063 vga_si->orig_video_lines = height;
1064 vga_default_font_height = c->vc_cell_height;
1067 if (width % 2 || width > vga_si->orig_video_cols ||
1068 height > (vga_si->orig_video_lines * vga_default_font_height)/
1072 if (con_is_visible(c) && !vga_is_gfx) /* who knows */
1073 vgacon_doresize(c, width, height);
1077 static int vgacon_set_origin(struct vc_data *c)
1079 if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
1080 (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
1082 c->vc_origin = c->vc_visible_origin = vga_vram_base;
1084 vga_rolled_over = 0;
1088 static void vgacon_save_screen(struct vc_data *c)
1090 static int vga_bootup_console = 0;
1092 if (!vga_bootup_console) {
1093 /* This is a gross hack, but here is the only place we can
1094 * set bootup console parameters without messing up generic
1095 * console initialization routines.
1097 vga_bootup_console = 1;
1098 c->state.x = vga_si->orig_x;
1099 c->state.y = vga_si->orig_y;
1102 /* We can't copy in more than the size of the video buffer,
1103 * or we'll be copying in VGA BIOS */
1106 scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1107 c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
1110 static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
1111 enum con_scroll dir, unsigned int lines)
1116 if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1119 if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1122 vgacon_restore_screen(c);
1123 oldo = c->vc_origin;
1124 delta = lines * c->vc_size_row;
1126 if (c->vc_scr_end + delta >= vga_vram_end) {
1127 scr_memcpyw((u16 *) vga_vram_base,
1128 (u16 *) (oldo + delta),
1129 c->vc_screenbuf_size - delta);
1130 c->vc_origin = vga_vram_base;
1131 vga_rolled_over = oldo - vga_vram_base;
1133 c->vc_origin += delta;
1134 scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
1135 delta), c->vc_video_erase_char,
1138 if (oldo - delta < vga_vram_base) {
1139 scr_memmovew((u16 *) (vga_vram_end -
1140 c->vc_screenbuf_size +
1141 delta), (u16 *) oldo,
1142 c->vc_screenbuf_size - delta);
1143 c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
1144 vga_rolled_over = 0;
1146 c->vc_origin -= delta;
1147 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1148 scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
1151 c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
1152 c->vc_visible_origin = c->vc_origin;
1154 c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1159 * The console `switch' structure for the VGA based console
1162 static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
1164 static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
1165 static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
1166 int count, int ypos, int xpos) { }
1168 const struct consw vga_con = {
1169 .owner = THIS_MODULE,
1170 .con_startup = vgacon_startup,
1171 .con_init = vgacon_init,
1172 .con_deinit = vgacon_deinit,
1173 .con_clear = vgacon_clear,
1174 .con_putc = vgacon_putc,
1175 .con_putcs = vgacon_putcs,
1176 .con_cursor = vgacon_cursor,
1177 .con_scroll = vgacon_scroll,
1178 .con_switch = vgacon_switch,
1179 .con_blank = vgacon_blank,
1180 .con_font_set = vgacon_font_set,
1181 .con_font_get = vgacon_font_get,
1182 .con_resize = vgacon_resize,
1183 .con_set_palette = vgacon_set_palette,
1184 .con_scrolldelta = vgacon_scrolldelta,
1185 .con_set_origin = vgacon_set_origin,
1186 .con_save_screen = vgacon_save_screen,
1187 .con_build_attr = vgacon_build_attr,
1188 .con_invert_region = vgacon_invert_region,
1190 EXPORT_SYMBOL(vga_con);
1192 void vgacon_register_screen(struct screen_info *si)
1197 conswitchp = &vga_con;
1201 MODULE_LICENSE("GPL");