11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * linux/drivers/video/vgacon.c -- Low level VGA based console driver
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * Created 28 Sep 1997 by Geert Uytterhoeven
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Rewritten by Martin Mares <mj@ucw.cz>, July 1998
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * This file is based on the old console.c, vga.c and vesa_blank.c drivers.
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
111da177e4SLinus Torvalds * 1995 Jay Estabrook
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * User definable mapping table and font loading by Eugene G. Crosser,
141da177e4SLinus Torvalds * <crosser@average.org>
151da177e4SLinus Torvalds *
161da177e4SLinus Torvalds * Improved loadable font/UTF-8 support by H. Peter Anvin
171da177e4SLinus Torvalds * Feb-Sep 1995 <peter.anvin@linux.org>
181da177e4SLinus Torvalds *
191da177e4SLinus Torvalds * Colour palette handling, by Simon Tatham
201da177e4SLinus Torvalds * 17-Jun-95 <sgt20@cam.ac.uk>
211da177e4SLinus Torvalds *
221da177e4SLinus Torvalds * if 512 char mode is already enabled don't re-enable it,
231da177e4SLinus Torvalds * because it causes screen to flicker, by Mitja Horvat
241da177e4SLinus Torvalds * 5-May-96 <mitja.horvat@guest.arnes.si>
251da177e4SLinus Torvalds *
261da177e4SLinus Torvalds * Use 2 outw instead of 4 outb_p to reduce erroneous text
271da177e4SLinus Torvalds * flashing on RHS of screen during heavy console scrolling .
281da177e4SLinus Torvalds * Oct 1996, Paul Gortmaker.
291da177e4SLinus Torvalds *
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
321da177e4SLinus Torvalds * License. See the file COPYING in the main directory of this archive for
331da177e4SLinus Torvalds * more details.
341da177e4SLinus Torvalds */
351da177e4SLinus Torvalds
361da177e4SLinus Torvalds #include <linux/module.h>
371da177e4SLinus Torvalds #include <linux/types.h>
381da177e4SLinus Torvalds #include <linux/fs.h>
391da177e4SLinus Torvalds #include <linux/kernel.h>
401da177e4SLinus Torvalds #include <linux/console.h>
411da177e4SLinus Torvalds #include <linux/string.h>
421da177e4SLinus Torvalds #include <linux/kd.h>
431da177e4SLinus Torvalds #include <linux/slab.h>
441da177e4SLinus Torvalds #include <linux/vt_kern.h>
450ab3691fSDave Airlie #include <linux/sched.h>
461da177e4SLinus Torvalds #include <linux/selection.h>
471da177e4SLinus Torvalds #include <linux/spinlock.h>
481da177e4SLinus Torvalds #include <linux/ioport.h>
491da177e4SLinus Torvalds #include <linux/init.h>
50894673eeSJon Smirl #include <linux/screen_info.h>
511da177e4SLinus Torvalds #include <video/vga.h>
521da177e4SLinus Torvalds #include <asm/io.h>
531da177e4SLinus Torvalds
546b2c1800SThomas Gleixner static DEFINE_RAW_SPINLOCK(vga_lock);
551da177e4SLinus Torvalds static int cursor_size_lastfrom;
561da177e4SLinus Torvalds static int cursor_size_lastto;
5753dbb26dSAntonino A. Daplas static u32 vgacon_xres;
5853dbb26dSAntonino A. Daplas static u32 vgacon_yres;
5989f0244eSMark Rustad static struct vgastate vgastate;
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds #define BLANK 0x0020
621da177e4SLinus Torvalds
6353dbb26dSAntonino A. Daplas #define VGA_FONTWIDTH 8 /* VGA does not support fontwidths != 8 */
641da177e4SLinus Torvalds /*
651da177e4SLinus Torvalds * Interface used by the world
661da177e4SLinus Torvalds */
671da177e4SLinus Torvalds
681da177e4SLinus Torvalds static int vgacon_set_origin(struct vc_data *c);
696ceed69cSJiri Slaby (SUSE)
704173f018SJiri Slaby static struct uni_pagedict *vgacon_uni_pagedir;
710f2893f0STakashi Iwai static int vgacon_refcount;
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds /* Description of the hardware situation */
740128beeeSHelge Deller static unsigned long vga_vram_base __read_mostly; /* Base of video memory */
750128beeeSHelge Deller static unsigned long vga_vram_end __read_mostly; /* End of video memory */
760128beeeSHelge Deller static unsigned int vga_vram_size __read_mostly; /* Size of video memory */
770128beeeSHelge Deller static u16 vga_video_port_reg __read_mostly; /* Video register select port */
780128beeeSHelge Deller static u16 vga_video_port_val __read_mostly; /* Video register value port */
791da177e4SLinus Torvalds static unsigned int vga_video_num_columns; /* Number of text columns */
801da177e4SLinus Torvalds static unsigned int vga_video_num_lines; /* Number of text lines */
8196fd9554SJiri Slaby static bool vga_can_do_color; /* Do we support colors? */
820128beeeSHelge Deller static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */
830128beeeSHelge Deller static unsigned char vga_video_type __read_mostly; /* Card type */
841da177e4SLinus Torvalds static int vga_vesa_blanked;
8596fd9554SJiri Slaby static bool vga_palette_blanked;
8696fd9554SJiri Slaby static bool vga_is_gfx;
8796fd9554SJiri Slaby static bool vga_512_chars;
881da177e4SLinus Torvalds static int vga_video_font_height;
890128beeeSHelge Deller static int vga_scan_lines __read_mostly;
905a3c96e9SJiri Slaby static unsigned int vga_rolled_over; /* last vc_origin offset before wrap */
911da177e4SLinus Torvalds
9296fd9554SJiri Slaby static bool vga_hardscroll_enabled;
9396fd9554SJiri Slaby static bool vga_hardscroll_user_enable = true;
94f453ba04SDave Airlie
no_scroll(char * str)951da177e4SLinus Torvalds static int __init no_scroll(char *str)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds /*
981da177e4SLinus Torvalds * Disabling scrollback is required for the Braillex ib80-piezo
991da177e4SLinus Torvalds * Braille reader made by F.H. Papenmeier (Germany).
1001da177e4SLinus Torvalds * Use the "no-scroll" bootflag.
1011da177e4SLinus Torvalds */
10296fd9554SJiri Slaby vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
1031da177e4SLinus Torvalds return 1;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds __setup("no-scroll", no_scroll);
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds * By replacing the four outb_p with two back to back outw, we can reduce
1101da177e4SLinus Torvalds * the window of opportunity to see text mislocated to the RHS of the
1111da177e4SLinus Torvalds * console during heavy scrolling activity. However there is the remote
1121da177e4SLinus Torvalds * possibility that some pre-dinosaur hardware won't like the back to back
1131da177e4SLinus Torvalds * I/O. Since the Xservers get away with it, we should be able to as well.
1141da177e4SLinus Torvalds */
write_vga(unsigned char reg,unsigned int val)1151da177e4SLinus Torvalds static inline void write_vga(unsigned char reg, unsigned int val)
1161da177e4SLinus Torvalds {
1171da177e4SLinus Torvalds unsigned int v1, v2;
1181da177e4SLinus Torvalds unsigned long flags;
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds /*
1211da177e4SLinus Torvalds * ddprintk might set the console position from interrupt
1221da177e4SLinus Torvalds * handlers, thus the write has to be IRQ-atomic.
1231da177e4SLinus Torvalds */
1246b2c1800SThomas Gleixner raw_spin_lock_irqsave(&vga_lock, flags);
1251da177e4SLinus Torvalds v1 = reg + (val & 0xff00);
1261da177e4SLinus Torvalds v2 = reg + 1 + ((val << 8) & 0xff00);
1271da177e4SLinus Torvalds outw(v1, vga_video_port_reg);
1281da177e4SLinus Torvalds outw(v2, vga_video_port_reg);
1296b2c1800SThomas Gleixner raw_spin_unlock_irqrestore(&vga_lock, flags);
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds
vga_set_mem_top(struct vc_data * c)13215bdab95SAntonino A. Daplas static inline void vga_set_mem_top(struct vc_data *c)
13315bdab95SAntonino A. Daplas {
13415bdab95SAntonino A. Daplas write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
13515bdab95SAntonino A. Daplas }
13615bdab95SAntonino A. Daplas
vgacon_scrolldelta(struct vc_data * c,int lines)13797293de9SJiri Slaby static void vgacon_scrolldelta(struct vc_data *c, int lines)
13815bdab95SAntonino A. Daplas {
13935cc56f9SJiri Slaby vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
14035cc56f9SJiri Slaby vga_vram_size);
14115bdab95SAntonino A. Daplas vga_set_mem_top(c);
14215bdab95SAntonino A. Daplas }
143bcd375f7SManuel Schölling
vgacon_restore_screen(struct vc_data * c)14403b89a08SJiri Slaby (SUSE) static void vgacon_restore_screen(struct vc_data *c)
14503b89a08SJiri Slaby (SUSE) {
14603b89a08SJiri Slaby (SUSE) if (c->vc_origin != c->vc_visible_origin)
14703b89a08SJiri Slaby (SUSE) vgacon_scrolldelta(c, 0);
14803b89a08SJiri Slaby (SUSE) }
14903b89a08SJiri Slaby (SUSE)
vgacon_startup(void)15050ec42edSAntonino A. Daplas static const char *vgacon_startup(void)
1511da177e4SLinus Torvalds {
1521da177e4SLinus Torvalds const char *display_desc = NULL;
1531da177e4SLinus Torvalds u16 saved1, saved2;
1541da177e4SLinus Torvalds volatile u16 *p;
1551da177e4SLinus Torvalds
156554ec37aSYannick Heneault if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
157554ec37aSYannick Heneault screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
1581da177e4SLinus Torvalds no_vga:
1591da177e4SLinus Torvalds #ifdef CONFIG_DUMMY_CONSOLE
1601da177e4SLinus Torvalds conswitchp = &dummy_con;
1611da177e4SLinus Torvalds return conswitchp->con_startup();
1621da177e4SLinus Torvalds #else
1631da177e4SLinus Torvalds return NULL;
1641da177e4SLinus Torvalds #endif
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds
167b9a58de5SJan H. Schönherr /* boot_params.screen_info reasonably initialized? */
168b9a58de5SJan H. Schönherr if ((screen_info.orig_video_lines == 0) ||
1693ea33510SH. Peter Anvin (screen_info.orig_video_cols == 0))
170a1a4849cSGerd Hoffmann goto no_vga;
171a1a4849cSGerd Hoffmann
1721da177e4SLinus Torvalds /* VGA16 modes are not handled by VGACON */
1733ea33510SH. Peter Anvin if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */
1743ea33510SH. Peter Anvin (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */
1753ea33510SH. Peter Anvin (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */
1763ea33510SH. Peter Anvin (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */
1773ea33510SH. Peter Anvin (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */
1781da177e4SLinus Torvalds goto no_vga;
1791da177e4SLinus Torvalds
1803ea33510SH. Peter Anvin vga_video_num_lines = screen_info.orig_video_lines;
1813ea33510SH. Peter Anvin vga_video_num_columns = screen_info.orig_video_cols;
18289f0244eSMark Rustad vgastate.vgabase = NULL;
1831da177e4SLinus Torvalds
1843ea33510SH. Peter Anvin if (screen_info.orig_video_mode == 7) {
1853ea33510SH. Peter Anvin /* Monochrome display */
1861da177e4SLinus Torvalds vga_vram_base = 0xb0000;
1871da177e4SLinus Torvalds vga_video_port_reg = VGA_CRT_IM;
1881da177e4SLinus Torvalds vga_video_port_val = VGA_CRT_DM;
1893ea33510SH. Peter Anvin if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
1901da177e4SLinus Torvalds static struct resource ega_console_resource =
191c8208411SBjorn Helgaas { .name = "ega",
192c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
193c8208411SBjorn Helgaas .start = 0x3B0,
194c8208411SBjorn Helgaas .end = 0x3BF };
1951da177e4SLinus Torvalds vga_video_type = VIDEO_TYPE_EGAM;
1964f1bcaf0SBjorn Helgaas vga_vram_size = 0x8000;
1971da177e4SLinus Torvalds display_desc = "EGA+";
1981da177e4SLinus Torvalds request_resource(&ioport_resource,
1991da177e4SLinus Torvalds &ega_console_resource);
2001da177e4SLinus Torvalds } else {
2011da177e4SLinus Torvalds static struct resource mda1_console_resource =
202c8208411SBjorn Helgaas { .name = "mda",
203c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
204c8208411SBjorn Helgaas .start = 0x3B0,
205c8208411SBjorn Helgaas .end = 0x3BB };
2061da177e4SLinus Torvalds static struct resource mda2_console_resource =
207c8208411SBjorn Helgaas { .name = "mda",
208c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
209c8208411SBjorn Helgaas .start = 0x3BF,
210c8208411SBjorn Helgaas .end = 0x3BF };
2111da177e4SLinus Torvalds vga_video_type = VIDEO_TYPE_MDA;
2124f1bcaf0SBjorn Helgaas vga_vram_size = 0x2000;
2131da177e4SLinus Torvalds display_desc = "*MDA";
2141da177e4SLinus Torvalds request_resource(&ioport_resource,
2151da177e4SLinus Torvalds &mda1_console_resource);
2161da177e4SLinus Torvalds request_resource(&ioport_resource,
2171da177e4SLinus Torvalds &mda2_console_resource);
2181da177e4SLinus Torvalds vga_video_font_height = 14;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds } else {
2211da177e4SLinus Torvalds /* If not, it is color. */
22296fd9554SJiri Slaby vga_can_do_color = true;
2231da177e4SLinus Torvalds vga_vram_base = 0xb8000;
2241da177e4SLinus Torvalds vga_video_port_reg = VGA_CRT_IC;
2251da177e4SLinus Torvalds vga_video_port_val = VGA_CRT_DC;
2263ea33510SH. Peter Anvin if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
2271da177e4SLinus Torvalds int i;
2281da177e4SLinus Torvalds
2294f1bcaf0SBjorn Helgaas vga_vram_size = 0x8000;
2301da177e4SLinus Torvalds
2313ea33510SH. Peter Anvin if (!screen_info.orig_video_isVGA) {
232c8208411SBjorn Helgaas static struct resource ega_console_resource =
233c8208411SBjorn Helgaas { .name = "ega",
234c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
235c8208411SBjorn Helgaas .start = 0x3C0,
236c8208411SBjorn Helgaas .end = 0x3DF };
2371da177e4SLinus Torvalds vga_video_type = VIDEO_TYPE_EGAC;
2381da177e4SLinus Torvalds display_desc = "EGA";
2391da177e4SLinus Torvalds request_resource(&ioport_resource,
2401da177e4SLinus Torvalds &ega_console_resource);
2411da177e4SLinus Torvalds } else {
242c8208411SBjorn Helgaas static struct resource vga_console_resource =
243c8208411SBjorn Helgaas { .name = "vga+",
244c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
245c8208411SBjorn Helgaas .start = 0x3C0,
246c8208411SBjorn Helgaas .end = 0x3DF };
2471da177e4SLinus Torvalds vga_video_type = VIDEO_TYPE_VGAC;
2481da177e4SLinus Torvalds display_desc = "VGA+";
2491da177e4SLinus Torvalds request_resource(&ioport_resource,
2501da177e4SLinus Torvalds &vga_console_resource);
2511da177e4SLinus Torvalds
2521da177e4SLinus Torvalds /*
2531da177e4SLinus Torvalds * Normalise the palette registers, to point
2541da177e4SLinus Torvalds * the 16 screen colours to the first 16
2551da177e4SLinus Torvalds * DAC entries.
2561da177e4SLinus Torvalds */
2571da177e4SLinus Torvalds
2581da177e4SLinus Torvalds for (i = 0; i < 16; i++) {
2591da177e4SLinus Torvalds inb_p(VGA_IS1_RC);
2601da177e4SLinus Torvalds outb_p(i, VGA_ATT_W);
2611da177e4SLinus Torvalds outb_p(i, VGA_ATT_W);
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds outb_p(0x20, VGA_ATT_W);
2641da177e4SLinus Torvalds
2651da177e4SLinus Torvalds /*
2661da177e4SLinus Torvalds * Now set the DAC registers back to their
2671da177e4SLinus Torvalds * default values
2681da177e4SLinus Torvalds */
2691da177e4SLinus Torvalds for (i = 0; i < 16; i++) {
2701da177e4SLinus Torvalds outb_p(color_table[i], VGA_PEL_IW);
2711da177e4SLinus Torvalds outb_p(default_red[i], VGA_PEL_D);
2721da177e4SLinus Torvalds outb_p(default_grn[i], VGA_PEL_D);
2731da177e4SLinus Torvalds outb_p(default_blu[i], VGA_PEL_D);
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds } else {
2771da177e4SLinus Torvalds static struct resource cga_console_resource =
278c8208411SBjorn Helgaas { .name = "cga",
279c8208411SBjorn Helgaas .flags = IORESOURCE_IO,
280c8208411SBjorn Helgaas .start = 0x3D4,
281c8208411SBjorn Helgaas .end = 0x3D5 };
2821da177e4SLinus Torvalds vga_video_type = VIDEO_TYPE_CGA;
2834f1bcaf0SBjorn Helgaas vga_vram_size = 0x2000;
2841da177e4SLinus Torvalds display_desc = "*CGA";
2851da177e4SLinus Torvalds request_resource(&ioport_resource,
2861da177e4SLinus Torvalds &cga_console_resource);
2871da177e4SLinus Torvalds vga_video_font_height = 8;
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds
2914f1bcaf0SBjorn Helgaas vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
2924f1bcaf0SBjorn Helgaas vga_vram_end = vga_vram_base + vga_vram_size;
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds /*
2951da177e4SLinus Torvalds * Find out if there is a graphics card present.
2961da177e4SLinus Torvalds * Are there smarter methods around?
2971da177e4SLinus Torvalds */
2981da177e4SLinus Torvalds p = (volatile u16 *) vga_vram_base;
2991da177e4SLinus Torvalds saved1 = scr_readw(p);
3001da177e4SLinus Torvalds saved2 = scr_readw(p + 1);
3011da177e4SLinus Torvalds scr_writew(0xAA55, p);
3021da177e4SLinus Torvalds scr_writew(0x55AA, p + 1);
3031da177e4SLinus Torvalds if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
3041da177e4SLinus Torvalds scr_writew(saved1, p);
3051da177e4SLinus Torvalds scr_writew(saved2, p + 1);
3061da177e4SLinus Torvalds goto no_vga;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds scr_writew(0x55AA, p);
3091da177e4SLinus Torvalds scr_writew(0xAA55, p + 1);
3101da177e4SLinus Torvalds if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
3111da177e4SLinus Torvalds scr_writew(saved1, p);
3121da177e4SLinus Torvalds scr_writew(saved2, p + 1);
3131da177e4SLinus Torvalds goto no_vga;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds scr_writew(saved1, p);
3161da177e4SLinus Torvalds scr_writew(saved2, p + 1);
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds if (vga_video_type == VIDEO_TYPE_EGAC
3191da177e4SLinus Torvalds || vga_video_type == VIDEO_TYPE_VGAC
3201da177e4SLinus Torvalds || vga_video_type == VIDEO_TYPE_EGAM) {
3211da177e4SLinus Torvalds vga_hardscroll_enabled = vga_hardscroll_user_enable;
3223ea33510SH. Peter Anvin vga_default_font_height = screen_info.orig_video_points;
3233ea33510SH. Peter Anvin vga_video_font_height = screen_info.orig_video_points;
3241da177e4SLinus Torvalds /* This may be suboptimal but is a safe bet - go with it */
3251da177e4SLinus Torvalds vga_scan_lines =
3261da177e4SLinus Torvalds vga_video_font_height * vga_video_num_lines;
3271da177e4SLinus Torvalds }
32853dbb26dSAntonino A. Daplas
3293ea33510SH. Peter Anvin vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
33053dbb26dSAntonino A. Daplas vgacon_yres = vga_scan_lines;
33150ec42edSAntonino A. Daplas
3321da177e4SLinus Torvalds return display_desc;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds
vgacon_init(struct vc_data * c,int init)3351da177e4SLinus Torvalds static void vgacon_init(struct vc_data *c, int init)
3361da177e4SLinus Torvalds {
3374173f018SJiri Slaby struct uni_pagedict *p;
3381da177e4SLinus Torvalds
33950ec42edSAntonino A. Daplas /*
3403dfac26eSMaciej W. Rozycki * We cannot be loaded as a module, therefore init will be 1
3413dfac26eSMaciej W. Rozycki * if we are the default console, however if we are a fallback
3423dfac26eSMaciej W. Rozycki * console, for example if fbcon has failed registration, then
3433dfac26eSMaciej W. Rozycki * init will be 0, so we need to make sure our boot parameters
3443dfac26eSMaciej W. Rozycki * have been copied to the console structure for vgacon_resize
3453dfac26eSMaciej W. Rozycki * ultimately called by vc_resize. Any subsequent calls to
3463dfac26eSMaciej W. Rozycki * vgacon_init init will have init set to 0 too.
34750ec42edSAntonino A. Daplas */
3481da177e4SLinus Torvalds c->vc_can_do_color = vga_can_do_color;
3493dfac26eSMaciej W. Rozycki c->vc_scan_lines = vga_scan_lines;
3503dfac26eSMaciej W. Rozycki c->vc_font.height = c->vc_cell_height = vga_video_font_height;
35150ec42edSAntonino A. Daplas
35250ec42edSAntonino A. Daplas /* set dimensions manually if init != 0 since vc_resize() will fail */
35350ec42edSAntonino A. Daplas if (init) {
3541da177e4SLinus Torvalds c->vc_cols = vga_video_num_columns;
3551da177e4SLinus Torvalds c->vc_rows = vga_video_num_lines;
35650ec42edSAntonino A. Daplas } else
35750ec42edSAntonino A. Daplas vc_resize(c, vga_video_num_columns, vga_video_num_lines);
35850ec42edSAntonino A. Daplas
3591da177e4SLinus Torvalds c->vc_complement_mask = 0x7700;
360a40920b4SBill Nottingham if (vga_512_chars)
361a40920b4SBill Nottingham c->vc_hi_font_mask = 0x0800;
3628da443b1SJiri Slaby p = *c->uni_pagedict_loc;
3638da443b1SJiri Slaby if (c->uni_pagedict_loc != &vgacon_uni_pagedir) {
3641da177e4SLinus Torvalds con_free_unimap(c);
3658da443b1SJiri Slaby c->uni_pagedict_loc = &vgacon_uni_pagedir;
3660f2893f0STakashi Iwai vgacon_refcount++;
3670f2893f0STakashi Iwai }
3680f2893f0STakashi Iwai if (!vgacon_uni_pagedir && p)
3691da177e4SLinus Torvalds con_set_default_unimap(c);
370f6c06b68SMatthew Garrett
371b434a680SMatthew Garrett /* Only set the default if the user didn't deliberately override it */
372b434a680SMatthew Garrett if (global_cursor_default == -1)
373b434a680SMatthew Garrett global_cursor_default =
374b434a680SMatthew Garrett !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
3751da177e4SLinus Torvalds }
3761da177e4SLinus Torvalds
vgacon_deinit(struct vc_data * c)3771da177e4SLinus Torvalds static void vgacon_deinit(struct vc_data *c)
3781da177e4SLinus Torvalds {
379f0c7d2b7SFrancisco Jerez /* When closing the active console, reset video origin */
3806ca8dfd7SJiri Slaby if (con_is_visible(c)) {
3811da177e4SLinus Torvalds c->vc_visible_origin = vga_vram_base;
3821da177e4SLinus Torvalds vga_set_mem_top(c);
3831da177e4SLinus Torvalds }
384f0c7d2b7SFrancisco Jerez
3850f2893f0STakashi Iwai if (!--vgacon_refcount)
386f0c7d2b7SFrancisco Jerez con_free_unimap(c);
3878da443b1SJiri Slaby c->uni_pagedict_loc = &c->uni_pagedict;
3881da177e4SLinus Torvalds con_set_default_unimap(c);
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds
vgacon_build_attr(struct vc_data * c,u8 color,enum vc_intensity intensity,bool blink,bool underline,bool reverse,bool italic)391b84ae3dcSJiri Slaby static u8 vgacon_build_attr(struct vc_data *c, u8 color,
392b84ae3dcSJiri Slaby enum vc_intensity intensity,
39377bc14f2SJiri Slaby bool blink, bool underline, bool reverse,
39477bc14f2SJiri Slaby bool italic)
3951da177e4SLinus Torvalds {
3961da177e4SLinus Torvalds u8 attr = color;
3971da177e4SLinus Torvalds
3981da177e4SLinus Torvalds if (vga_can_do_color) {
399fa6ce9abSJan Engelhardt if (italic)
400fa6ce9abSJan Engelhardt attr = (attr & 0xF0) | c->vc_itcolor;
401fa6ce9abSJan Engelhardt else if (underline)
4021da177e4SLinus Torvalds attr = (attr & 0xf0) | c->vc_ulcolor;
403b84ae3dcSJiri Slaby else if (intensity == VCI_HALF_BRIGHT)
4041da177e4SLinus Torvalds attr = (attr & 0xf0) | c->vc_halfcolor;
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds if (reverse)
4071da177e4SLinus Torvalds attr =
4081da177e4SLinus Torvalds ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
4091da177e4SLinus Torvalds 0x77);
4101da177e4SLinus Torvalds if (blink)
4111da177e4SLinus Torvalds attr ^= 0x80;
412b84ae3dcSJiri Slaby if (intensity == VCI_BOLD)
4131da177e4SLinus Torvalds attr ^= 0x08;
4141da177e4SLinus Torvalds if (!vga_can_do_color) {
415fa6ce9abSJan Engelhardt if (italic)
416fa6ce9abSJan Engelhardt attr = (attr & 0xF8) | 0x02;
417fa6ce9abSJan Engelhardt else if (underline)
4181da177e4SLinus Torvalds attr = (attr & 0xf8) | 0x01;
419b84ae3dcSJiri Slaby else if (intensity == VCI_HALF_BRIGHT)
4201da177e4SLinus Torvalds attr = (attr & 0xf0) | 0x08;
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds return attr;
4231da177e4SLinus Torvalds }
4241da177e4SLinus Torvalds
vgacon_invert_region(struct vc_data * c,u16 * p,int count)4251da177e4SLinus Torvalds static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
4261da177e4SLinus Torvalds {
42796fd9554SJiri Slaby const bool col = vga_can_do_color;
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds while (count--) {
4301da177e4SLinus Torvalds u16 a = scr_readw(p);
4311da177e4SLinus Torvalds if (col)
4321da177e4SLinus Torvalds a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
4331da177e4SLinus Torvalds (((a) & 0x0700) << 4);
4341da177e4SLinus Torvalds else
4351da177e4SLinus Torvalds a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
4361da177e4SLinus Torvalds scr_writew(a, p++);
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds
vgacon_set_cursor_size(int from,int to)440c900dc68SJiri Slaby (SUSE) static void vgacon_set_cursor_size(int from, int to)
4411da177e4SLinus Torvalds {
4421da177e4SLinus Torvalds unsigned long flags;
4431da177e4SLinus Torvalds int curs, cure;
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
4461da177e4SLinus Torvalds return;
4471da177e4SLinus Torvalds cursor_size_lastfrom = from;
4481da177e4SLinus Torvalds cursor_size_lastto = to;
4491da177e4SLinus Torvalds
4506b2c1800SThomas Gleixner raw_spin_lock_irqsave(&vga_lock, flags);
4512115aea8SSamuel Thibault if (vga_video_type >= VIDEO_TYPE_VGAC) {
4522115aea8SSamuel Thibault outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
4531da177e4SLinus Torvalds curs = inb_p(vga_video_port_val);
4542115aea8SSamuel Thibault outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
4551da177e4SLinus Torvalds cure = inb_p(vga_video_port_val);
4562115aea8SSamuel Thibault } else {
4572115aea8SSamuel Thibault curs = 0;
4582115aea8SSamuel Thibault cure = 0;
4592115aea8SSamuel Thibault }
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds curs = (curs & 0xc0) | from;
4621da177e4SLinus Torvalds cure = (cure & 0xe0) | to;
4631da177e4SLinus Torvalds
4642115aea8SSamuel Thibault outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
4651da177e4SLinus Torvalds outb_p(curs, vga_video_port_val);
4662115aea8SSamuel Thibault outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
4671da177e4SLinus Torvalds outb_p(cure, vga_video_port_val);
4686b2c1800SThomas Gleixner raw_spin_unlock_irqrestore(&vga_lock, flags);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds
vgacon_cursor(struct vc_data * c,int mode)4711da177e4SLinus Torvalds static void vgacon_cursor(struct vc_data *c, int mode)
4721da177e4SLinus Torvalds {
473*1023ca19SJiri Slaby (SUSE) unsigned int c_height;
474*1023ca19SJiri Slaby (SUSE)
4752ae85477SAntonino A. Daplas if (c->vc_mode != KD_TEXT)
4762ae85477SAntonino A. Daplas return;
4772ae85477SAntonino A. Daplas
47815bdab95SAntonino A. Daplas vgacon_restore_screen(c);
47915bdab95SAntonino A. Daplas
480*1023ca19SJiri Slaby (SUSE) c_height = c->vc_cell_height;
481*1023ca19SJiri Slaby (SUSE)
4821da177e4SLinus Torvalds switch (mode) {
4831da177e4SLinus Torvalds case CM_ERASE:
48488dcb6c4SSamuel Thibault write_vga(14, (c->vc_pos - vga_vram_base) / 2);
4852115aea8SSamuel Thibault if (vga_video_type >= VIDEO_TYPE_VGAC)
486c900dc68SJiri Slaby (SUSE) vgacon_set_cursor_size(31, 30);
4872115aea8SSamuel Thibault else
488c900dc68SJiri Slaby (SUSE) vgacon_set_cursor_size(31, 31);
4891da177e4SLinus Torvalds break;
4901da177e4SLinus Torvalds
4911da177e4SLinus Torvalds case CM_MOVE:
4921da177e4SLinus Torvalds case CM_DRAW:
4931da177e4SLinus Torvalds write_vga(14, (c->vc_pos - vga_vram_base) / 2);
494c0e4b3adSJiri Slaby switch (CUR_SIZE(c->vc_cursor_type)) {
4951da177e4SLinus Torvalds case CUR_UNDERLINE:
496*1023ca19SJiri Slaby (SUSE) vgacon_set_cursor_size(c_height -
497*1023ca19SJiri Slaby (SUSE) (c_height < 10 ? 2 : 3),
498*1023ca19SJiri Slaby (SUSE) c_height -
499*1023ca19SJiri Slaby (SUSE) (c_height < 10 ? 1 : 2));
5001da177e4SLinus Torvalds break;
5011da177e4SLinus Torvalds case CUR_TWO_THIRDS:
502*1023ca19SJiri Slaby (SUSE) vgacon_set_cursor_size(c_height / 3, c_height -
503*1023ca19SJiri Slaby (SUSE) (c_height < 10 ? 1 : 2));
5041da177e4SLinus Torvalds break;
5051da177e4SLinus Torvalds case CUR_LOWER_THIRD:
506*1023ca19SJiri Slaby (SUSE) vgacon_set_cursor_size(c_height * 2 / 3, c_height -
507*1023ca19SJiri Slaby (SUSE) (c_height < 10 ? 1 : 2));
5081da177e4SLinus Torvalds break;
5091da177e4SLinus Torvalds case CUR_LOWER_HALF:
510*1023ca19SJiri Slaby (SUSE) vgacon_set_cursor_size(c_height / 2, c_height -
511*1023ca19SJiri Slaby (SUSE) (c_height < 10 ? 1 : 2));
5121da177e4SLinus Torvalds break;
5131da177e4SLinus Torvalds case CUR_NONE:
5142115aea8SSamuel Thibault if (vga_video_type >= VIDEO_TYPE_VGAC)
515c900dc68SJiri Slaby (SUSE) vgacon_set_cursor_size(31, 30);
5162115aea8SSamuel Thibault else
517c900dc68SJiri Slaby (SUSE) vgacon_set_cursor_size(31, 31);
5181da177e4SLinus Torvalds break;
5191da177e4SLinus Torvalds default:
520*1023ca19SJiri Slaby (SUSE) vgacon_set_cursor_size(1, c_height);
5211da177e4SLinus Torvalds break;
5221da177e4SLinus Torvalds }
5231da177e4SLinus Torvalds break;
5241da177e4SLinus Torvalds }
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds
vgacon_doresize(struct vc_data * c,unsigned int width,unsigned int height)52793686f6bSJiri Slaby (SUSE) static void vgacon_doresize(struct vc_data *c,
52828254d43SSamuel Thibault unsigned int width, unsigned int height)
52928254d43SSamuel Thibault {
53028254d43SSamuel Thibault unsigned long flags;
531860dafa9SMaciej W. Rozycki unsigned int scanlines = height * c->vc_cell_height;
532d1521260SSamuel Thibault u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
53328254d43SSamuel Thibault
5346b2c1800SThomas Gleixner raw_spin_lock_irqsave(&vga_lock, flags);
53528254d43SSamuel Thibault
536d1521260SSamuel Thibault vgacon_xres = width * VGA_FONTWIDTH;
537860dafa9SMaciej W. Rozycki vgacon_yres = height * c->vc_cell_height;
538d1521260SSamuel Thibault if (vga_video_type >= VIDEO_TYPE_VGAC) {
539954de914SSamuel Thibault outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
540954de914SSamuel Thibault max_scan = inb_p(vga_video_port_val);
541954de914SSamuel Thibault
542954de914SSamuel Thibault if (max_scan & 0x80)
543954de914SSamuel Thibault scanlines <<= 1;
544954de914SSamuel Thibault
54528254d43SSamuel Thibault outb_p(VGA_CRTC_MODE, vga_video_port_reg);
54628254d43SSamuel Thibault mode = inb_p(vga_video_port_val);
54728254d43SSamuel Thibault
54828254d43SSamuel Thibault if (mode & 0x04)
54928254d43SSamuel Thibault scanlines >>= 1;
55028254d43SSamuel Thibault
55128254d43SSamuel Thibault scanlines -= 1;
55228254d43SSamuel Thibault scanlines_lo = scanlines & 0xff;
55328254d43SSamuel Thibault
55428254d43SSamuel Thibault outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
55528254d43SSamuel Thibault r7 = inb_p(vga_video_port_val) & ~0x42;
55628254d43SSamuel Thibault
55728254d43SSamuel Thibault if (scanlines & 0x100)
55828254d43SSamuel Thibault r7 |= 0x02;
55928254d43SSamuel Thibault if (scanlines & 0x200)
56028254d43SSamuel Thibault r7 |= 0x40;
56128254d43SSamuel Thibault
56228254d43SSamuel Thibault /* deprotect registers */
56328254d43SSamuel Thibault outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
56428254d43SSamuel Thibault vsync_end = inb_p(vga_video_port_val);
56528254d43SSamuel Thibault outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
56628254d43SSamuel Thibault outb_p(vsync_end & ~0x80, vga_video_port_val);
567d1521260SSamuel Thibault }
56828254d43SSamuel Thibault
56928254d43SSamuel Thibault outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
57028254d43SSamuel Thibault outb_p(width - 1, vga_video_port_val);
57128254d43SSamuel Thibault outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
57228254d43SSamuel Thibault outb_p(width >> 1, vga_video_port_val);
57328254d43SSamuel Thibault
574d1521260SSamuel Thibault if (vga_video_type >= VIDEO_TYPE_VGAC) {
57528254d43SSamuel Thibault outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
57628254d43SSamuel Thibault outb_p(scanlines_lo, vga_video_port_val);
57728254d43SSamuel Thibault outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
57828254d43SSamuel Thibault outb_p(r7,vga_video_port_val);
57928254d43SSamuel Thibault
58028254d43SSamuel Thibault /* reprotect registers */
58128254d43SSamuel Thibault outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
58228254d43SSamuel Thibault outb_p(vsync_end, vga_video_port_val);
583d1521260SSamuel Thibault }
58428254d43SSamuel Thibault
5856b2c1800SThomas Gleixner raw_spin_unlock_irqrestore(&vga_lock, flags);
58628254d43SSamuel Thibault }
58728254d43SSamuel Thibault
vgacon_switch(struct vc_data * c)5881da177e4SLinus Torvalds static int vgacon_switch(struct vc_data *c)
5891da177e4SLinus Torvalds {
59053dbb26dSAntonino A. Daplas int x = c->vc_cols * VGA_FONTWIDTH;
591860dafa9SMaciej W. Rozycki int y = c->vc_rows * c->vc_cell_height;
5923ea33510SH. Peter Anvin int rows = screen_info.orig_video_lines * vga_default_font_height/
593860dafa9SMaciej W. Rozycki c->vc_cell_height;
5941da177e4SLinus Torvalds /*
5951da177e4SLinus Torvalds * We need to save screen size here as it's the only way
5961da177e4SLinus Torvalds * we can spot the screen has been resized and we need to
5971da177e4SLinus Torvalds * set size of freshly allocated screens ourselves.
5981da177e4SLinus Torvalds */
5991da177e4SLinus Torvalds vga_video_num_columns = c->vc_cols;
6001da177e4SLinus Torvalds vga_video_num_lines = c->vc_rows;
601f18cd8f7SJames Simmons
602f18cd8f7SJames Simmons /* We can only copy out the size of the video buffer here,
603f18cd8f7SJames Simmons * otherwise we get into VGA BIOS */
604f18cd8f7SJames Simmons
60528254d43SSamuel Thibault if (!vga_is_gfx) {
6061da177e4SLinus Torvalds scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
60728254d43SSamuel Thibault c->vc_screenbuf_size > vga_vram_size ?
60828254d43SSamuel Thibault vga_vram_size : c->vc_screenbuf_size);
60953dbb26dSAntonino A. Daplas
61053dbb26dSAntonino A. Daplas if ((vgacon_xres != x || vgacon_yres != y) &&
61153dbb26dSAntonino A. Daplas (!(vga_video_num_columns % 2) &&
6123ea33510SH. Peter Anvin vga_video_num_columns <= screen_info.orig_video_cols &&
61353dbb26dSAntonino A. Daplas vga_video_num_lines <= rows))
61428254d43SSamuel Thibault vgacon_doresize(c, c->vc_cols, c->vc_rows);
61528254d43SSamuel Thibault }
61628254d43SSamuel Thibault
6171da177e4SLinus Torvalds return 0; /* Redrawing not needed */
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds
vga_set_palette(struct vc_data * vc,const unsigned char * table)6208ede5cceSJiri Slaby static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds int i, j;
6231da177e4SLinus Torvalds
62489f0244eSMark Rustad vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
6251da177e4SLinus Torvalds for (i = j = 0; i < 16; i++) {
62689f0244eSMark Rustad vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
62789f0244eSMark Rustad vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
62889f0244eSMark Rustad vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
62989f0244eSMark Rustad vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds }
6321da177e4SLinus Torvalds
vgacon_set_palette(struct vc_data * vc,const unsigned char * table)633709280daSJiri Slaby static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
6341da177e4SLinus Torvalds {
6351da177e4SLinus Torvalds if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
6366ca8dfd7SJiri Slaby || !con_is_visible(vc))
637709280daSJiri Slaby return;
6381da177e4SLinus Torvalds vga_set_palette(vc, table);
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds /* structure holding original VGA register settings */
6421da177e4SLinus Torvalds static struct {
6431da177e4SLinus Torvalds unsigned char SeqCtrlIndex; /* Sequencer Index reg. */
6441da177e4SLinus Torvalds unsigned char CrtCtrlIndex; /* CRT-Contr. Index reg. */
6451da177e4SLinus Torvalds unsigned char CrtMiscIO; /* Miscellaneous register */
6461da177e4SLinus Torvalds unsigned char HorizontalTotal; /* CRT-Controller:00h */
6471da177e4SLinus Torvalds unsigned char HorizDisplayEnd; /* CRT-Controller:01h */
6481da177e4SLinus Torvalds unsigned char StartHorizRetrace; /* CRT-Controller:04h */
6491da177e4SLinus Torvalds unsigned char EndHorizRetrace; /* CRT-Controller:05h */
6501da177e4SLinus Torvalds unsigned char Overflow; /* CRT-Controller:07h */
6511da177e4SLinus Torvalds unsigned char StartVertRetrace; /* CRT-Controller:10h */
6521da177e4SLinus Torvalds unsigned char EndVertRetrace; /* CRT-Controller:11h */
6531da177e4SLinus Torvalds unsigned char ModeControl; /* CRT-Controller:17h */
6541da177e4SLinus Torvalds unsigned char ClockingMode; /* Seq-Controller:01h */
6551da177e4SLinus Torvalds } vga_state;
6561da177e4SLinus Torvalds
vga_vesa_blank(struct vgastate * state,int mode)6571da177e4SLinus Torvalds static void vga_vesa_blank(struct vgastate *state, int mode)
6581da177e4SLinus Torvalds {
6591da177e4SLinus Torvalds /* save original values of VGA controller registers */
6601da177e4SLinus Torvalds if (!vga_vesa_blanked) {
6616b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
6621da177e4SLinus Torvalds vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
6631da177e4SLinus Torvalds vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
6641da177e4SLinus Torvalds vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
6656b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
6661da177e4SLinus Torvalds
6671da177e4SLinus Torvalds outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
6681da177e4SLinus Torvalds vga_state.HorizontalTotal = inb_p(vga_video_port_val);
6691da177e4SLinus Torvalds outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
6701da177e4SLinus Torvalds vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
6711da177e4SLinus Torvalds outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
6721da177e4SLinus Torvalds vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
6731da177e4SLinus Torvalds outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
6741da177e4SLinus Torvalds vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
6751da177e4SLinus Torvalds outb_p(0x07, vga_video_port_reg); /* Overflow */
6761da177e4SLinus Torvalds vga_state.Overflow = inb_p(vga_video_port_val);
6771da177e4SLinus Torvalds outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
6781da177e4SLinus Torvalds vga_state.StartVertRetrace = inb_p(vga_video_port_val);
6791da177e4SLinus Torvalds outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
6801da177e4SLinus Torvalds vga_state.EndVertRetrace = inb_p(vga_video_port_val);
6811da177e4SLinus Torvalds outb_p(0x17, vga_video_port_reg); /* ModeControl */
6821da177e4SLinus Torvalds vga_state.ModeControl = inb_p(vga_video_port_val);
6831da177e4SLinus Torvalds vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
6841da177e4SLinus Torvalds }
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds /* assure that video is enabled */
6871da177e4SLinus Torvalds /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
6886b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
6891da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
6901da177e4SLinus Torvalds
6911da177e4SLinus Torvalds /* test for vertical retrace in process.... */
6921da177e4SLinus Torvalds if ((vga_state.CrtMiscIO & 0x80) == 0x80)
6931da177e4SLinus Torvalds vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
6941da177e4SLinus Torvalds
6951da177e4SLinus Torvalds /*
6961da177e4SLinus Torvalds * Set <End of vertical retrace> to minimum (0) and
6971da177e4SLinus Torvalds * <Start of vertical Retrace> to maximum (incl. overflow)
6981da177e4SLinus Torvalds * Result: turn off vertical sync (VSync) pulse.
6991da177e4SLinus Torvalds */
7001da177e4SLinus Torvalds if (mode & VESA_VSYNC_SUSPEND) {
7011da177e4SLinus Torvalds outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
7021da177e4SLinus Torvalds outb_p(0xff, vga_video_port_val); /* maximum value */
7031da177e4SLinus Torvalds outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
7041da177e4SLinus Torvalds outb_p(0x40, vga_video_port_val); /* minimum (bits 0..3) */
7051da177e4SLinus Torvalds outb_p(0x07, vga_video_port_reg); /* Overflow */
7061da177e4SLinus Torvalds outb_p(vga_state.Overflow | 0x84, vga_video_port_val); /* bits 9,10 of vert. retrace */
7071da177e4SLinus Torvalds }
7081da177e4SLinus Torvalds
7091da177e4SLinus Torvalds if (mode & VESA_HSYNC_SUSPEND) {
7101da177e4SLinus Torvalds /*
7111da177e4SLinus Torvalds * Set <End of horizontal retrace> to minimum (0) and
7121da177e4SLinus Torvalds * <Start of horizontal Retrace> to maximum
7131da177e4SLinus Torvalds * Result: turn off horizontal sync (HSync) pulse.
7141da177e4SLinus Torvalds */
7151da177e4SLinus Torvalds outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
7161da177e4SLinus Torvalds outb_p(0xff, vga_video_port_val); /* maximum */
7171da177e4SLinus Torvalds outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
7181da177e4SLinus Torvalds outb_p(0x00, vga_video_port_val); /* minimum (0) */
7191da177e4SLinus Torvalds }
7201da177e4SLinus Torvalds
7211da177e4SLinus Torvalds /* restore both index registers */
7221da177e4SLinus Torvalds vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
7231da177e4SLinus Torvalds outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
7246b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
7251da177e4SLinus Torvalds }
7261da177e4SLinus Torvalds
vga_vesa_unblank(struct vgastate * state)7271da177e4SLinus Torvalds static void vga_vesa_unblank(struct vgastate *state)
7281da177e4SLinus Torvalds {
7291da177e4SLinus Torvalds /* restore original values of VGA controller registers */
7306b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
7311da177e4SLinus Torvalds vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
7321da177e4SLinus Torvalds
7331da177e4SLinus Torvalds outb_p(0x00, vga_video_port_reg); /* HorizontalTotal */
7341da177e4SLinus Torvalds outb_p(vga_state.HorizontalTotal, vga_video_port_val);
7351da177e4SLinus Torvalds outb_p(0x01, vga_video_port_reg); /* HorizDisplayEnd */
7361da177e4SLinus Torvalds outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
7371da177e4SLinus Torvalds outb_p(0x04, vga_video_port_reg); /* StartHorizRetrace */
7381da177e4SLinus Torvalds outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
7391da177e4SLinus Torvalds outb_p(0x05, vga_video_port_reg); /* EndHorizRetrace */
7401da177e4SLinus Torvalds outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
7411da177e4SLinus Torvalds outb_p(0x07, vga_video_port_reg); /* Overflow */
7421da177e4SLinus Torvalds outb_p(vga_state.Overflow, vga_video_port_val);
7431da177e4SLinus Torvalds outb_p(0x10, vga_video_port_reg); /* StartVertRetrace */
7441da177e4SLinus Torvalds outb_p(vga_state.StartVertRetrace, vga_video_port_val);
7451da177e4SLinus Torvalds outb_p(0x11, vga_video_port_reg); /* EndVertRetrace */
7461da177e4SLinus Torvalds outb_p(vga_state.EndVertRetrace, vga_video_port_val);
7471da177e4SLinus Torvalds outb_p(0x17, vga_video_port_reg); /* ModeControl */
7481da177e4SLinus Torvalds outb_p(vga_state.ModeControl, vga_video_port_val);
7491da177e4SLinus Torvalds /* ClockingMode */
7501da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds /* restore index/control registers */
7531da177e4SLinus Torvalds vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
7541da177e4SLinus Torvalds outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
7556b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds
vga_pal_blank(struct vgastate * state)7581da177e4SLinus Torvalds static void vga_pal_blank(struct vgastate *state)
7591da177e4SLinus Torvalds {
7601da177e4SLinus Torvalds int i;
7611da177e4SLinus Torvalds
7621a66ddcbSPozsar Balazs vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
7631da177e4SLinus Torvalds for (i = 0; i < 16; i++) {
7641da177e4SLinus Torvalds vga_w(state->vgabase, VGA_PEL_IW, i);
7651da177e4SLinus Torvalds vga_w(state->vgabase, VGA_PEL_D, 0);
7661da177e4SLinus Torvalds vga_w(state->vgabase, VGA_PEL_D, 0);
7671da177e4SLinus Torvalds vga_w(state->vgabase, VGA_PEL_D, 0);
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds }
7701da177e4SLinus Torvalds
vgacon_blank(struct vc_data * c,int blank,int mode_switch)7711da177e4SLinus Torvalds static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
7721da177e4SLinus Torvalds {
7731da177e4SLinus Torvalds switch (blank) {
7741da177e4SLinus Torvalds case 0: /* Unblank */
7751da177e4SLinus Torvalds if (vga_vesa_blanked) {
77689f0244eSMark Rustad vga_vesa_unblank(&vgastate);
7771da177e4SLinus Torvalds vga_vesa_blanked = 0;
7781da177e4SLinus Torvalds }
7791da177e4SLinus Torvalds if (vga_palette_blanked) {
7801da177e4SLinus Torvalds vga_set_palette(c, color_table);
78196fd9554SJiri Slaby vga_palette_blanked = false;
7821da177e4SLinus Torvalds return 0;
7831da177e4SLinus Torvalds }
78496fd9554SJiri Slaby vga_is_gfx = false;
7851da177e4SLinus Torvalds /* Tell console.c that it has to restore the screen itself */
7861da177e4SLinus Torvalds return 1;
7871da177e4SLinus Torvalds case 1: /* Normal blanking */
7881da177e4SLinus Torvalds case -1: /* Obsolete */
7891da177e4SLinus Torvalds if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
79089f0244eSMark Rustad vga_pal_blank(&vgastate);
79196fd9554SJiri Slaby vga_palette_blanked = true;
7921da177e4SLinus Torvalds return 0;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds vgacon_set_origin(c);
7951da177e4SLinus Torvalds scr_memsetw((void *) vga_vram_base, BLANK,
7961da177e4SLinus Torvalds c->vc_screenbuf_size);
7971da177e4SLinus Torvalds if (mode_switch)
79896fd9554SJiri Slaby vga_is_gfx = true;
7991da177e4SLinus Torvalds return 1;
8001da177e4SLinus Torvalds default: /* VESA blanking */
8011da177e4SLinus Torvalds if (vga_video_type == VIDEO_TYPE_VGAC) {
80289f0244eSMark Rustad vga_vesa_blank(&vgastate, blank - 1);
8031da177e4SLinus Torvalds vga_vesa_blanked = blank;
8041da177e4SLinus Torvalds }
8051da177e4SLinus Torvalds return 0;
8061da177e4SLinus Torvalds }
8071da177e4SLinus Torvalds }
8081da177e4SLinus Torvalds
8091da177e4SLinus Torvalds /*
8101da177e4SLinus Torvalds * PIO_FONT support.
8111da177e4SLinus Torvalds *
8121da177e4SLinus Torvalds * The font loading code goes back to the codepage package by
8131da177e4SLinus Torvalds * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
8141da177e4SLinus Torvalds * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
8151da177e4SLinus Torvalds * Video Systems_ by Richard Wilton. 1987. Microsoft Press".)
8161da177e4SLinus Torvalds *
8171da177e4SLinus Torvalds * Change for certain monochrome monitors by Yury Shevchuck
8181da177e4SLinus Torvalds * (sizif@botik.yaroslavl.su).
8191da177e4SLinus Torvalds */
8201da177e4SLinus Torvalds
8211da177e4SLinus Torvalds #define colourmap 0xa0000
8221da177e4SLinus Torvalds /* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
8231da177e4SLinus Torvalds should use 0xA0000 for the bwmap as well.. */
8241da177e4SLinus Torvalds #define blackwmap 0xa0000
8251da177e4SLinus Torvalds #define cmapsz 8192
8261da177e4SLinus Torvalds
vgacon_do_font_op(struct vgastate * state,char * arg,int set,bool ch512)82796fd9554SJiri Slaby static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
82896fd9554SJiri Slaby bool ch512)
8291da177e4SLinus Torvalds {
8301da177e4SLinus Torvalds unsigned short video_port_status = vga_video_port_reg + 6;
8311da177e4SLinus Torvalds int font_select = 0x00, beg, i;
8321da177e4SLinus Torvalds char *charmap;
8332a248307SDave Airlie bool clear_attribs = false;
8341da177e4SLinus Torvalds if (vga_video_type != VIDEO_TYPE_EGAM) {
8354f1bcaf0SBjorn Helgaas charmap = (char *) VGA_MAP_MEM(colourmap, 0);
8361da177e4SLinus Torvalds beg = 0x0e;
8371da177e4SLinus Torvalds } else {
8384f1bcaf0SBjorn Helgaas charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
8391da177e4SLinus Torvalds beg = 0x0a;
8401da177e4SLinus Torvalds }
8411da177e4SLinus Torvalds
8421da177e4SLinus Torvalds /*
8431da177e4SLinus Torvalds * All fonts are loaded in slot 0 (0:1 for 512 ch)
8441da177e4SLinus Torvalds */
8451da177e4SLinus Torvalds
8461da177e4SLinus Torvalds if (!arg)
8471da177e4SLinus Torvalds return -EINVAL; /* Return to default font not supported */
8481da177e4SLinus Torvalds
8491da177e4SLinus Torvalds font_select = ch512 ? 0x04 : 0x00;
8501da177e4SLinus Torvalds
8516b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
8521da177e4SLinus Torvalds /* First, the Sequencer */
8531da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
8541da177e4SLinus Torvalds /* CPU writes only to map 2 */
8551da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
8561da177e4SLinus Torvalds /* Sequential addressing */
8571da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
8581da177e4SLinus Torvalds /* Clear synchronous reset */
8591da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
8601da177e4SLinus Torvalds
8611da177e4SLinus Torvalds /* Now, the graphics controller, select map 2 */
8621da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
8631da177e4SLinus Torvalds /* disable odd-even addressing */
8641da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
8651da177e4SLinus Torvalds /* map start at A000:0000 */
8661da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
8676b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
8681da177e4SLinus Torvalds
8691da177e4SLinus Torvalds if (arg) {
8701da177e4SLinus Torvalds if (set)
8717e6d72c1SMarcelo Tosatti for (i = 0; i < cmapsz; i++) {
8721da177e4SLinus Torvalds vga_writeb(arg[i], charmap + i);
8737e6d72c1SMarcelo Tosatti cond_resched();
8747e6d72c1SMarcelo Tosatti }
8751da177e4SLinus Torvalds else
8767e6d72c1SMarcelo Tosatti for (i = 0; i < cmapsz; i++) {
8771da177e4SLinus Torvalds arg[i] = vga_readb(charmap + i);
8787e6d72c1SMarcelo Tosatti cond_resched();
8797e6d72c1SMarcelo Tosatti }
8801da177e4SLinus Torvalds
8811da177e4SLinus Torvalds /*
8821da177e4SLinus Torvalds * In 512-character mode, the character map is not contiguous if
8831da177e4SLinus Torvalds * we want to remain EGA compatible -- which we do
8841da177e4SLinus Torvalds */
8851da177e4SLinus Torvalds
8861da177e4SLinus Torvalds if (ch512) {
8871da177e4SLinus Torvalds charmap += 2 * cmapsz;
8881da177e4SLinus Torvalds arg += cmapsz;
8891da177e4SLinus Torvalds if (set)
8907e6d72c1SMarcelo Tosatti for (i = 0; i < cmapsz; i++) {
8911da177e4SLinus Torvalds vga_writeb(arg[i], charmap + i);
8927e6d72c1SMarcelo Tosatti cond_resched();
8937e6d72c1SMarcelo Tosatti }
8941da177e4SLinus Torvalds else
8957e6d72c1SMarcelo Tosatti for (i = 0; i < cmapsz; i++) {
8961da177e4SLinus Torvalds arg[i] = vga_readb(charmap + i);
8977e6d72c1SMarcelo Tosatti cond_resched();
8987e6d72c1SMarcelo Tosatti }
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds }
9011da177e4SLinus Torvalds
9026b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
9031da177e4SLinus Torvalds /* First, the sequencer, Synchronous reset */
9041da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
9051da177e4SLinus Torvalds /* CPU writes to maps 0 and 1 */
9061da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
9071da177e4SLinus Torvalds /* odd-even addressing */
9081da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
9091da177e4SLinus Torvalds /* Character Map Select */
9101da177e4SLinus Torvalds if (set)
9111da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
9121da177e4SLinus Torvalds /* clear synchronous reset */
9131da177e4SLinus Torvalds vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
9141da177e4SLinus Torvalds
9151da177e4SLinus Torvalds /* Now, the graphics controller, select map 0 for CPU */
9161da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
9171da177e4SLinus Torvalds /* enable even-odd addressing */
9181da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
9191da177e4SLinus Torvalds /* map starts at b800:0 or b000:0 */
9201da177e4SLinus Torvalds vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
9211da177e4SLinus Torvalds
9221da177e4SLinus Torvalds /* if 512 char mode is already enabled don't re-enable it. */
9231da177e4SLinus Torvalds if ((set) && (ch512 != vga_512_chars)) {
9241da177e4SLinus Torvalds vga_512_chars = ch512;
9251da177e4SLinus Torvalds /* 256-char: enable intensity bit
9261da177e4SLinus Torvalds 512-char: disable intensity bit */
9271da177e4SLinus Torvalds inb_p(video_port_status); /* clear address flip-flop */
9281da177e4SLinus Torvalds /* color plane enable register */
9291da177e4SLinus Torvalds vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
9301da177e4SLinus Torvalds /* Wilton (1987) mentions the following; I don't know what
9311da177e4SLinus Torvalds it means, but it works, and it appears necessary */
9321da177e4SLinus Torvalds inb_p(video_port_status);
9331da177e4SLinus Torvalds vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
9342a248307SDave Airlie clear_attribs = true;
9351da177e4SLinus Torvalds }
9366b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
9372a248307SDave Airlie
9382a248307SDave Airlie if (clear_attribs) {
9392a248307SDave Airlie for (i = 0; i < MAX_NR_CONSOLES; i++) {
9402a248307SDave Airlie struct vc_data *c = vc_cons[i].d;
9412a248307SDave Airlie if (c && c->vc_sw == &vga_con) {
9422a248307SDave Airlie /* force hi font mask to 0, so we always clear
9432a248307SDave Airlie the bit on either transition */
9442a248307SDave Airlie c->vc_hi_font_mask = 0x00;
9452a248307SDave Airlie clear_buffer_attributes(c);
9462a248307SDave Airlie c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
9472a248307SDave Airlie }
9482a248307SDave Airlie }
9492a248307SDave Airlie }
9501da177e4SLinus Torvalds return 0;
9511da177e4SLinus Torvalds }
9521da177e4SLinus Torvalds
9531da177e4SLinus Torvalds /*
9541da177e4SLinus Torvalds * Adjust the screen to fit a font of a certain height
9551da177e4SLinus Torvalds */
vgacon_adjust_height(struct vc_data * vc,unsigned fontheight)9561da177e4SLinus Torvalds static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds unsigned char ovr, vde, fsr;
9591da177e4SLinus Torvalds int rows, maxscan, i;
9601da177e4SLinus Torvalds
9611da177e4SLinus Torvalds rows = vc->vc_scan_lines / fontheight; /* Number of video rows we end up with */
9621da177e4SLinus Torvalds maxscan = rows * fontheight - 1; /* Scan lines to actually display-1 */
9631da177e4SLinus Torvalds
9641da177e4SLinus Torvalds /* Reprogram the CRTC for the new font size
9651da177e4SLinus Torvalds Note: the attempt to read the overflow register will fail
9661da177e4SLinus Torvalds on an EGA, but using 0xff for the previous value appears to
9671da177e4SLinus Torvalds be OK for EGA text modes in the range 257-512 scan lines, so I
9681da177e4SLinus Torvalds guess we don't need to worry about it.
9691da177e4SLinus Torvalds
9701da177e4SLinus Torvalds The same applies for the spill bits in the font size and cursor
9711da177e4SLinus Torvalds registers; they are write-only on EGA, but it appears that they
9721da177e4SLinus Torvalds are all don't care bits on EGA, so I guess it doesn't matter. */
9731da177e4SLinus Torvalds
9746b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
9751da177e4SLinus Torvalds outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
9761da177e4SLinus Torvalds ovr = inb_p(vga_video_port_val);
9771da177e4SLinus Torvalds outb_p(0x09, vga_video_port_reg); /* Font size register */
9781da177e4SLinus Torvalds fsr = inb_p(vga_video_port_val);
9796b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
9801da177e4SLinus Torvalds
9811da177e4SLinus Torvalds vde = maxscan & 0xff; /* Vertical display end reg */
9821da177e4SLinus Torvalds ovr = (ovr & 0xbd) + /* Overflow register */
9831da177e4SLinus Torvalds ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
9841da177e4SLinus Torvalds fsr = (fsr & 0xe0) + (fontheight - 1); /* Font size register */
9851da177e4SLinus Torvalds
9866b2c1800SThomas Gleixner raw_spin_lock_irq(&vga_lock);
9871da177e4SLinus Torvalds outb_p(0x07, vga_video_port_reg); /* CRTC overflow register */
9881da177e4SLinus Torvalds outb_p(ovr, vga_video_port_val);
9891da177e4SLinus Torvalds outb_p(0x09, vga_video_port_reg); /* Font size */
9901da177e4SLinus Torvalds outb_p(fsr, vga_video_port_val);
9911da177e4SLinus Torvalds outb_p(0x12, vga_video_port_reg); /* Vertical display limit */
9921da177e4SLinus Torvalds outb_p(vde, vga_video_port_val);
9936b2c1800SThomas Gleixner raw_spin_unlock_irq(&vga_lock);
9945ef897c7SAntonino A. Daplas vga_video_font_height = fontheight;
9951da177e4SLinus Torvalds
9961da177e4SLinus Torvalds for (i = 0; i < MAX_NR_CONSOLES; i++) {
9971da177e4SLinus Torvalds struct vc_data *c = vc_cons[i].d;
9981da177e4SLinus Torvalds
9991da177e4SLinus Torvalds if (c && c->vc_sw == &vga_con) {
10006ca8dfd7SJiri Slaby if (con_is_visible(c)) {
10011da177e4SLinus Torvalds /* void size to cause regs to be rewritten */
10021da177e4SLinus Torvalds cursor_size_lastfrom = 0;
10031da177e4SLinus Torvalds cursor_size_lastto = 0;
10041da177e4SLinus Torvalds c->vc_sw->con_cursor(c, CM_DRAW);
10051da177e4SLinus Torvalds }
1006860dafa9SMaciej W. Rozycki c->vc_font.height = c->vc_cell_height = fontheight;
10071da177e4SLinus Torvalds vc_resize(c, 0, rows); /* Adjust console size */
10081da177e4SLinus Torvalds }
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds return 0;
10111da177e4SLinus Torvalds }
10121da177e4SLinus Torvalds
vgacon_font_set(struct vc_data * c,struct console_font * font,unsigned int vpitch,unsigned int flags)1013c396a5bfSKees Cook static int vgacon_font_set(struct vc_data *c, struct console_font *font,
1014ffc1e089SSamuel Thibault unsigned int vpitch, unsigned int flags)
10151da177e4SLinus Torvalds {
10161da177e4SLinus Torvalds unsigned charcount = font->charcount;
10171da177e4SLinus Torvalds int rc;
10181da177e4SLinus Torvalds
10191da177e4SLinus Torvalds if (vga_video_type < VIDEO_TYPE_EGAM)
10201da177e4SLinus Torvalds return -EINVAL;
10211da177e4SLinus Torvalds
102205e2600cSSamuel Thibault if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
102353dbb26dSAntonino A. Daplas (charcount != 256 && charcount != 512))
10241da177e4SLinus Torvalds return -EINVAL;
10251da177e4SLinus Torvalds
102689f0244eSMark Rustad rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
10271da177e4SLinus Torvalds if (rc)
10281da177e4SLinus Torvalds return rc;
10291da177e4SLinus Torvalds
10301da177e4SLinus Torvalds if (!(flags & KD_FONT_FLAG_DONT_RECALC))
10311da177e4SLinus Torvalds rc = vgacon_adjust_height(c, font->height);
10321da177e4SLinus Torvalds return rc;
10331da177e4SLinus Torvalds }
10341da177e4SLinus Torvalds
vgacon_font_get(struct vc_data * c,struct console_font * font,unsigned int vpitch)1035ffc1e089SSamuel Thibault static int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
10361da177e4SLinus Torvalds {
1037ffc1e089SSamuel Thibault if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
10381da177e4SLinus Torvalds return -EINVAL;
10391da177e4SLinus Torvalds
104053dbb26dSAntonino A. Daplas font->width = VGA_FONTWIDTH;
10411da177e4SLinus Torvalds font->height = c->vc_font.height;
10421da177e4SLinus Torvalds font->charcount = vga_512_chars ? 512 : 256;
10431da177e4SLinus Torvalds if (!font->data)
10441da177e4SLinus Torvalds return 0;
104589f0244eSMark Rustad return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
10461da177e4SLinus Torvalds }
10471da177e4SLinus Torvalds
vgacon_resize(struct vc_data * c,unsigned int width,unsigned int height,unsigned int user)104828254d43SSamuel Thibault static int vgacon_resize(struct vc_data *c, unsigned int width,
1049e400b6ecSAntonino A. Daplas unsigned int height, unsigned int user)
105028254d43SSamuel Thibault {
1051513dc792SZhang Xiaoxu if ((width << 1) * height > vga_vram_size)
1052513dc792SZhang Xiaoxu return -EINVAL;
1053513dc792SZhang Xiaoxu
1054d4d0ad57SMaciej W. Rozycki if (user) {
1055d4d0ad57SMaciej W. Rozycki /*
1056d4d0ad57SMaciej W. Rozycki * Ho ho! Someone (svgatextmode, eh?) may have reprogrammed
1057d4d0ad57SMaciej W. Rozycki * the video mode! Set the new defaults then and go away.
1058d4d0ad57SMaciej W. Rozycki */
1059d4d0ad57SMaciej W. Rozycki screen_info.orig_video_cols = width;
1060d4d0ad57SMaciej W. Rozycki screen_info.orig_video_lines = height;
1061860dafa9SMaciej W. Rozycki vga_default_font_height = c->vc_cell_height;
1062d4d0ad57SMaciej W. Rozycki return 0;
1063d4d0ad57SMaciej W. Rozycki }
10643ea33510SH. Peter Anvin if (width % 2 || width > screen_info.orig_video_cols ||
10653ea33510SH. Peter Anvin height > (screen_info.orig_video_lines * vga_default_font_height)/
1066860dafa9SMaciej W. Rozycki c->vc_cell_height)
1067d4d0ad57SMaciej W. Rozycki return -EINVAL;
106828254d43SSamuel Thibault
10696ca8dfd7SJiri Slaby if (con_is_visible(c) && !vga_is_gfx) /* who knows */
107028254d43SSamuel Thibault vgacon_doresize(c, width, height);
107128254d43SSamuel Thibault return 0;
107228254d43SSamuel Thibault }
107328254d43SSamuel Thibault
vgacon_set_origin(struct vc_data * c)10741da177e4SLinus Torvalds static int vgacon_set_origin(struct vc_data *c)
10751da177e4SLinus Torvalds {
10761da177e4SLinus Torvalds if (vga_is_gfx || /* We don't play origin tricks in graphic modes */
10771da177e4SLinus Torvalds (console_blanked && !vga_palette_blanked)) /* Nor we write to blanked screens */
10781da177e4SLinus Torvalds return 0;
10791da177e4SLinus Torvalds c->vc_origin = c->vc_visible_origin = vga_vram_base;
10801da177e4SLinus Torvalds vga_set_mem_top(c);
10811da177e4SLinus Torvalds vga_rolled_over = 0;
10821da177e4SLinus Torvalds return 1;
10831da177e4SLinus Torvalds }
10841da177e4SLinus Torvalds
vgacon_save_screen(struct vc_data * c)10851da177e4SLinus Torvalds static void vgacon_save_screen(struct vc_data *c)
10861da177e4SLinus Torvalds {
10871da177e4SLinus Torvalds static int vga_bootup_console = 0;
10881da177e4SLinus Torvalds
10891da177e4SLinus Torvalds if (!vga_bootup_console) {
10901da177e4SLinus Torvalds /* This is a gross hack, but here is the only place we can
10911da177e4SLinus Torvalds * set bootup console parameters without messing up generic
10921da177e4SLinus Torvalds * console initialization routines.
10931da177e4SLinus Torvalds */
10941da177e4SLinus Torvalds vga_bootup_console = 1;
109528bc24fcSJiri Slaby c->state.x = screen_info.orig_x;
109628bc24fcSJiri Slaby c->state.y = screen_info.orig_y;
10971da177e4SLinus Torvalds }
1098f18cd8f7SJames Simmons
1099025dfdafSFrederik Schwarzer /* We can't copy in more than the size of the video buffer,
1100f18cd8f7SJames Simmons * or we'll be copying in VGA BIOS */
1101f18cd8f7SJames Simmons
11021da177e4SLinus Torvalds if (!vga_is_gfx)
11031da177e4SLinus Torvalds scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
1104f18cd8f7SJames Simmons c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
11051da177e4SLinus Torvalds }
11061da177e4SLinus Torvalds
vgacon_scroll(struct vc_data * c,unsigned int t,unsigned int b,enum con_scroll dir,unsigned int lines)1107d705ff38SJiri Slaby static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
1108d705ff38SJiri Slaby enum con_scroll dir, unsigned int lines)
11091da177e4SLinus Torvalds {
11101da177e4SLinus Torvalds unsigned long oldo;
11111da177e4SLinus Torvalds unsigned int delta;
11121da177e4SLinus Torvalds
11132ae85477SAntonino A. Daplas if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
1114d705ff38SJiri Slaby return false;
11151da177e4SLinus Torvalds
11161da177e4SLinus Torvalds if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
1117d705ff38SJiri Slaby return false;
11181da177e4SLinus Torvalds
111915bdab95SAntonino A. Daplas vgacon_restore_screen(c);
11201da177e4SLinus Torvalds oldo = c->vc_origin;
11211da177e4SLinus Torvalds delta = lines * c->vc_size_row;
11221da177e4SLinus Torvalds if (dir == SM_UP) {
11231da177e4SLinus Torvalds if (c->vc_scr_end + delta >= vga_vram_end) {
11241da177e4SLinus Torvalds scr_memcpyw((u16 *) vga_vram_base,
11251da177e4SLinus Torvalds (u16 *) (oldo + delta),
11261da177e4SLinus Torvalds c->vc_screenbuf_size - delta);
11271da177e4SLinus Torvalds c->vc_origin = vga_vram_base;
11281da177e4SLinus Torvalds vga_rolled_over = oldo - vga_vram_base;
11291da177e4SLinus Torvalds } else
11301da177e4SLinus Torvalds c->vc_origin += delta;
11311da177e4SLinus Torvalds scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
113293f78da4SLinus Torvalds delta), c->vc_video_erase_char,
11331da177e4SLinus Torvalds delta);
11341da177e4SLinus Torvalds } else {
11351da177e4SLinus Torvalds if (oldo - delta < vga_vram_base) {
11361da177e4SLinus Torvalds scr_memmovew((u16 *) (vga_vram_end -
11371da177e4SLinus Torvalds c->vc_screenbuf_size +
11381da177e4SLinus Torvalds delta), (u16 *) oldo,
11391da177e4SLinus Torvalds c->vc_screenbuf_size - delta);
11401da177e4SLinus Torvalds c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
11411da177e4SLinus Torvalds vga_rolled_over = 0;
11421da177e4SLinus Torvalds } else
11431da177e4SLinus Torvalds c->vc_origin -= delta;
11441da177e4SLinus Torvalds c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
114593f78da4SLinus Torvalds scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
11461da177e4SLinus Torvalds delta);
11471da177e4SLinus Torvalds }
11481da177e4SLinus Torvalds c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
11491da177e4SLinus Torvalds c->vc_visible_origin = c->vc_origin;
11501da177e4SLinus Torvalds vga_set_mem_top(c);
11511da177e4SLinus Torvalds c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
1152d705ff38SJiri Slaby return true;
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds
11551da177e4SLinus Torvalds /*
11561da177e4SLinus Torvalds * The console `switch' structure for the VGA based console
11571da177e4SLinus Torvalds */
11581da177e4SLinus Torvalds
vgacon_clear(struct vc_data * vc,int sy,int sx,int height,int width)1159c396a5bfSKees Cook static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
1160c396a5bfSKees Cook int width) { }
vgacon_putc(struct vc_data * vc,int c,int ypos,int xpos)1161c396a5bfSKees Cook static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
vgacon_putcs(struct vc_data * vc,const unsigned short * s,int count,int ypos,int xpos)1162c396a5bfSKees Cook static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
1163c396a5bfSKees Cook int count, int ypos, int xpos) { }
11641da177e4SLinus Torvalds
11651da177e4SLinus Torvalds const struct consw vga_con = {
11661da177e4SLinus Torvalds .owner = THIS_MODULE,
11671da177e4SLinus Torvalds .con_startup = vgacon_startup,
11681da177e4SLinus Torvalds .con_init = vgacon_init,
11691da177e4SLinus Torvalds .con_deinit = vgacon_deinit,
1170c396a5bfSKees Cook .con_clear = vgacon_clear,
1171c396a5bfSKees Cook .con_putc = vgacon_putc,
1172c396a5bfSKees Cook .con_putcs = vgacon_putcs,
11731da177e4SLinus Torvalds .con_cursor = vgacon_cursor,
11741da177e4SLinus Torvalds .con_scroll = vgacon_scroll,
11751da177e4SLinus Torvalds .con_switch = vgacon_switch,
11761da177e4SLinus Torvalds .con_blank = vgacon_blank,
11771da177e4SLinus Torvalds .con_font_set = vgacon_font_set,
11781da177e4SLinus Torvalds .con_font_get = vgacon_font_get,
117928254d43SSamuel Thibault .con_resize = vgacon_resize,
11801da177e4SLinus Torvalds .con_set_palette = vgacon_set_palette,
11811da177e4SLinus Torvalds .con_scrolldelta = vgacon_scrolldelta,
11821da177e4SLinus Torvalds .con_set_origin = vgacon_set_origin,
11831da177e4SLinus Torvalds .con_save_screen = vgacon_save_screen,
11841da177e4SLinus Torvalds .con_build_attr = vgacon_build_attr,
11851da177e4SLinus Torvalds .con_invert_region = vgacon_invert_region,
11861da177e4SLinus Torvalds };
1187a4de0526SDaniel Vetter EXPORT_SYMBOL(vga_con);
11881da177e4SLinus Torvalds
11891da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1190