162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  linux/drivers/video/vgacon.c -- Low level VGA based console driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *	Created 28 Sep 1997 by Geert Uytterhoeven
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *	Copyright (C) 1991, 1992  Linus Torvalds
1162306a36Sopenharmony_ci *			    1995  Jay Estabrook
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci *	User definable mapping table and font loading by Eugene G. Crosser,
1462306a36Sopenharmony_ci *	<crosser@average.org>
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *	Improved loadable font/UTF-8 support by H. Peter Anvin
1762306a36Sopenharmony_ci *	Feb-Sep 1995 <peter.anvin@linux.org>
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *	Colour palette handling, by Simon Tatham
2062306a36Sopenharmony_ci *	17-Jun-95 <sgt20@cam.ac.uk>
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci *	if 512 char mode is already enabled don't re-enable it,
2362306a36Sopenharmony_ci *	because it causes screen to flicker, by Mitja Horvat
2462306a36Sopenharmony_ci *	5-May-96 <mitja.horvat@guest.arnes.si>
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *	Use 2 outw instead of 4 outb_p to reduce erroneous text
2762306a36Sopenharmony_ci *	flashing on RHS of screen during heavy console scrolling .
2862306a36Sopenharmony_ci *	Oct 1996, Paul Gortmaker.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *  This file is subject to the terms and conditions of the GNU General Public
3262306a36Sopenharmony_ci *  License.  See the file COPYING in the main directory of this archive for
3362306a36Sopenharmony_ci *  more details.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/module.h>
3762306a36Sopenharmony_ci#include <linux/types.h>
3862306a36Sopenharmony_ci#include <linux/fs.h>
3962306a36Sopenharmony_ci#include <linux/kernel.h>
4062306a36Sopenharmony_ci#include <linux/console.h>
4162306a36Sopenharmony_ci#include <linux/string.h>
4262306a36Sopenharmony_ci#include <linux/kd.h>
4362306a36Sopenharmony_ci#include <linux/slab.h>
4462306a36Sopenharmony_ci#include <linux/vt_kern.h>
4562306a36Sopenharmony_ci#include <linux/sched.h>
4662306a36Sopenharmony_ci#include <linux/selection.h>
4762306a36Sopenharmony_ci#include <linux/spinlock.h>
4862306a36Sopenharmony_ci#include <linux/ioport.h>
4962306a36Sopenharmony_ci#include <linux/init.h>
5062306a36Sopenharmony_ci#include <linux/screen_info.h>
5162306a36Sopenharmony_ci#include <video/vga.h>
5262306a36Sopenharmony_ci#include <asm/io.h>
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(vga_lock);
5562306a36Sopenharmony_cistatic int cursor_size_lastfrom;
5662306a36Sopenharmony_cistatic int cursor_size_lastto;
5762306a36Sopenharmony_cistatic u32 vgacon_xres;
5862306a36Sopenharmony_cistatic u32 vgacon_yres;
5962306a36Sopenharmony_cistatic struct vgastate vgastate;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define BLANK 0x0020
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci *  Interface used by the world
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int vgacon_set_origin(struct vc_data *c);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic struct uni_pagedict *vgacon_uni_pagedir;
7162306a36Sopenharmony_cistatic int vgacon_refcount;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Description of the hardware situation */
7462306a36Sopenharmony_cistatic unsigned long	vga_vram_base		__read_mostly;	/* Base of video memory */
7562306a36Sopenharmony_cistatic unsigned long	vga_vram_end		__read_mostly;	/* End of video memory */
7662306a36Sopenharmony_cistatic unsigned int	vga_vram_size		__read_mostly;	/* Size of video memory */
7762306a36Sopenharmony_cistatic u16		vga_video_port_reg	__read_mostly;	/* Video register select port */
7862306a36Sopenharmony_cistatic u16		vga_video_port_val	__read_mostly;	/* Video register value port */
7962306a36Sopenharmony_cistatic unsigned int	vga_video_num_columns;			/* Number of text columns */
8062306a36Sopenharmony_cistatic unsigned int	vga_video_num_lines;			/* Number of text lines */
8162306a36Sopenharmony_cistatic bool		vga_can_do_color;			/* Do we support colors? */
8262306a36Sopenharmony_cistatic unsigned int	vga_default_font_height __read_mostly;	/* Height of default screen font */
8362306a36Sopenharmony_cistatic unsigned char	vga_video_type		__read_mostly;	/* Card type */
8462306a36Sopenharmony_cistatic int		vga_vesa_blanked;
8562306a36Sopenharmony_cistatic bool 		vga_palette_blanked;
8662306a36Sopenharmony_cistatic bool 		vga_is_gfx;
8762306a36Sopenharmony_cistatic bool 		vga_512_chars;
8862306a36Sopenharmony_cistatic int 		vga_video_font_height;
8962306a36Sopenharmony_cistatic int 		vga_scan_lines		__read_mostly;
9062306a36Sopenharmony_cistatic unsigned int 	vga_rolled_over; /* last vc_origin offset before wrap */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic bool vga_hardscroll_enabled;
9362306a36Sopenharmony_cistatic bool vga_hardscroll_user_enable = true;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int __init no_scroll(char *str)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	/*
9862306a36Sopenharmony_ci	 * Disabling scrollback is required for the Braillex ib80-piezo
9962306a36Sopenharmony_ci	 * Braille reader made by F.H. Papenmeier (Germany).
10062306a36Sopenharmony_ci	 * Use the "no-scroll" bootflag.
10162306a36Sopenharmony_ci	 */
10262306a36Sopenharmony_ci	vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
10362306a36Sopenharmony_ci	return 1;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci__setup("no-scroll", no_scroll);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * By replacing the four outb_p with two back to back outw, we can reduce
11062306a36Sopenharmony_ci * the window of opportunity to see text mislocated to the RHS of the
11162306a36Sopenharmony_ci * console during heavy scrolling activity. However there is the remote
11262306a36Sopenharmony_ci * possibility that some pre-dinosaur hardware won't like the back to back
11362306a36Sopenharmony_ci * I/O. Since the Xservers get away with it, we should be able to as well.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_cistatic inline void write_vga(unsigned char reg, unsigned int val)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	unsigned int v1, v2;
11862306a36Sopenharmony_ci	unsigned long flags;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/*
12162306a36Sopenharmony_ci	 * ddprintk might set the console position from interrupt
12262306a36Sopenharmony_ci	 * handlers, thus the write has to be IRQ-atomic.
12362306a36Sopenharmony_ci	 */
12462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&vga_lock, flags);
12562306a36Sopenharmony_ci	v1 = reg + (val & 0xff00);
12662306a36Sopenharmony_ci	v2 = reg + 1 + ((val << 8) & 0xff00);
12762306a36Sopenharmony_ci	outw(v1, vga_video_port_reg);
12862306a36Sopenharmony_ci	outw(v2, vga_video_port_reg);
12962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&vga_lock, flags);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic inline void vga_set_mem_top(struct vc_data *c)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void vgacon_scrolldelta(struct vc_data *c, int lines)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
14062306a36Sopenharmony_ci			vga_vram_size);
14162306a36Sopenharmony_ci	vga_set_mem_top(c);
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic void vgacon_restore_screen(struct vc_data *c)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	if (c->vc_origin != c->vc_visible_origin)
14762306a36Sopenharmony_ci		vgacon_scrolldelta(c, 0);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic const char *vgacon_startup(void)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	const char *display_desc = NULL;
15362306a36Sopenharmony_ci	u16 saved1, saved2;
15462306a36Sopenharmony_ci	volatile u16 *p;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
15762306a36Sopenharmony_ci	    screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
15862306a36Sopenharmony_ci	      no_vga:
15962306a36Sopenharmony_ci#ifdef CONFIG_DUMMY_CONSOLE
16062306a36Sopenharmony_ci		conswitchp = &dummy_con;
16162306a36Sopenharmony_ci		return conswitchp->con_startup();
16262306a36Sopenharmony_ci#else
16362306a36Sopenharmony_ci		return NULL;
16462306a36Sopenharmony_ci#endif
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* boot_params.screen_info reasonably initialized? */
16862306a36Sopenharmony_ci	if ((screen_info.orig_video_lines == 0) ||
16962306a36Sopenharmony_ci	    (screen_info.orig_video_cols  == 0))
17062306a36Sopenharmony_ci		goto no_vga;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* VGA16 modes are not handled by VGACON */
17362306a36Sopenharmony_ci	if ((screen_info.orig_video_mode == 0x0D) ||	/* 320x200/4 */
17462306a36Sopenharmony_ci	    (screen_info.orig_video_mode == 0x0E) ||	/* 640x200/4 */
17562306a36Sopenharmony_ci	    (screen_info.orig_video_mode == 0x10) ||	/* 640x350/4 */
17662306a36Sopenharmony_ci	    (screen_info.orig_video_mode == 0x12) ||	/* 640x480/4 */
17762306a36Sopenharmony_ci	    (screen_info.orig_video_mode == 0x6A))	/* 800x600/4 (VESA) */
17862306a36Sopenharmony_ci		goto no_vga;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	vga_video_num_lines = screen_info.orig_video_lines;
18162306a36Sopenharmony_ci	vga_video_num_columns = screen_info.orig_video_cols;
18262306a36Sopenharmony_ci	vgastate.vgabase = NULL;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (screen_info.orig_video_mode == 7) {
18562306a36Sopenharmony_ci		/* Monochrome display */
18662306a36Sopenharmony_ci		vga_vram_base = 0xb0000;
18762306a36Sopenharmony_ci		vga_video_port_reg = VGA_CRT_IM;
18862306a36Sopenharmony_ci		vga_video_port_val = VGA_CRT_DM;
18962306a36Sopenharmony_ci		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
19062306a36Sopenharmony_ci			static struct resource ega_console_resource =
19162306a36Sopenharmony_ci			    { .name	= "ega",
19262306a36Sopenharmony_ci			      .flags	= IORESOURCE_IO,
19362306a36Sopenharmony_ci			      .start	= 0x3B0,
19462306a36Sopenharmony_ci			      .end	= 0x3BF };
19562306a36Sopenharmony_ci			vga_video_type = VIDEO_TYPE_EGAM;
19662306a36Sopenharmony_ci			vga_vram_size = 0x8000;
19762306a36Sopenharmony_ci			display_desc = "EGA+";
19862306a36Sopenharmony_ci			request_resource(&ioport_resource,
19962306a36Sopenharmony_ci					 &ega_console_resource);
20062306a36Sopenharmony_ci		} else {
20162306a36Sopenharmony_ci			static struct resource mda1_console_resource =
20262306a36Sopenharmony_ci			    { .name	= "mda",
20362306a36Sopenharmony_ci			      .flags	= IORESOURCE_IO,
20462306a36Sopenharmony_ci			      .start	= 0x3B0,
20562306a36Sopenharmony_ci			      .end	= 0x3BB };
20662306a36Sopenharmony_ci			static struct resource mda2_console_resource =
20762306a36Sopenharmony_ci			    { .name	= "mda",
20862306a36Sopenharmony_ci			      .flags	= IORESOURCE_IO,
20962306a36Sopenharmony_ci			      .start	= 0x3BF,
21062306a36Sopenharmony_ci			      .end	= 0x3BF };
21162306a36Sopenharmony_ci			vga_video_type = VIDEO_TYPE_MDA;
21262306a36Sopenharmony_ci			vga_vram_size = 0x2000;
21362306a36Sopenharmony_ci			display_desc = "*MDA";
21462306a36Sopenharmony_ci			request_resource(&ioport_resource,
21562306a36Sopenharmony_ci					 &mda1_console_resource);
21662306a36Sopenharmony_ci			request_resource(&ioport_resource,
21762306a36Sopenharmony_ci					 &mda2_console_resource);
21862306a36Sopenharmony_ci			vga_video_font_height = 14;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci	} else {
22162306a36Sopenharmony_ci		/* If not, it is color. */
22262306a36Sopenharmony_ci		vga_can_do_color = true;
22362306a36Sopenharmony_ci		vga_vram_base = 0xb8000;
22462306a36Sopenharmony_ci		vga_video_port_reg = VGA_CRT_IC;
22562306a36Sopenharmony_ci		vga_video_port_val = VGA_CRT_DC;
22662306a36Sopenharmony_ci		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
22762306a36Sopenharmony_ci			int i;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci			vga_vram_size = 0x8000;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci			if (!screen_info.orig_video_isVGA) {
23262306a36Sopenharmony_ci				static struct resource ega_console_resource =
23362306a36Sopenharmony_ci				    { .name	= "ega",
23462306a36Sopenharmony_ci				      .flags	= IORESOURCE_IO,
23562306a36Sopenharmony_ci				      .start	= 0x3C0,
23662306a36Sopenharmony_ci				      .end	= 0x3DF };
23762306a36Sopenharmony_ci				vga_video_type = VIDEO_TYPE_EGAC;
23862306a36Sopenharmony_ci				display_desc = "EGA";
23962306a36Sopenharmony_ci				request_resource(&ioport_resource,
24062306a36Sopenharmony_ci						 &ega_console_resource);
24162306a36Sopenharmony_ci			} else {
24262306a36Sopenharmony_ci				static struct resource vga_console_resource =
24362306a36Sopenharmony_ci				    { .name	= "vga+",
24462306a36Sopenharmony_ci				      .flags	= IORESOURCE_IO,
24562306a36Sopenharmony_ci				      .start	= 0x3C0,
24662306a36Sopenharmony_ci				      .end	= 0x3DF };
24762306a36Sopenharmony_ci				vga_video_type = VIDEO_TYPE_VGAC;
24862306a36Sopenharmony_ci				display_desc = "VGA+";
24962306a36Sopenharmony_ci				request_resource(&ioport_resource,
25062306a36Sopenharmony_ci						 &vga_console_resource);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci				/*
25362306a36Sopenharmony_ci				 * Normalise the palette registers, to point
25462306a36Sopenharmony_ci				 * the 16 screen colours to the first 16
25562306a36Sopenharmony_ci				 * DAC entries.
25662306a36Sopenharmony_ci				 */
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci				for (i = 0; i < 16; i++) {
25962306a36Sopenharmony_ci					inb_p(VGA_IS1_RC);
26062306a36Sopenharmony_ci					outb_p(i, VGA_ATT_W);
26162306a36Sopenharmony_ci					outb_p(i, VGA_ATT_W);
26262306a36Sopenharmony_ci				}
26362306a36Sopenharmony_ci				outb_p(0x20, VGA_ATT_W);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci				/*
26662306a36Sopenharmony_ci				 * Now set the DAC registers back to their
26762306a36Sopenharmony_ci				 * default values
26862306a36Sopenharmony_ci				 */
26962306a36Sopenharmony_ci				for (i = 0; i < 16; i++) {
27062306a36Sopenharmony_ci					outb_p(color_table[i], VGA_PEL_IW);
27162306a36Sopenharmony_ci					outb_p(default_red[i], VGA_PEL_D);
27262306a36Sopenharmony_ci					outb_p(default_grn[i], VGA_PEL_D);
27362306a36Sopenharmony_ci					outb_p(default_blu[i], VGA_PEL_D);
27462306a36Sopenharmony_ci				}
27562306a36Sopenharmony_ci			}
27662306a36Sopenharmony_ci		} else {
27762306a36Sopenharmony_ci			static struct resource cga_console_resource =
27862306a36Sopenharmony_ci			    { .name	= "cga",
27962306a36Sopenharmony_ci			      .flags	= IORESOURCE_IO,
28062306a36Sopenharmony_ci			      .start	= 0x3D4,
28162306a36Sopenharmony_ci			      .end	= 0x3D5 };
28262306a36Sopenharmony_ci			vga_video_type = VIDEO_TYPE_CGA;
28362306a36Sopenharmony_ci			vga_vram_size = 0x2000;
28462306a36Sopenharmony_ci			display_desc = "*CGA";
28562306a36Sopenharmony_ci			request_resource(&ioport_resource,
28662306a36Sopenharmony_ci					 &cga_console_resource);
28762306a36Sopenharmony_ci			vga_video_font_height = 8;
28862306a36Sopenharmony_ci		}
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
29262306a36Sopenharmony_ci	vga_vram_end = vga_vram_base + vga_vram_size;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/*
29562306a36Sopenharmony_ci	 *      Find out if there is a graphics card present.
29662306a36Sopenharmony_ci	 *      Are there smarter methods around?
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	p = (volatile u16 *) vga_vram_base;
29962306a36Sopenharmony_ci	saved1 = scr_readw(p);
30062306a36Sopenharmony_ci	saved2 = scr_readw(p + 1);
30162306a36Sopenharmony_ci	scr_writew(0xAA55, p);
30262306a36Sopenharmony_ci	scr_writew(0x55AA, p + 1);
30362306a36Sopenharmony_ci	if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
30462306a36Sopenharmony_ci		scr_writew(saved1, p);
30562306a36Sopenharmony_ci		scr_writew(saved2, p + 1);
30662306a36Sopenharmony_ci		goto no_vga;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	scr_writew(0x55AA, p);
30962306a36Sopenharmony_ci	scr_writew(0xAA55, p + 1);
31062306a36Sopenharmony_ci	if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
31162306a36Sopenharmony_ci		scr_writew(saved1, p);
31262306a36Sopenharmony_ci		scr_writew(saved2, p + 1);
31362306a36Sopenharmony_ci		goto no_vga;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci	scr_writew(saved1, p);
31662306a36Sopenharmony_ci	scr_writew(saved2, p + 1);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (vga_video_type == VIDEO_TYPE_EGAC
31962306a36Sopenharmony_ci	    || vga_video_type == VIDEO_TYPE_VGAC
32062306a36Sopenharmony_ci	    || vga_video_type == VIDEO_TYPE_EGAM) {
32162306a36Sopenharmony_ci		vga_hardscroll_enabled = vga_hardscroll_user_enable;
32262306a36Sopenharmony_ci		vga_default_font_height = screen_info.orig_video_points;
32362306a36Sopenharmony_ci		vga_video_font_height = screen_info.orig_video_points;
32462306a36Sopenharmony_ci		/* This may be suboptimal but is a safe bet - go with it */
32562306a36Sopenharmony_ci		vga_scan_lines =
32662306a36Sopenharmony_ci		    vga_video_font_height * vga_video_num_lines;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
33062306a36Sopenharmony_ci	vgacon_yres = vga_scan_lines;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return display_desc;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic void vgacon_init(struct vc_data *c, int init)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct uni_pagedict *p;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * We cannot be loaded as a module, therefore init will be 1
34162306a36Sopenharmony_ci	 * if we are the default console, however if we are a fallback
34262306a36Sopenharmony_ci	 * console, for example if fbcon has failed registration, then
34362306a36Sopenharmony_ci	 * init will be 0, so we need to make sure our boot parameters
34462306a36Sopenharmony_ci	 * have been copied to the console structure for vgacon_resize
34562306a36Sopenharmony_ci	 * ultimately called by vc_resize.  Any subsequent calls to
34662306a36Sopenharmony_ci	 * vgacon_init init will have init set to 0 too.
34762306a36Sopenharmony_ci	 */
34862306a36Sopenharmony_ci	c->vc_can_do_color = vga_can_do_color;
34962306a36Sopenharmony_ci	c->vc_scan_lines = vga_scan_lines;
35062306a36Sopenharmony_ci	c->vc_font.height = c->vc_cell_height = vga_video_font_height;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	/* set dimensions manually if init != 0 since vc_resize() will fail */
35362306a36Sopenharmony_ci	if (init) {
35462306a36Sopenharmony_ci		c->vc_cols = vga_video_num_columns;
35562306a36Sopenharmony_ci		c->vc_rows = vga_video_num_lines;
35662306a36Sopenharmony_ci	} else
35762306a36Sopenharmony_ci		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	c->vc_complement_mask = 0x7700;
36062306a36Sopenharmony_ci	if (vga_512_chars)
36162306a36Sopenharmony_ci		c->vc_hi_font_mask = 0x0800;
36262306a36Sopenharmony_ci	p = *c->uni_pagedict_loc;
36362306a36Sopenharmony_ci	if (c->uni_pagedict_loc != &vgacon_uni_pagedir) {
36462306a36Sopenharmony_ci		con_free_unimap(c);
36562306a36Sopenharmony_ci		c->uni_pagedict_loc = &vgacon_uni_pagedir;
36662306a36Sopenharmony_ci		vgacon_refcount++;
36762306a36Sopenharmony_ci	}
36862306a36Sopenharmony_ci	if (!vgacon_uni_pagedir && p)
36962306a36Sopenharmony_ci		con_set_default_unimap(c);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	/* Only set the default if the user didn't deliberately override it */
37262306a36Sopenharmony_ci	if (global_cursor_default == -1)
37362306a36Sopenharmony_ci		global_cursor_default =
37462306a36Sopenharmony_ci			!(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic void vgacon_deinit(struct vc_data *c)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	/* When closing the active console, reset video origin */
38062306a36Sopenharmony_ci	if (con_is_visible(c)) {
38162306a36Sopenharmony_ci		c->vc_visible_origin = vga_vram_base;
38262306a36Sopenharmony_ci		vga_set_mem_top(c);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	if (!--vgacon_refcount)
38662306a36Sopenharmony_ci		con_free_unimap(c);
38762306a36Sopenharmony_ci	c->uni_pagedict_loc = &c->uni_pagedict;
38862306a36Sopenharmony_ci	con_set_default_unimap(c);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic u8 vgacon_build_attr(struct vc_data *c, u8 color,
39262306a36Sopenharmony_ci			    enum vc_intensity intensity,
39362306a36Sopenharmony_ci			    bool blink, bool underline, bool reverse,
39462306a36Sopenharmony_ci			    bool italic)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	u8 attr = color;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (vga_can_do_color) {
39962306a36Sopenharmony_ci		if (italic)
40062306a36Sopenharmony_ci			attr = (attr & 0xF0) | c->vc_itcolor;
40162306a36Sopenharmony_ci		else if (underline)
40262306a36Sopenharmony_ci			attr = (attr & 0xf0) | c->vc_ulcolor;
40362306a36Sopenharmony_ci		else if (intensity == VCI_HALF_BRIGHT)
40462306a36Sopenharmony_ci			attr = (attr & 0xf0) | c->vc_halfcolor;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci	if (reverse)
40762306a36Sopenharmony_ci		attr =
40862306a36Sopenharmony_ci		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
40962306a36Sopenharmony_ci				       0x77);
41062306a36Sopenharmony_ci	if (blink)
41162306a36Sopenharmony_ci		attr ^= 0x80;
41262306a36Sopenharmony_ci	if (intensity == VCI_BOLD)
41362306a36Sopenharmony_ci		attr ^= 0x08;
41462306a36Sopenharmony_ci	if (!vga_can_do_color) {
41562306a36Sopenharmony_ci		if (italic)
41662306a36Sopenharmony_ci			attr = (attr & 0xF8) | 0x02;
41762306a36Sopenharmony_ci		else if (underline)
41862306a36Sopenharmony_ci			attr = (attr & 0xf8) | 0x01;
41962306a36Sopenharmony_ci		else if (intensity == VCI_HALF_BRIGHT)
42062306a36Sopenharmony_ci			attr = (attr & 0xf0) | 0x08;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci	return attr;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	const bool col = vga_can_do_color;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	while (count--) {
43062306a36Sopenharmony_ci		u16 a = scr_readw(p);
43162306a36Sopenharmony_ci		if (col)
43262306a36Sopenharmony_ci			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
43362306a36Sopenharmony_ci			    (((a) & 0x0700) << 4);
43462306a36Sopenharmony_ci		else
43562306a36Sopenharmony_ci			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
43662306a36Sopenharmony_ci		scr_writew(a, p++);
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void vgacon_set_cursor_size(int from, int to)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	unsigned long flags;
44362306a36Sopenharmony_ci	int curs, cure;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
44662306a36Sopenharmony_ci		return;
44762306a36Sopenharmony_ci	cursor_size_lastfrom = from;
44862306a36Sopenharmony_ci	cursor_size_lastto = to;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&vga_lock, flags);
45162306a36Sopenharmony_ci	if (vga_video_type >= VIDEO_TYPE_VGAC) {
45262306a36Sopenharmony_ci		outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
45362306a36Sopenharmony_ci		curs = inb_p(vga_video_port_val);
45462306a36Sopenharmony_ci		outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
45562306a36Sopenharmony_ci		cure = inb_p(vga_video_port_val);
45662306a36Sopenharmony_ci	} else {
45762306a36Sopenharmony_ci		curs = 0;
45862306a36Sopenharmony_ci		cure = 0;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	curs = (curs & 0xc0) | from;
46262306a36Sopenharmony_ci	cure = (cure & 0xe0) | to;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
46562306a36Sopenharmony_ci	outb_p(curs, vga_video_port_val);
46662306a36Sopenharmony_ci	outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
46762306a36Sopenharmony_ci	outb_p(cure, vga_video_port_val);
46862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&vga_lock, flags);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic void vgacon_cursor(struct vc_data *c, int mode)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	unsigned int c_height;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (c->vc_mode != KD_TEXT)
47662306a36Sopenharmony_ci		return;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	vgacon_restore_screen(c);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	c_height = c->vc_cell_height;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	switch (mode) {
48362306a36Sopenharmony_ci	case CM_ERASE:
48462306a36Sopenharmony_ci		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
48562306a36Sopenharmony_ci	        if (vga_video_type >= VIDEO_TYPE_VGAC)
48662306a36Sopenharmony_ci			vgacon_set_cursor_size(31, 30);
48762306a36Sopenharmony_ci		else
48862306a36Sopenharmony_ci			vgacon_set_cursor_size(31, 31);
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	case CM_MOVE:
49262306a36Sopenharmony_ci	case CM_DRAW:
49362306a36Sopenharmony_ci		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
49462306a36Sopenharmony_ci		switch (CUR_SIZE(c->vc_cursor_type)) {
49562306a36Sopenharmony_ci		case CUR_UNDERLINE:
49662306a36Sopenharmony_ci			vgacon_set_cursor_size(c_height -
49762306a36Sopenharmony_ci					       (c_height < 10 ? 2 : 3),
49862306a36Sopenharmony_ci					       c_height -
49962306a36Sopenharmony_ci					       (c_height < 10 ? 1 : 2));
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		case CUR_TWO_THIRDS:
50262306a36Sopenharmony_ci			vgacon_set_cursor_size(c_height / 3, c_height -
50362306a36Sopenharmony_ci					       (c_height < 10 ? 1 : 2));
50462306a36Sopenharmony_ci			break;
50562306a36Sopenharmony_ci		case CUR_LOWER_THIRD:
50662306a36Sopenharmony_ci			vgacon_set_cursor_size(c_height * 2 / 3, c_height -
50762306a36Sopenharmony_ci					       (c_height < 10 ? 1 : 2));
50862306a36Sopenharmony_ci			break;
50962306a36Sopenharmony_ci		case CUR_LOWER_HALF:
51062306a36Sopenharmony_ci			vgacon_set_cursor_size(c_height / 2, c_height -
51162306a36Sopenharmony_ci					       (c_height < 10 ? 1 : 2));
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci		case CUR_NONE:
51462306a36Sopenharmony_ci			if (vga_video_type >= VIDEO_TYPE_VGAC)
51562306a36Sopenharmony_ci				vgacon_set_cursor_size(31, 30);
51662306a36Sopenharmony_ci			else
51762306a36Sopenharmony_ci				vgacon_set_cursor_size(31, 31);
51862306a36Sopenharmony_ci			break;
51962306a36Sopenharmony_ci		default:
52062306a36Sopenharmony_ci			vgacon_set_cursor_size(1, c_height);
52162306a36Sopenharmony_ci			break;
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci		break;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic void vgacon_doresize(struct vc_data *c,
52862306a36Sopenharmony_ci		unsigned int width, unsigned int height)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	unsigned long flags;
53162306a36Sopenharmony_ci	unsigned int scanlines = height * c->vc_cell_height;
53262306a36Sopenharmony_ci	u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	raw_spin_lock_irqsave(&vga_lock, flags);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	vgacon_xres = width * VGA_FONTWIDTH;
53762306a36Sopenharmony_ci	vgacon_yres = height * c->vc_cell_height;
53862306a36Sopenharmony_ci	if (vga_video_type >= VIDEO_TYPE_VGAC) {
53962306a36Sopenharmony_ci		outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
54062306a36Sopenharmony_ci		max_scan = inb_p(vga_video_port_val);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci		if (max_scan & 0x80)
54362306a36Sopenharmony_ci			scanlines <<= 1;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		outb_p(VGA_CRTC_MODE, vga_video_port_reg);
54662306a36Sopenharmony_ci		mode = inb_p(vga_video_port_val);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		if (mode & 0x04)
54962306a36Sopenharmony_ci			scanlines >>= 1;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		scanlines -= 1;
55262306a36Sopenharmony_ci		scanlines_lo = scanlines & 0xff;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
55562306a36Sopenharmony_ci		r7 = inb_p(vga_video_port_val) & ~0x42;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		if (scanlines & 0x100)
55862306a36Sopenharmony_ci			r7 |= 0x02;
55962306a36Sopenharmony_ci		if (scanlines & 0x200)
56062306a36Sopenharmony_ci			r7 |= 0x40;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci		/* deprotect registers */
56362306a36Sopenharmony_ci		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
56462306a36Sopenharmony_ci		vsync_end = inb_p(vga_video_port_val);
56562306a36Sopenharmony_ci		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
56662306a36Sopenharmony_ci		outb_p(vsync_end & ~0x80, vga_video_port_val);
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
57062306a36Sopenharmony_ci	outb_p(width - 1, vga_video_port_val);
57162306a36Sopenharmony_ci	outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
57262306a36Sopenharmony_ci	outb_p(width >> 1, vga_video_port_val);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (vga_video_type >= VIDEO_TYPE_VGAC) {
57562306a36Sopenharmony_ci		outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
57662306a36Sopenharmony_ci		outb_p(scanlines_lo, vga_video_port_val);
57762306a36Sopenharmony_ci		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
57862306a36Sopenharmony_ci		outb_p(r7,vga_video_port_val);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		/* reprotect registers */
58162306a36Sopenharmony_ci		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
58262306a36Sopenharmony_ci		outb_p(vsync_end, vga_video_port_val);
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&vga_lock, flags);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic int vgacon_switch(struct vc_data *c)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	int x = c->vc_cols * VGA_FONTWIDTH;
59162306a36Sopenharmony_ci	int y = c->vc_rows * c->vc_cell_height;
59262306a36Sopenharmony_ci	int rows = screen_info.orig_video_lines * vga_default_font_height/
59362306a36Sopenharmony_ci		c->vc_cell_height;
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * We need to save screen size here as it's the only way
59662306a36Sopenharmony_ci	 * we can spot the screen has been resized and we need to
59762306a36Sopenharmony_ci	 * set size of freshly allocated screens ourselves.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	vga_video_num_columns = c->vc_cols;
60062306a36Sopenharmony_ci	vga_video_num_lines = c->vc_rows;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* We can only copy out the size of the video buffer here,
60362306a36Sopenharmony_ci	 * otherwise we get into VGA BIOS */
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (!vga_is_gfx) {
60662306a36Sopenharmony_ci		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
60762306a36Sopenharmony_ci			    c->vc_screenbuf_size > vga_vram_size ?
60862306a36Sopenharmony_ci				vga_vram_size : c->vc_screenbuf_size);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		if ((vgacon_xres != x || vgacon_yres != y) &&
61162306a36Sopenharmony_ci		    (!(vga_video_num_columns % 2) &&
61262306a36Sopenharmony_ci		     vga_video_num_columns <= screen_info.orig_video_cols &&
61362306a36Sopenharmony_ci		     vga_video_num_lines <= rows))
61462306a36Sopenharmony_ci			vgacon_doresize(c, c->vc_cols, c->vc_rows);
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	return 0;		/* Redrawing not needed */
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_cistatic void vga_set_palette(struct vc_data *vc, const unsigned char *table)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	int i, j;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
62562306a36Sopenharmony_ci	for (i = j = 0; i < 16; i++) {
62662306a36Sopenharmony_ci		vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
62762306a36Sopenharmony_ci		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
62862306a36Sopenharmony_ci		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
62962306a36Sopenharmony_ci		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
63662306a36Sopenharmony_ci	    || !con_is_visible(vc))
63762306a36Sopenharmony_ci		return;
63862306a36Sopenharmony_ci	vga_set_palette(vc, table);
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci/* structure holding original VGA register settings */
64262306a36Sopenharmony_cistatic struct {
64362306a36Sopenharmony_ci	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
64462306a36Sopenharmony_ci	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
64562306a36Sopenharmony_ci	unsigned char CrtMiscIO;	/* Miscellaneous register */
64662306a36Sopenharmony_ci	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
64762306a36Sopenharmony_ci	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
64862306a36Sopenharmony_ci	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
64962306a36Sopenharmony_ci	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
65062306a36Sopenharmony_ci	unsigned char Overflow;	/* CRT-Controller:07h */
65162306a36Sopenharmony_ci	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
65262306a36Sopenharmony_ci	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
65362306a36Sopenharmony_ci	unsigned char ModeControl;	/* CRT-Controller:17h */
65462306a36Sopenharmony_ci	unsigned char ClockingMode;	/* Seq-Controller:01h */
65562306a36Sopenharmony_ci} vga_state;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic void vga_vesa_blank(struct vgastate *state, int mode)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	/* save original values of VGA controller registers */
66062306a36Sopenharmony_ci	if (!vga_vesa_blanked) {
66162306a36Sopenharmony_ci		raw_spin_lock_irq(&vga_lock);
66262306a36Sopenharmony_ci		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
66362306a36Sopenharmony_ci		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
66462306a36Sopenharmony_ci		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
66562306a36Sopenharmony_ci		raw_spin_unlock_irq(&vga_lock);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
66862306a36Sopenharmony_ci		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
66962306a36Sopenharmony_ci		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
67062306a36Sopenharmony_ci		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
67162306a36Sopenharmony_ci		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
67262306a36Sopenharmony_ci		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
67362306a36Sopenharmony_ci		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
67462306a36Sopenharmony_ci		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
67562306a36Sopenharmony_ci		outb_p(0x07, vga_video_port_reg);	/* Overflow */
67662306a36Sopenharmony_ci		vga_state.Overflow = inb_p(vga_video_port_val);
67762306a36Sopenharmony_ci		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
67862306a36Sopenharmony_ci		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
67962306a36Sopenharmony_ci		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
68062306a36Sopenharmony_ci		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
68162306a36Sopenharmony_ci		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
68262306a36Sopenharmony_ci		vga_state.ModeControl = inb_p(vga_video_port_val);
68362306a36Sopenharmony_ci		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/* assure that video is enabled */
68762306a36Sopenharmony_ci	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
68862306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
68962306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	/* test for vertical retrace in process.... */
69262306a36Sopenharmony_ci	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
69362306a36Sopenharmony_ci		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/*
69662306a36Sopenharmony_ci	 * Set <End of vertical retrace> to minimum (0) and
69762306a36Sopenharmony_ci	 * <Start of vertical Retrace> to maximum (incl. overflow)
69862306a36Sopenharmony_ci	 * Result: turn off vertical sync (VSync) pulse.
69962306a36Sopenharmony_ci	 */
70062306a36Sopenharmony_ci	if (mode & VESA_VSYNC_SUSPEND) {
70162306a36Sopenharmony_ci		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
70262306a36Sopenharmony_ci		outb_p(0xff, vga_video_port_val);	/* maximum value */
70362306a36Sopenharmony_ci		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
70462306a36Sopenharmony_ci		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
70562306a36Sopenharmony_ci		outb_p(0x07, vga_video_port_reg);	/* Overflow */
70662306a36Sopenharmony_ci		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (mode & VESA_HSYNC_SUSPEND) {
71062306a36Sopenharmony_ci		/*
71162306a36Sopenharmony_ci		 * Set <End of horizontal retrace> to minimum (0) and
71262306a36Sopenharmony_ci		 *  <Start of horizontal Retrace> to maximum
71362306a36Sopenharmony_ci		 * Result: turn off horizontal sync (HSync) pulse.
71462306a36Sopenharmony_ci		 */
71562306a36Sopenharmony_ci		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
71662306a36Sopenharmony_ci		outb_p(0xff, vga_video_port_val);	/* maximum */
71762306a36Sopenharmony_ci		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
71862306a36Sopenharmony_ci		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* restore both index registers */
72262306a36Sopenharmony_ci	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
72362306a36Sopenharmony_ci	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
72462306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_cistatic void vga_vesa_unblank(struct vgastate *state)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	/* restore original values of VGA controller registers */
73062306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
73162306a36Sopenharmony_ci	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
73462306a36Sopenharmony_ci	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
73562306a36Sopenharmony_ci	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
73662306a36Sopenharmony_ci	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
73762306a36Sopenharmony_ci	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
73862306a36Sopenharmony_ci	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
73962306a36Sopenharmony_ci	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
74062306a36Sopenharmony_ci	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
74162306a36Sopenharmony_ci	outb_p(0x07, vga_video_port_reg);	/* Overflow */
74262306a36Sopenharmony_ci	outb_p(vga_state.Overflow, vga_video_port_val);
74362306a36Sopenharmony_ci	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
74462306a36Sopenharmony_ci	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
74562306a36Sopenharmony_ci	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
74662306a36Sopenharmony_ci	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
74762306a36Sopenharmony_ci	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
74862306a36Sopenharmony_ci	outb_p(vga_state.ModeControl, vga_video_port_val);
74962306a36Sopenharmony_ci	/* ClockingMode */
75062306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	/* restore index/control registers */
75362306a36Sopenharmony_ci	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
75462306a36Sopenharmony_ci	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
75562306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic void vga_pal_blank(struct vgastate *state)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	int i;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
76362306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
76462306a36Sopenharmony_ci		vga_w(state->vgabase, VGA_PEL_IW, i);
76562306a36Sopenharmony_ci		vga_w(state->vgabase, VGA_PEL_D, 0);
76662306a36Sopenharmony_ci		vga_w(state->vgabase, VGA_PEL_D, 0);
76762306a36Sopenharmony_ci		vga_w(state->vgabase, VGA_PEL_D, 0);
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	switch (blank) {
77462306a36Sopenharmony_ci	case 0:		/* Unblank */
77562306a36Sopenharmony_ci		if (vga_vesa_blanked) {
77662306a36Sopenharmony_ci			vga_vesa_unblank(&vgastate);
77762306a36Sopenharmony_ci			vga_vesa_blanked = 0;
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci		if (vga_palette_blanked) {
78062306a36Sopenharmony_ci			vga_set_palette(c, color_table);
78162306a36Sopenharmony_ci			vga_palette_blanked = false;
78262306a36Sopenharmony_ci			return 0;
78362306a36Sopenharmony_ci		}
78462306a36Sopenharmony_ci		vga_is_gfx = false;
78562306a36Sopenharmony_ci		/* Tell console.c that it has to restore the screen itself */
78662306a36Sopenharmony_ci		return 1;
78762306a36Sopenharmony_ci	case 1:		/* Normal blanking */
78862306a36Sopenharmony_ci	case -1:	/* Obsolete */
78962306a36Sopenharmony_ci		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
79062306a36Sopenharmony_ci			vga_pal_blank(&vgastate);
79162306a36Sopenharmony_ci			vga_palette_blanked = true;
79262306a36Sopenharmony_ci			return 0;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci		vgacon_set_origin(c);
79562306a36Sopenharmony_ci		scr_memsetw((void *) vga_vram_base, BLANK,
79662306a36Sopenharmony_ci			    c->vc_screenbuf_size);
79762306a36Sopenharmony_ci		if (mode_switch)
79862306a36Sopenharmony_ci			vga_is_gfx = true;
79962306a36Sopenharmony_ci		return 1;
80062306a36Sopenharmony_ci	default:		/* VESA blanking */
80162306a36Sopenharmony_ci		if (vga_video_type == VIDEO_TYPE_VGAC) {
80262306a36Sopenharmony_ci			vga_vesa_blank(&vgastate, blank - 1);
80362306a36Sopenharmony_ci			vga_vesa_blanked = blank;
80462306a36Sopenharmony_ci		}
80562306a36Sopenharmony_ci		return 0;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci/*
81062306a36Sopenharmony_ci * PIO_FONT support.
81162306a36Sopenharmony_ci *
81262306a36Sopenharmony_ci * The font loading code goes back to the codepage package by
81362306a36Sopenharmony_ci * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
81462306a36Sopenharmony_ci * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
81562306a36Sopenharmony_ci * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
81662306a36Sopenharmony_ci *
81762306a36Sopenharmony_ci * Change for certain monochrome monitors by Yury Shevchuck
81862306a36Sopenharmony_ci * (sizif@botik.yaroslavl.su).
81962306a36Sopenharmony_ci */
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci#define colourmap 0xa0000
82262306a36Sopenharmony_ci/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
82362306a36Sopenharmony_ci   should use 0xA0000 for the bwmap as well.. */
82462306a36Sopenharmony_ci#define blackwmap 0xa0000
82562306a36Sopenharmony_ci#define cmapsz 8192
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_cistatic int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
82862306a36Sopenharmony_ci		bool ch512)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	unsigned short video_port_status = vga_video_port_reg + 6;
83162306a36Sopenharmony_ci	int font_select = 0x00, beg, i;
83262306a36Sopenharmony_ci	char *charmap;
83362306a36Sopenharmony_ci	bool clear_attribs = false;
83462306a36Sopenharmony_ci	if (vga_video_type != VIDEO_TYPE_EGAM) {
83562306a36Sopenharmony_ci		charmap = (char *) VGA_MAP_MEM(colourmap, 0);
83662306a36Sopenharmony_ci		beg = 0x0e;
83762306a36Sopenharmony_ci	} else {
83862306a36Sopenharmony_ci		charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
83962306a36Sopenharmony_ci		beg = 0x0a;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	/*
84362306a36Sopenharmony_ci	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
84462306a36Sopenharmony_ci	 */
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	if (!arg)
84762306a36Sopenharmony_ci		return -EINVAL;	/* Return to default font not supported */
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	font_select = ch512 ? 0x04 : 0x00;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
85262306a36Sopenharmony_ci	/* First, the Sequencer */
85362306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
85462306a36Sopenharmony_ci	/* CPU writes only to map 2 */
85562306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);
85662306a36Sopenharmony_ci	/* Sequential addressing */
85762306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);
85862306a36Sopenharmony_ci	/* Clear synchronous reset */
85962306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	/* Now, the graphics controller, select map 2 */
86262306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);
86362306a36Sopenharmony_ci	/* disable odd-even addressing */
86462306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
86562306a36Sopenharmony_ci	/* map start at A000:0000 */
86662306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
86762306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (arg) {
87062306a36Sopenharmony_ci		if (set)
87162306a36Sopenharmony_ci			for (i = 0; i < cmapsz; i++) {
87262306a36Sopenharmony_ci				vga_writeb(arg[i], charmap + i);
87362306a36Sopenharmony_ci				cond_resched();
87462306a36Sopenharmony_ci			}
87562306a36Sopenharmony_ci		else
87662306a36Sopenharmony_ci			for (i = 0; i < cmapsz; i++) {
87762306a36Sopenharmony_ci				arg[i] = vga_readb(charmap + i);
87862306a36Sopenharmony_ci				cond_resched();
87962306a36Sopenharmony_ci			}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		/*
88262306a36Sopenharmony_ci		 * In 512-character mode, the character map is not contiguous if
88362306a36Sopenharmony_ci		 * we want to remain EGA compatible -- which we do
88462306a36Sopenharmony_ci		 */
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		if (ch512) {
88762306a36Sopenharmony_ci			charmap += 2 * cmapsz;
88862306a36Sopenharmony_ci			arg += cmapsz;
88962306a36Sopenharmony_ci			if (set)
89062306a36Sopenharmony_ci				for (i = 0; i < cmapsz; i++) {
89162306a36Sopenharmony_ci					vga_writeb(arg[i], charmap + i);
89262306a36Sopenharmony_ci					cond_resched();
89362306a36Sopenharmony_ci				}
89462306a36Sopenharmony_ci			else
89562306a36Sopenharmony_ci				for (i = 0; i < cmapsz; i++) {
89662306a36Sopenharmony_ci					arg[i] = vga_readb(charmap + i);
89762306a36Sopenharmony_ci					cond_resched();
89862306a36Sopenharmony_ci				}
89962306a36Sopenharmony_ci		}
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
90362306a36Sopenharmony_ci	/* First, the sequencer, Synchronous reset */
90462306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
90562306a36Sopenharmony_ci	/* CPU writes to maps 0 and 1 */
90662306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
90762306a36Sopenharmony_ci	/* odd-even addressing */
90862306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
90962306a36Sopenharmony_ci	/* Character Map Select */
91062306a36Sopenharmony_ci	if (set)
91162306a36Sopenharmony_ci		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
91262306a36Sopenharmony_ci	/* clear synchronous reset */
91362306a36Sopenharmony_ci	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	/* Now, the graphics controller, select map 0 for CPU */
91662306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
91762306a36Sopenharmony_ci	/* enable even-odd addressing */
91862306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
91962306a36Sopenharmony_ci	/* map starts at b800:0 or b000:0 */
92062306a36Sopenharmony_ci	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	/* if 512 char mode is already enabled don't re-enable it. */
92362306a36Sopenharmony_ci	if ((set) && (ch512 != vga_512_chars)) {
92462306a36Sopenharmony_ci		vga_512_chars = ch512;
92562306a36Sopenharmony_ci		/* 256-char: enable intensity bit
92662306a36Sopenharmony_ci		   512-char: disable intensity bit */
92762306a36Sopenharmony_ci		inb_p(video_port_status);	/* clear address flip-flop */
92862306a36Sopenharmony_ci		/* color plane enable register */
92962306a36Sopenharmony_ci		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
93062306a36Sopenharmony_ci		/* Wilton (1987) mentions the following; I don't know what
93162306a36Sopenharmony_ci		   it means, but it works, and it appears necessary */
93262306a36Sopenharmony_ci		inb_p(video_port_status);
93362306a36Sopenharmony_ci		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
93462306a36Sopenharmony_ci		clear_attribs = true;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (clear_attribs) {
93962306a36Sopenharmony_ci		for (i = 0; i < MAX_NR_CONSOLES; i++) {
94062306a36Sopenharmony_ci			struct vc_data *c = vc_cons[i].d;
94162306a36Sopenharmony_ci			if (c && c->vc_sw == &vga_con) {
94262306a36Sopenharmony_ci				/* force hi font mask to 0, so we always clear
94362306a36Sopenharmony_ci				   the bit on either transition */
94462306a36Sopenharmony_ci				c->vc_hi_font_mask = 0x00;
94562306a36Sopenharmony_ci				clear_buffer_attributes(c);
94662306a36Sopenharmony_ci				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
94762306a36Sopenharmony_ci			}
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci	return 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci/*
95462306a36Sopenharmony_ci * Adjust the screen to fit a font of a certain height
95562306a36Sopenharmony_ci */
95662306a36Sopenharmony_cistatic int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	unsigned char ovr, vde, fsr;
95962306a36Sopenharmony_ci	int rows, maxscan, i;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
96262306a36Sopenharmony_ci	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	/* Reprogram the CRTC for the new font size
96562306a36Sopenharmony_ci	   Note: the attempt to read the overflow register will fail
96662306a36Sopenharmony_ci	   on an EGA, but using 0xff for the previous value appears to
96762306a36Sopenharmony_ci	   be OK for EGA text modes in the range 257-512 scan lines, so I
96862306a36Sopenharmony_ci	   guess we don't need to worry about it.
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	   The same applies for the spill bits in the font size and cursor
97162306a36Sopenharmony_ci	   registers; they are write-only on EGA, but it appears that they
97262306a36Sopenharmony_ci	   are all don't care bits on EGA, so I guess it doesn't matter. */
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
97562306a36Sopenharmony_ci	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
97662306a36Sopenharmony_ci	ovr = inb_p(vga_video_port_val);
97762306a36Sopenharmony_ci	outb_p(0x09, vga_video_port_reg);	/* Font size register */
97862306a36Sopenharmony_ci	fsr = inb_p(vga_video_port_val);
97962306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	vde = maxscan & 0xff;	/* Vertical display end reg */
98262306a36Sopenharmony_ci	ovr = (ovr & 0xbd) +	/* Overflow register */
98362306a36Sopenharmony_ci	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
98462306a36Sopenharmony_ci	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	raw_spin_lock_irq(&vga_lock);
98762306a36Sopenharmony_ci	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
98862306a36Sopenharmony_ci	outb_p(ovr, vga_video_port_val);
98962306a36Sopenharmony_ci	outb_p(0x09, vga_video_port_reg);	/* Font size */
99062306a36Sopenharmony_ci	outb_p(fsr, vga_video_port_val);
99162306a36Sopenharmony_ci	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
99262306a36Sopenharmony_ci	outb_p(vde, vga_video_port_val);
99362306a36Sopenharmony_ci	raw_spin_unlock_irq(&vga_lock);
99462306a36Sopenharmony_ci	vga_video_font_height = fontheight;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	for (i = 0; i < MAX_NR_CONSOLES; i++) {
99762306a36Sopenharmony_ci		struct vc_data *c = vc_cons[i].d;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		if (c && c->vc_sw == &vga_con) {
100062306a36Sopenharmony_ci			if (con_is_visible(c)) {
100162306a36Sopenharmony_ci			        /* void size to cause regs to be rewritten */
100262306a36Sopenharmony_ci				cursor_size_lastfrom = 0;
100362306a36Sopenharmony_ci				cursor_size_lastto = 0;
100462306a36Sopenharmony_ci				c->vc_sw->con_cursor(c, CM_DRAW);
100562306a36Sopenharmony_ci			}
100662306a36Sopenharmony_ci			c->vc_font.height = c->vc_cell_height = fontheight;
100762306a36Sopenharmony_ci			vc_resize(c, 0, rows);	/* Adjust console size */
100862306a36Sopenharmony_ci		}
100962306a36Sopenharmony_ci	}
101062306a36Sopenharmony_ci	return 0;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic int vgacon_font_set(struct vc_data *c, struct console_font *font,
101462306a36Sopenharmony_ci			   unsigned int vpitch, unsigned int flags)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	unsigned charcount = font->charcount;
101762306a36Sopenharmony_ci	int rc;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (vga_video_type < VIDEO_TYPE_EGAM)
102062306a36Sopenharmony_ci		return -EINVAL;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (font->width != VGA_FONTWIDTH || font->height > 32 || vpitch != 32 ||
102362306a36Sopenharmony_ci	    (charcount != 256 && charcount != 512))
102462306a36Sopenharmony_ci		return -EINVAL;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
102762306a36Sopenharmony_ci	if (rc)
102862306a36Sopenharmony_ci		return rc;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
103162306a36Sopenharmony_ci		rc = vgacon_adjust_height(c, font->height);
103262306a36Sopenharmony_ci	return rc;
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic int vgacon_font_get(struct vc_data *c, struct console_font *font, unsigned int vpitch)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	if (vga_video_type < VIDEO_TYPE_EGAM || vpitch != 32)
103862306a36Sopenharmony_ci		return -EINVAL;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	font->width = VGA_FONTWIDTH;
104162306a36Sopenharmony_ci	font->height = c->vc_font.height;
104262306a36Sopenharmony_ci	font->charcount = vga_512_chars ? 512 : 256;
104362306a36Sopenharmony_ci	if (!font->data)
104462306a36Sopenharmony_ci		return 0;
104562306a36Sopenharmony_ci	return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic int vgacon_resize(struct vc_data *c, unsigned int width,
104962306a36Sopenharmony_ci			 unsigned int height, unsigned int user)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	if ((width << 1) * height > vga_vram_size)
105262306a36Sopenharmony_ci		return -EINVAL;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	if (user) {
105562306a36Sopenharmony_ci		/*
105662306a36Sopenharmony_ci		 * Ho ho!  Someone (svgatextmode, eh?) may have reprogrammed
105762306a36Sopenharmony_ci		 * the video mode!  Set the new defaults then and go away.
105862306a36Sopenharmony_ci		 */
105962306a36Sopenharmony_ci		screen_info.orig_video_cols = width;
106062306a36Sopenharmony_ci		screen_info.orig_video_lines = height;
106162306a36Sopenharmony_ci		vga_default_font_height = c->vc_cell_height;
106262306a36Sopenharmony_ci		return 0;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci	if (width % 2 || width > screen_info.orig_video_cols ||
106562306a36Sopenharmony_ci	    height > (screen_info.orig_video_lines * vga_default_font_height)/
106662306a36Sopenharmony_ci	    c->vc_cell_height)
106762306a36Sopenharmony_ci		return -EINVAL;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	if (con_is_visible(c) && !vga_is_gfx) /* who knows */
107062306a36Sopenharmony_ci		vgacon_doresize(c, width, height);
107162306a36Sopenharmony_ci	return 0;
107262306a36Sopenharmony_ci}
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic int vgacon_set_origin(struct vc_data *c)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
107762306a36Sopenharmony_ci	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
107862306a36Sopenharmony_ci		return 0;
107962306a36Sopenharmony_ci	c->vc_origin = c->vc_visible_origin = vga_vram_base;
108062306a36Sopenharmony_ci	vga_set_mem_top(c);
108162306a36Sopenharmony_ci	vga_rolled_over = 0;
108262306a36Sopenharmony_ci	return 1;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic void vgacon_save_screen(struct vc_data *c)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	static int vga_bootup_console = 0;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!vga_bootup_console) {
109062306a36Sopenharmony_ci		/* This is a gross hack, but here is the only place we can
109162306a36Sopenharmony_ci		 * set bootup console parameters without messing up generic
109262306a36Sopenharmony_ci		 * console initialization routines.
109362306a36Sopenharmony_ci		 */
109462306a36Sopenharmony_ci		vga_bootup_console = 1;
109562306a36Sopenharmony_ci		c->state.x = screen_info.orig_x;
109662306a36Sopenharmony_ci		c->state.y = screen_info.orig_y;
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	/* We can't copy in more than the size of the video buffer,
110062306a36Sopenharmony_ci	 * or we'll be copying in VGA BIOS */
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	if (!vga_is_gfx)
110362306a36Sopenharmony_ci		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
110462306a36Sopenharmony_ci			    c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
110862306a36Sopenharmony_ci		enum con_scroll dir, unsigned int lines)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	unsigned long oldo;
111162306a36Sopenharmony_ci	unsigned int delta;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
111462306a36Sopenharmony_ci		return false;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
111762306a36Sopenharmony_ci		return false;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	vgacon_restore_screen(c);
112062306a36Sopenharmony_ci	oldo = c->vc_origin;
112162306a36Sopenharmony_ci	delta = lines * c->vc_size_row;
112262306a36Sopenharmony_ci	if (dir == SM_UP) {
112362306a36Sopenharmony_ci		if (c->vc_scr_end + delta >= vga_vram_end) {
112462306a36Sopenharmony_ci			scr_memcpyw((u16 *) vga_vram_base,
112562306a36Sopenharmony_ci				    (u16 *) (oldo + delta),
112662306a36Sopenharmony_ci				    c->vc_screenbuf_size - delta);
112762306a36Sopenharmony_ci			c->vc_origin = vga_vram_base;
112862306a36Sopenharmony_ci			vga_rolled_over = oldo - vga_vram_base;
112962306a36Sopenharmony_ci		} else
113062306a36Sopenharmony_ci			c->vc_origin += delta;
113162306a36Sopenharmony_ci		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
113262306a36Sopenharmony_ci				     delta), c->vc_video_erase_char,
113362306a36Sopenharmony_ci			    delta);
113462306a36Sopenharmony_ci	} else {
113562306a36Sopenharmony_ci		if (oldo - delta < vga_vram_base) {
113662306a36Sopenharmony_ci			scr_memmovew((u16 *) (vga_vram_end -
113762306a36Sopenharmony_ci					      c->vc_screenbuf_size +
113862306a36Sopenharmony_ci					      delta), (u16 *) oldo,
113962306a36Sopenharmony_ci				     c->vc_screenbuf_size - delta);
114062306a36Sopenharmony_ci			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
114162306a36Sopenharmony_ci			vga_rolled_over = 0;
114262306a36Sopenharmony_ci		} else
114362306a36Sopenharmony_ci			c->vc_origin -= delta;
114462306a36Sopenharmony_ci		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
114562306a36Sopenharmony_ci		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
114662306a36Sopenharmony_ci			    delta);
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
114962306a36Sopenharmony_ci	c->vc_visible_origin = c->vc_origin;
115062306a36Sopenharmony_ci	vga_set_mem_top(c);
115162306a36Sopenharmony_ci	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
115262306a36Sopenharmony_ci	return true;
115362306a36Sopenharmony_ci}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci/*
115662306a36Sopenharmony_ci *  The console `switch' structure for the VGA based console
115762306a36Sopenharmony_ci */
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
116062306a36Sopenharmony_ci			 int width) { }
116162306a36Sopenharmony_cistatic void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
116262306a36Sopenharmony_cistatic void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
116362306a36Sopenharmony_ci			 int count, int ypos, int xpos) { }
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ciconst struct consw vga_con = {
116662306a36Sopenharmony_ci	.owner = THIS_MODULE,
116762306a36Sopenharmony_ci	.con_startup = vgacon_startup,
116862306a36Sopenharmony_ci	.con_init = vgacon_init,
116962306a36Sopenharmony_ci	.con_deinit = vgacon_deinit,
117062306a36Sopenharmony_ci	.con_clear = vgacon_clear,
117162306a36Sopenharmony_ci	.con_putc = vgacon_putc,
117262306a36Sopenharmony_ci	.con_putcs = vgacon_putcs,
117362306a36Sopenharmony_ci	.con_cursor = vgacon_cursor,
117462306a36Sopenharmony_ci	.con_scroll = vgacon_scroll,
117562306a36Sopenharmony_ci	.con_switch = vgacon_switch,
117662306a36Sopenharmony_ci	.con_blank = vgacon_blank,
117762306a36Sopenharmony_ci	.con_font_set = vgacon_font_set,
117862306a36Sopenharmony_ci	.con_font_get = vgacon_font_get,
117962306a36Sopenharmony_ci	.con_resize = vgacon_resize,
118062306a36Sopenharmony_ci	.con_set_palette = vgacon_set_palette,
118162306a36Sopenharmony_ci	.con_scrolldelta = vgacon_scrolldelta,
118262306a36Sopenharmony_ci	.con_set_origin = vgacon_set_origin,
118362306a36Sopenharmony_ci	.con_save_screen = vgacon_save_screen,
118462306a36Sopenharmony_ci	.con_build_attr = vgacon_build_attr,
118562306a36Sopenharmony_ci	.con_invert_region = vgacon_invert_region,
118662306a36Sopenharmony_ci};
118762306a36Sopenharmony_ciEXPORT_SYMBOL(vga_con);
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1190