cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vgacon.c (36725B)


      1/*
      2 *  linux/drivers/video/vgacon.c -- Low level VGA based console driver
      3 *
      4 *	Created 28 Sep 1997 by Geert Uytterhoeven
      5 *
      6 *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998
      7 *
      8 *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.
      9 *
     10 *	Copyright (C) 1991, 1992  Linus Torvalds
     11 *			    1995  Jay Estabrook
     12 *
     13 *	User definable mapping table and font loading by Eugene G. Crosser,
     14 *	<crosser@average.org>
     15 *
     16 *	Improved loadable font/UTF-8 support by H. Peter Anvin
     17 *	Feb-Sep 1995 <peter.anvin@linux.org>
     18 *
     19 *	Colour palette handling, by Simon Tatham
     20 *	17-Jun-95 <sgt20@cam.ac.uk>
     21 *
     22 *	if 512 char mode is already enabled don't re-enable it,
     23 *	because it causes screen to flicker, by Mitja Horvat
     24 *	5-May-96 <mitja.horvat@guest.arnes.si>
     25 *
     26 *	Use 2 outw instead of 4 outb_p to reduce erroneous text
     27 *	flashing on RHS of screen during heavy console scrolling .
     28 *	Oct 1996, Paul Gortmaker.
     29 *
     30 *
     31 *  This file is subject to the terms and conditions of the GNU General Public
     32 *  License.  See the file COPYING in the main directory of this archive for
     33 *  more details.
     34 */
     35
     36#include <linux/module.h>
     37#include <linux/types.h>
     38#include <linux/fs.h>
     39#include <linux/kernel.h>
     40#include <linux/console.h>
     41#include <linux/string.h>
     42#include <linux/kd.h>
     43#include <linux/slab.h>
     44#include <linux/vt_kern.h>
     45#include <linux/sched.h>
     46#include <linux/selection.h>
     47#include <linux/spinlock.h>
     48#include <linux/ioport.h>
     49#include <linux/init.h>
     50#include <linux/screen_info.h>
     51#include <video/vga.h>
     52#include <asm/io.h>
     53
     54static DEFINE_RAW_SPINLOCK(vga_lock);
     55static int cursor_size_lastfrom;
     56static int cursor_size_lastto;
     57static u32 vgacon_xres;
     58static u32 vgacon_yres;
     59static struct vgastate vgastate;
     60
     61#define BLANK 0x0020
     62
     63#define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */
     64/*
     65 *  Interface used by the world
     66 */
     67
     68static const char *vgacon_startup(void);
     69static void vgacon_init(struct vc_data *c, int init);
     70static void vgacon_deinit(struct vc_data *c);
     71static void vgacon_cursor(struct vc_data *c, int mode);
     72static int vgacon_switch(struct vc_data *c);
     73static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);
     74static void vgacon_scrolldelta(struct vc_data *c, int lines);
     75static int vgacon_set_origin(struct vc_data *c);
     76static void vgacon_save_screen(struct vc_data *c);
     77static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
     78static struct uni_pagedir *vgacon_uni_pagedir;
     79static int vgacon_refcount;
     80
     81/* Description of the hardware situation */
     82static unsigned long	vga_vram_base		__read_mostly;	/* Base of video memory */
     83static unsigned long	vga_vram_end		__read_mostly;	/* End of video memory */
     84static unsigned int	vga_vram_size		__read_mostly;	/* Size of video memory */
     85static u16		vga_video_port_reg	__read_mostly;	/* Video register select port */
     86static u16		vga_video_port_val	__read_mostly;	/* Video register value port */
     87static unsigned int	vga_video_num_columns;			/* Number of text columns */
     88static unsigned int	vga_video_num_lines;			/* Number of text lines */
     89static bool		vga_can_do_color;			/* Do we support colors? */
     90static unsigned int	vga_default_font_height __read_mostly;	/* Height of default screen font */
     91static unsigned char	vga_video_type		__read_mostly;	/* Card type */
     92static int		vga_vesa_blanked;
     93static bool 		vga_palette_blanked;
     94static bool 		vga_is_gfx;
     95static bool 		vga_512_chars;
     96static int 		vga_video_font_height;
     97static int 		vga_scan_lines		__read_mostly;
     98static unsigned int 	vga_rolled_over; /* last vc_origin offset before wrap */
     99
    100static bool vga_hardscroll_enabled;
    101static bool vga_hardscroll_user_enable = true;
    102
    103static int __init no_scroll(char *str)
    104{
    105	/*
    106	 * Disabling scrollback is required for the Braillex ib80-piezo
    107	 * Braille reader made by F.H. Papenmeier (Germany).
    108	 * Use the "no-scroll" bootflag.
    109	 */
    110	vga_hardscroll_user_enable = vga_hardscroll_enabled = false;
    111	return 1;
    112}
    113
    114__setup("no-scroll", no_scroll);
    115
    116/*
    117 * By replacing the four outb_p with two back to back outw, we can reduce
    118 * the window of opportunity to see text mislocated to the RHS of the
    119 * console during heavy scrolling activity. However there is the remote
    120 * possibility that some pre-dinosaur hardware won't like the back to back
    121 * I/O. Since the Xservers get away with it, we should be able to as well.
    122 */
    123static inline void write_vga(unsigned char reg, unsigned int val)
    124{
    125	unsigned int v1, v2;
    126	unsigned long flags;
    127
    128	/*
    129	 * ddprintk might set the console position from interrupt
    130	 * handlers, thus the write has to be IRQ-atomic.
    131	 */
    132	raw_spin_lock_irqsave(&vga_lock, flags);
    133	v1 = reg + (val & 0xff00);
    134	v2 = reg + 1 + ((val << 8) & 0xff00);
    135	outw(v1, vga_video_port_reg);
    136	outw(v2, vga_video_port_reg);
    137	raw_spin_unlock_irqrestore(&vga_lock, flags);
    138}
    139
    140static inline void vga_set_mem_top(struct vc_data *c)
    141{
    142	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);
    143}
    144
    145static void vgacon_restore_screen(struct vc_data *c)
    146{
    147	if (c->vc_origin != c->vc_visible_origin)
    148		vgacon_scrolldelta(c, 0);
    149}
    150
    151static void vgacon_scrolldelta(struct vc_data *c, int lines)
    152{
    153	vc_scrolldelta_helper(c, lines, vga_rolled_over, (void *)vga_vram_base,
    154			vga_vram_size);
    155	vga_set_mem_top(c);
    156}
    157
    158static const char *vgacon_startup(void)
    159{
    160	const char *display_desc = NULL;
    161	u16 saved1, saved2;
    162	volatile u16 *p;
    163
    164	if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB ||
    165	    screen_info.orig_video_isVGA == VIDEO_TYPE_EFI) {
    166	      no_vga:
    167#ifdef CONFIG_DUMMY_CONSOLE
    168		conswitchp = &dummy_con;
    169		return conswitchp->con_startup();
    170#else
    171		return NULL;
    172#endif
    173	}
    174
    175	/* boot_params.screen_info reasonably initialized? */
    176	if ((screen_info.orig_video_lines == 0) ||
    177	    (screen_info.orig_video_cols  == 0))
    178		goto no_vga;
    179
    180	/* VGA16 modes are not handled by VGACON */
    181	if ((screen_info.orig_video_mode == 0x0D) ||	/* 320x200/4 */
    182	    (screen_info.orig_video_mode == 0x0E) ||	/* 640x200/4 */
    183	    (screen_info.orig_video_mode == 0x10) ||	/* 640x350/4 */
    184	    (screen_info.orig_video_mode == 0x12) ||	/* 640x480/4 */
    185	    (screen_info.orig_video_mode == 0x6A))	/* 800x600/4 (VESA) */
    186		goto no_vga;
    187
    188	vga_video_num_lines = screen_info.orig_video_lines;
    189	vga_video_num_columns = screen_info.orig_video_cols;
    190	vgastate.vgabase = NULL;
    191
    192	if (screen_info.orig_video_mode == 7) {
    193		/* Monochrome display */
    194		vga_vram_base = 0xb0000;
    195		vga_video_port_reg = VGA_CRT_IM;
    196		vga_video_port_val = VGA_CRT_DM;
    197		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
    198			static struct resource ega_console_resource =
    199			    { .name	= "ega",
    200			      .flags	= IORESOURCE_IO,
    201			      .start	= 0x3B0,
    202			      .end	= 0x3BF };
    203			vga_video_type = VIDEO_TYPE_EGAM;
    204			vga_vram_size = 0x8000;
    205			display_desc = "EGA+";
    206			request_resource(&ioport_resource,
    207					 &ega_console_resource);
    208		} else {
    209			static struct resource mda1_console_resource =
    210			    { .name	= "mda",
    211			      .flags	= IORESOURCE_IO,
    212			      .start	= 0x3B0,
    213			      .end	= 0x3BB };
    214			static struct resource mda2_console_resource =
    215			    { .name	= "mda",
    216			      .flags	= IORESOURCE_IO,
    217			      .start	= 0x3BF,
    218			      .end	= 0x3BF };
    219			vga_video_type = VIDEO_TYPE_MDA;
    220			vga_vram_size = 0x2000;
    221			display_desc = "*MDA";
    222			request_resource(&ioport_resource,
    223					 &mda1_console_resource);
    224			request_resource(&ioport_resource,
    225					 &mda2_console_resource);
    226			vga_video_font_height = 14;
    227		}
    228	} else {
    229		/* If not, it is color. */
    230		vga_can_do_color = true;
    231		vga_vram_base = 0xb8000;
    232		vga_video_port_reg = VGA_CRT_IC;
    233		vga_video_port_val = VGA_CRT_DC;
    234		if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
    235			int i;
    236
    237			vga_vram_size = 0x8000;
    238
    239			if (!screen_info.orig_video_isVGA) {
    240				static struct resource ega_console_resource =
    241				    { .name	= "ega",
    242				      .flags	= IORESOURCE_IO,
    243				      .start	= 0x3C0,
    244				      .end	= 0x3DF };
    245				vga_video_type = VIDEO_TYPE_EGAC;
    246				display_desc = "EGA";
    247				request_resource(&ioport_resource,
    248						 &ega_console_resource);
    249			} else {
    250				static struct resource vga_console_resource =
    251				    { .name	= "vga+",
    252				      .flags	= IORESOURCE_IO,
    253				      .start	= 0x3C0,
    254				      .end	= 0x3DF };
    255				vga_video_type = VIDEO_TYPE_VGAC;
    256				display_desc = "VGA+";
    257				request_resource(&ioport_resource,
    258						 &vga_console_resource);
    259
    260				/*
    261				 * Normalise the palette registers, to point
    262				 * the 16 screen colours to the first 16
    263				 * DAC entries.
    264				 */
    265
    266				for (i = 0; i < 16; i++) {
    267					inb_p(VGA_IS1_RC);
    268					outb_p(i, VGA_ATT_W);
    269					outb_p(i, VGA_ATT_W);
    270				}
    271				outb_p(0x20, VGA_ATT_W);
    272
    273				/*
    274				 * Now set the DAC registers back to their
    275				 * default values
    276				 */
    277				for (i = 0; i < 16; i++) {
    278					outb_p(color_table[i], VGA_PEL_IW);
    279					outb_p(default_red[i], VGA_PEL_D);
    280					outb_p(default_grn[i], VGA_PEL_D);
    281					outb_p(default_blu[i], VGA_PEL_D);
    282				}
    283			}
    284		} else {
    285			static struct resource cga_console_resource =
    286			    { .name	= "cga",
    287			      .flags	= IORESOURCE_IO,
    288			      .start	= 0x3D4,
    289			      .end	= 0x3D5 };
    290			vga_video_type = VIDEO_TYPE_CGA;
    291			vga_vram_size = 0x2000;
    292			display_desc = "*CGA";
    293			request_resource(&ioport_resource,
    294					 &cga_console_resource);
    295			vga_video_font_height = 8;
    296		}
    297	}
    298
    299	vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size);
    300	vga_vram_end = vga_vram_base + vga_vram_size;
    301
    302	/*
    303	 *      Find out if there is a graphics card present.
    304	 *      Are there smarter methods around?
    305	 */
    306	p = (volatile u16 *) vga_vram_base;
    307	saved1 = scr_readw(p);
    308	saved2 = scr_readw(p + 1);
    309	scr_writew(0xAA55, p);
    310	scr_writew(0x55AA, p + 1);
    311	if (scr_readw(p) != 0xAA55 || scr_readw(p + 1) != 0x55AA) {
    312		scr_writew(saved1, p);
    313		scr_writew(saved2, p + 1);
    314		goto no_vga;
    315	}
    316	scr_writew(0x55AA, p);
    317	scr_writew(0xAA55, p + 1);
    318	if (scr_readw(p) != 0x55AA || scr_readw(p + 1) != 0xAA55) {
    319		scr_writew(saved1, p);
    320		scr_writew(saved2, p + 1);
    321		goto no_vga;
    322	}
    323	scr_writew(saved1, p);
    324	scr_writew(saved2, p + 1);
    325
    326	if (vga_video_type == VIDEO_TYPE_EGAC
    327	    || vga_video_type == VIDEO_TYPE_VGAC
    328	    || vga_video_type == VIDEO_TYPE_EGAM) {
    329		vga_hardscroll_enabled = vga_hardscroll_user_enable;
    330		vga_default_font_height = screen_info.orig_video_points;
    331		vga_video_font_height = screen_info.orig_video_points;
    332		/* This may be suboptimal but is a safe bet - go with it */
    333		vga_scan_lines =
    334		    vga_video_font_height * vga_video_num_lines;
    335	}
    336
    337	vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
    338	vgacon_yres = vga_scan_lines;
    339
    340	return display_desc;
    341}
    342
    343static void vgacon_init(struct vc_data *c, int init)
    344{
    345	struct uni_pagedir *p;
    346
    347	/*
    348	 * We cannot be loaded as a module, therefore init will be 1
    349	 * if we are the default console, however if we are a fallback
    350	 * console, for example if fbcon has failed registration, then
    351	 * init will be 0, so we need to make sure our boot parameters
    352	 * have been copied to the console structure for vgacon_resize
    353	 * ultimately called by vc_resize.  Any subsequent calls to
    354	 * vgacon_init init will have init set to 0 too.
    355	 */
    356	c->vc_can_do_color = vga_can_do_color;
    357	c->vc_scan_lines = vga_scan_lines;
    358	c->vc_font.height = c->vc_cell_height = vga_video_font_height;
    359
    360	/* set dimensions manually if init != 0 since vc_resize() will fail */
    361	if (init) {
    362		c->vc_cols = vga_video_num_columns;
    363		c->vc_rows = vga_video_num_lines;
    364	} else
    365		vc_resize(c, vga_video_num_columns, vga_video_num_lines);
    366
    367	c->vc_complement_mask = 0x7700;
    368	if (vga_512_chars)
    369		c->vc_hi_font_mask = 0x0800;
    370	p = *c->vc_uni_pagedir_loc;
    371	if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
    372		con_free_unimap(c);
    373		c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
    374		vgacon_refcount++;
    375	}
    376	if (!vgacon_uni_pagedir && p)
    377		con_set_default_unimap(c);
    378
    379	/* Only set the default if the user didn't deliberately override it */
    380	if (global_cursor_default == -1)
    381		global_cursor_default =
    382			!(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
    383}
    384
    385static void vgacon_deinit(struct vc_data *c)
    386{
    387	/* When closing the active console, reset video origin */
    388	if (con_is_visible(c)) {
    389		c->vc_visible_origin = vga_vram_base;
    390		vga_set_mem_top(c);
    391	}
    392
    393	if (!--vgacon_refcount)
    394		con_free_unimap(c);
    395	c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
    396	con_set_default_unimap(c);
    397}
    398
    399static u8 vgacon_build_attr(struct vc_data *c, u8 color,
    400			    enum vc_intensity intensity,
    401			    bool blink, bool underline, bool reverse,
    402			    bool italic)
    403{
    404	u8 attr = color;
    405
    406	if (vga_can_do_color) {
    407		if (italic)
    408			attr = (attr & 0xF0) | c->vc_itcolor;
    409		else if (underline)
    410			attr = (attr & 0xf0) | c->vc_ulcolor;
    411		else if (intensity == VCI_HALF_BRIGHT)
    412			attr = (attr & 0xf0) | c->vc_halfcolor;
    413	}
    414	if (reverse)
    415		attr =
    416		    ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) &
    417				       0x77);
    418	if (blink)
    419		attr ^= 0x80;
    420	if (intensity == VCI_BOLD)
    421		attr ^= 0x08;
    422	if (!vga_can_do_color) {
    423		if (italic)
    424			attr = (attr & 0xF8) | 0x02;
    425		else if (underline)
    426			attr = (attr & 0xf8) | 0x01;
    427		else if (intensity == VCI_HALF_BRIGHT)
    428			attr = (attr & 0xf0) | 0x08;
    429	}
    430	return attr;
    431}
    432
    433static void vgacon_invert_region(struct vc_data *c, u16 * p, int count)
    434{
    435	const bool col = vga_can_do_color;
    436
    437	while (count--) {
    438		u16 a = scr_readw(p);
    439		if (col)
    440			a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
    441			    (((a) & 0x0700) << 4);
    442		else
    443			a ^= ((a & 0x0700) == 0x0100) ? 0x7000 : 0x7700;
    444		scr_writew(a, p++);
    445	}
    446}
    447
    448static void vgacon_set_cursor_size(int xpos, int from, int to)
    449{
    450	unsigned long flags;
    451	int curs, cure;
    452
    453	if ((from == cursor_size_lastfrom) && (to == cursor_size_lastto))
    454		return;
    455	cursor_size_lastfrom = from;
    456	cursor_size_lastto = to;
    457
    458	raw_spin_lock_irqsave(&vga_lock, flags);
    459	if (vga_video_type >= VIDEO_TYPE_VGAC) {
    460		outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
    461		curs = inb_p(vga_video_port_val);
    462		outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
    463		cure = inb_p(vga_video_port_val);
    464	} else {
    465		curs = 0;
    466		cure = 0;
    467	}
    468
    469	curs = (curs & 0xc0) | from;
    470	cure = (cure & 0xe0) | to;
    471
    472	outb_p(VGA_CRTC_CURSOR_START, vga_video_port_reg);
    473	outb_p(curs, vga_video_port_val);
    474	outb_p(VGA_CRTC_CURSOR_END, vga_video_port_reg);
    475	outb_p(cure, vga_video_port_val);
    476	raw_spin_unlock_irqrestore(&vga_lock, flags);
    477}
    478
    479static void vgacon_cursor(struct vc_data *c, int mode)
    480{
    481	if (c->vc_mode != KD_TEXT)
    482		return;
    483
    484	vgacon_restore_screen(c);
    485
    486	switch (mode) {
    487	case CM_ERASE:
    488		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
    489	        if (vga_video_type >= VIDEO_TYPE_VGAC)
    490			vgacon_set_cursor_size(c->state.x, 31, 30);
    491		else
    492			vgacon_set_cursor_size(c->state.x, 31, 31);
    493		break;
    494
    495	case CM_MOVE:
    496	case CM_DRAW:
    497		write_vga(14, (c->vc_pos - vga_vram_base) / 2);
    498		switch (CUR_SIZE(c->vc_cursor_type)) {
    499		case CUR_UNDERLINE:
    500			vgacon_set_cursor_size(c->state.x,
    501					       c->vc_cell_height -
    502					       (c->vc_cell_height <
    503						10 ? 2 : 3),
    504					       c->vc_cell_height -
    505					       (c->vc_cell_height <
    506						10 ? 1 : 2));
    507			break;
    508		case CUR_TWO_THIRDS:
    509			vgacon_set_cursor_size(c->state.x,
    510					       c->vc_cell_height / 3,
    511					       c->vc_cell_height -
    512					       (c->vc_cell_height <
    513						10 ? 1 : 2));
    514			break;
    515		case CUR_LOWER_THIRD:
    516			vgacon_set_cursor_size(c->state.x,
    517					       (c->vc_cell_height * 2) / 3,
    518					       c->vc_cell_height -
    519					       (c->vc_cell_height <
    520						10 ? 1 : 2));
    521			break;
    522		case CUR_LOWER_HALF:
    523			vgacon_set_cursor_size(c->state.x,
    524					       c->vc_cell_height / 2,
    525					       c->vc_cell_height -
    526					       (c->vc_cell_height <
    527						10 ? 1 : 2));
    528			break;
    529		case CUR_NONE:
    530			if (vga_video_type >= VIDEO_TYPE_VGAC)
    531				vgacon_set_cursor_size(c->state.x, 31, 30);
    532			else
    533				vgacon_set_cursor_size(c->state.x, 31, 31);
    534			break;
    535		default:
    536			vgacon_set_cursor_size(c->state.x, 1,
    537					       c->vc_cell_height);
    538			break;
    539		}
    540		break;
    541	}
    542}
    543
    544static int vgacon_doresize(struct vc_data *c,
    545		unsigned int width, unsigned int height)
    546{
    547	unsigned long flags;
    548	unsigned int scanlines = height * c->vc_cell_height;
    549	u8 scanlines_lo = 0, r7 = 0, vsync_end = 0, mode, max_scan;
    550
    551	raw_spin_lock_irqsave(&vga_lock, flags);
    552
    553	vgacon_xres = width * VGA_FONTWIDTH;
    554	vgacon_yres = height * c->vc_cell_height;
    555	if (vga_video_type >= VIDEO_TYPE_VGAC) {
    556		outb_p(VGA_CRTC_MAX_SCAN, vga_video_port_reg);
    557		max_scan = inb_p(vga_video_port_val);
    558
    559		if (max_scan & 0x80)
    560			scanlines <<= 1;
    561
    562		outb_p(VGA_CRTC_MODE, vga_video_port_reg);
    563		mode = inb_p(vga_video_port_val);
    564
    565		if (mode & 0x04)
    566			scanlines >>= 1;
    567
    568		scanlines -= 1;
    569		scanlines_lo = scanlines & 0xff;
    570
    571		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
    572		r7 = inb_p(vga_video_port_val) & ~0x42;
    573
    574		if (scanlines & 0x100)
    575			r7 |= 0x02;
    576		if (scanlines & 0x200)
    577			r7 |= 0x40;
    578
    579		/* deprotect registers */
    580		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
    581		vsync_end = inb_p(vga_video_port_val);
    582		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
    583		outb_p(vsync_end & ~0x80, vga_video_port_val);
    584	}
    585
    586	outb_p(VGA_CRTC_H_DISP, vga_video_port_reg);
    587	outb_p(width - 1, vga_video_port_val);
    588	outb_p(VGA_CRTC_OFFSET, vga_video_port_reg);
    589	outb_p(width >> 1, vga_video_port_val);
    590
    591	if (vga_video_type >= VIDEO_TYPE_VGAC) {
    592		outb_p(VGA_CRTC_V_DISP_END, vga_video_port_reg);
    593		outb_p(scanlines_lo, vga_video_port_val);
    594		outb_p(VGA_CRTC_OVERFLOW, vga_video_port_reg);
    595		outb_p(r7,vga_video_port_val);
    596
    597		/* reprotect registers */
    598		outb_p(VGA_CRTC_V_SYNC_END, vga_video_port_reg);
    599		outb_p(vsync_end, vga_video_port_val);
    600	}
    601
    602	raw_spin_unlock_irqrestore(&vga_lock, flags);
    603	return 0;
    604}
    605
    606static int vgacon_switch(struct vc_data *c)
    607{
    608	int x = c->vc_cols * VGA_FONTWIDTH;
    609	int y = c->vc_rows * c->vc_cell_height;
    610	int rows = screen_info.orig_video_lines * vga_default_font_height/
    611		c->vc_cell_height;
    612	/*
    613	 * We need to save screen size here as it's the only way
    614	 * we can spot the screen has been resized and we need to
    615	 * set size of freshly allocated screens ourselves.
    616	 */
    617	vga_video_num_columns = c->vc_cols;
    618	vga_video_num_lines = c->vc_rows;
    619
    620	/* We can only copy out the size of the video buffer here,
    621	 * otherwise we get into VGA BIOS */
    622
    623	if (!vga_is_gfx) {
    624		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,
    625			    c->vc_screenbuf_size > vga_vram_size ?
    626				vga_vram_size : c->vc_screenbuf_size);
    627
    628		if ((vgacon_xres != x || vgacon_yres != y) &&
    629		    (!(vga_video_num_columns % 2) &&
    630		     vga_video_num_columns <= screen_info.orig_video_cols &&
    631		     vga_video_num_lines <= rows))
    632			vgacon_doresize(c, c->vc_cols, c->vc_rows);
    633	}
    634
    635	return 0;		/* Redrawing not needed */
    636}
    637
    638static void vga_set_palette(struct vc_data *vc, const unsigned char *table)
    639{
    640	int i, j;
    641
    642	vga_w(vgastate.vgabase, VGA_PEL_MSK, 0xff);
    643	for (i = j = 0; i < 16; i++) {
    644		vga_w(vgastate.vgabase, VGA_PEL_IW, table[i]);
    645		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
    646		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
    647		vga_w(vgastate.vgabase, VGA_PEL_D, vc->vc_palette[j++] >> 2);
    648	}
    649}
    650
    651static void vgacon_set_palette(struct vc_data *vc, const unsigned char *table)
    652{
    653	if (vga_video_type != VIDEO_TYPE_VGAC || vga_palette_blanked
    654	    || !con_is_visible(vc))
    655		return;
    656	vga_set_palette(vc, table);
    657}
    658
    659/* structure holding original VGA register settings */
    660static struct {
    661	unsigned char SeqCtrlIndex;	/* Sequencer Index reg.   */
    662	unsigned char CrtCtrlIndex;	/* CRT-Contr. Index reg.  */
    663	unsigned char CrtMiscIO;	/* Miscellaneous register */
    664	unsigned char HorizontalTotal;	/* CRT-Controller:00h */
    665	unsigned char HorizDisplayEnd;	/* CRT-Controller:01h */
    666	unsigned char StartHorizRetrace;	/* CRT-Controller:04h */
    667	unsigned char EndHorizRetrace;	/* CRT-Controller:05h */
    668	unsigned char Overflow;	/* CRT-Controller:07h */
    669	unsigned char StartVertRetrace;	/* CRT-Controller:10h */
    670	unsigned char EndVertRetrace;	/* CRT-Controller:11h */
    671	unsigned char ModeControl;	/* CRT-Controller:17h */
    672	unsigned char ClockingMode;	/* Seq-Controller:01h */
    673} vga_state;
    674
    675static void vga_vesa_blank(struct vgastate *state, int mode)
    676{
    677	/* save original values of VGA controller registers */
    678	if (!vga_vesa_blanked) {
    679		raw_spin_lock_irq(&vga_lock);
    680		vga_state.SeqCtrlIndex = vga_r(state->vgabase, VGA_SEQ_I);
    681		vga_state.CrtCtrlIndex = inb_p(vga_video_port_reg);
    682		vga_state.CrtMiscIO = vga_r(state->vgabase, VGA_MIS_R);
    683		raw_spin_unlock_irq(&vga_lock);
    684
    685		outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
    686		vga_state.HorizontalTotal = inb_p(vga_video_port_val);
    687		outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
    688		vga_state.HorizDisplayEnd = inb_p(vga_video_port_val);
    689		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
    690		vga_state.StartHorizRetrace = inb_p(vga_video_port_val);
    691		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
    692		vga_state.EndHorizRetrace = inb_p(vga_video_port_val);
    693		outb_p(0x07, vga_video_port_reg);	/* Overflow */
    694		vga_state.Overflow = inb_p(vga_video_port_val);
    695		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
    696		vga_state.StartVertRetrace = inb_p(vga_video_port_val);
    697		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
    698		vga_state.EndVertRetrace = inb_p(vga_video_port_val);
    699		outb_p(0x17, vga_video_port_reg);	/* ModeControl */
    700		vga_state.ModeControl = inb_p(vga_video_port_val);
    701		vga_state.ClockingMode = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
    702	}
    703
    704	/* assure that video is enabled */
    705	/* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */
    706	raw_spin_lock_irq(&vga_lock);
    707	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode | 0x20);
    708
    709	/* test for vertical retrace in process.... */
    710	if ((vga_state.CrtMiscIO & 0x80) == 0x80)
    711		vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO & 0xEF);
    712
    713	/*
    714	 * Set <End of vertical retrace> to minimum (0) and
    715	 * <Start of vertical Retrace> to maximum (incl. overflow)
    716	 * Result: turn off vertical sync (VSync) pulse.
    717	 */
    718	if (mode & VESA_VSYNC_SUSPEND) {
    719		outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
    720		outb_p(0xff, vga_video_port_val);	/* maximum value */
    721		outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
    722		outb_p(0x40, vga_video_port_val);	/* minimum (bits 0..3)  */
    723		outb_p(0x07, vga_video_port_reg);	/* Overflow */
    724		outb_p(vga_state.Overflow | 0x84, vga_video_port_val);	/* bits 9,10 of vert. retrace */
    725	}
    726
    727	if (mode & VESA_HSYNC_SUSPEND) {
    728		/*
    729		 * Set <End of horizontal retrace> to minimum (0) and
    730		 *  <Start of horizontal Retrace> to maximum
    731		 * Result: turn off horizontal sync (HSync) pulse.
    732		 */
    733		outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
    734		outb_p(0xff, vga_video_port_val);	/* maximum */
    735		outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
    736		outb_p(0x00, vga_video_port_val);	/* minimum (0) */
    737	}
    738
    739	/* restore both index registers */
    740	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
    741	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
    742	raw_spin_unlock_irq(&vga_lock);
    743}
    744
    745static void vga_vesa_unblank(struct vgastate *state)
    746{
    747	/* restore original values of VGA controller registers */
    748	raw_spin_lock_irq(&vga_lock);
    749	vga_w(state->vgabase, VGA_MIS_W, vga_state.CrtMiscIO);
    750
    751	outb_p(0x00, vga_video_port_reg);	/* HorizontalTotal */
    752	outb_p(vga_state.HorizontalTotal, vga_video_port_val);
    753	outb_p(0x01, vga_video_port_reg);	/* HorizDisplayEnd */
    754	outb_p(vga_state.HorizDisplayEnd, vga_video_port_val);
    755	outb_p(0x04, vga_video_port_reg);	/* StartHorizRetrace */
    756	outb_p(vga_state.StartHorizRetrace, vga_video_port_val);
    757	outb_p(0x05, vga_video_port_reg);	/* EndHorizRetrace */
    758	outb_p(vga_state.EndHorizRetrace, vga_video_port_val);
    759	outb_p(0x07, vga_video_port_reg);	/* Overflow */
    760	outb_p(vga_state.Overflow, vga_video_port_val);
    761	outb_p(0x10, vga_video_port_reg);	/* StartVertRetrace */
    762	outb_p(vga_state.StartVertRetrace, vga_video_port_val);
    763	outb_p(0x11, vga_video_port_reg);	/* EndVertRetrace */
    764	outb_p(vga_state.EndVertRetrace, vga_video_port_val);
    765	outb_p(0x17, vga_video_port_reg);	/* ModeControl */
    766	outb_p(vga_state.ModeControl, vga_video_port_val);
    767	/* ClockingMode */
    768	vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE, vga_state.ClockingMode);
    769
    770	/* restore index/control registers */
    771	vga_w(state->vgabase, VGA_SEQ_I, vga_state.SeqCtrlIndex);
    772	outb_p(vga_state.CrtCtrlIndex, vga_video_port_reg);
    773	raw_spin_unlock_irq(&vga_lock);
    774}
    775
    776static void vga_pal_blank(struct vgastate *state)
    777{
    778	int i;
    779
    780	vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
    781	for (i = 0; i < 16; i++) {
    782		vga_w(state->vgabase, VGA_PEL_IW, i);
    783		vga_w(state->vgabase, VGA_PEL_D, 0);
    784		vga_w(state->vgabase, VGA_PEL_D, 0);
    785		vga_w(state->vgabase, VGA_PEL_D, 0);
    786	}
    787}
    788
    789static int vgacon_blank(struct vc_data *c, int blank, int mode_switch)
    790{
    791	switch (blank) {
    792	case 0:		/* Unblank */
    793		if (vga_vesa_blanked) {
    794			vga_vesa_unblank(&vgastate);
    795			vga_vesa_blanked = 0;
    796		}
    797		if (vga_palette_blanked) {
    798			vga_set_palette(c, color_table);
    799			vga_palette_blanked = false;
    800			return 0;
    801		}
    802		vga_is_gfx = false;
    803		/* Tell console.c that it has to restore the screen itself */
    804		return 1;
    805	case 1:		/* Normal blanking */
    806	case -1:	/* Obsolete */
    807		if (!mode_switch && vga_video_type == VIDEO_TYPE_VGAC) {
    808			vga_pal_blank(&vgastate);
    809			vga_palette_blanked = true;
    810			return 0;
    811		}
    812		vgacon_set_origin(c);
    813		scr_memsetw((void *) vga_vram_base, BLANK,
    814			    c->vc_screenbuf_size);
    815		if (mode_switch)
    816			vga_is_gfx = true;
    817		return 1;
    818	default:		/* VESA blanking */
    819		if (vga_video_type == VIDEO_TYPE_VGAC) {
    820			vga_vesa_blank(&vgastate, blank - 1);
    821			vga_vesa_blanked = blank;
    822		}
    823		return 0;
    824	}
    825}
    826
    827/*
    828 * PIO_FONT support.
    829 *
    830 * The font loading code goes back to the codepage package by
    831 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original
    832 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2
    833 * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)
    834 *
    835 * Change for certain monochrome monitors by Yury Shevchuck
    836 * (sizif@botik.yaroslavl.su).
    837 */
    838
    839#define colourmap 0xa0000
    840/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we
    841   should use 0xA0000 for the bwmap as well.. */
    842#define blackwmap 0xa0000
    843#define cmapsz 8192
    844
    845static int vgacon_do_font_op(struct vgastate *state, char *arg, int set,
    846		bool ch512)
    847{
    848	unsigned short video_port_status = vga_video_port_reg + 6;
    849	int font_select = 0x00, beg, i;
    850	char *charmap;
    851	bool clear_attribs = false;
    852	if (vga_video_type != VIDEO_TYPE_EGAM) {
    853		charmap = (char *) VGA_MAP_MEM(colourmap, 0);
    854		beg = 0x0e;
    855	} else {
    856		charmap = (char *) VGA_MAP_MEM(blackwmap, 0);
    857		beg = 0x0a;
    858	}
    859
    860	/*
    861	 * All fonts are loaded in slot 0 (0:1 for 512 ch)
    862	 */
    863
    864	if (!arg)
    865		return -EINVAL;	/* Return to default font not supported */
    866
    867	font_select = ch512 ? 0x04 : 0x00;
    868
    869	raw_spin_lock_irq(&vga_lock);
    870	/* First, the Sequencer */
    871	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
    872	/* CPU writes only to map 2 */
    873	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x04);	
    874	/* Sequential addressing */
    875	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x07);	
    876	/* Clear synchronous reset */
    877	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
    878
    879	/* Now, the graphics controller, select map 2 */
    880	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x02);		
    881	/* disable odd-even addressing */
    882	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x00);
    883	/* map start at A000:0000 */
    884	vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x00);
    885	raw_spin_unlock_irq(&vga_lock);
    886
    887	if (arg) {
    888		if (set)
    889			for (i = 0; i < cmapsz; i++) {
    890				vga_writeb(arg[i], charmap + i);
    891				cond_resched();
    892			}
    893		else
    894			for (i = 0; i < cmapsz; i++) {
    895				arg[i] = vga_readb(charmap + i);
    896				cond_resched();
    897			}
    898
    899		/*
    900		 * In 512-character mode, the character map is not contiguous if
    901		 * we want to remain EGA compatible -- which we do
    902		 */
    903
    904		if (ch512) {
    905			charmap += 2 * cmapsz;
    906			arg += cmapsz;
    907			if (set)
    908				for (i = 0; i < cmapsz; i++) {
    909					vga_writeb(arg[i], charmap + i);
    910					cond_resched();
    911				}
    912			else
    913				for (i = 0; i < cmapsz; i++) {
    914					arg[i] = vga_readb(charmap + i);
    915					cond_resched();
    916				}
    917		}
    918	}
    919
    920	raw_spin_lock_irq(&vga_lock);
    921	/* First, the sequencer, Synchronous reset */
    922	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);	
    923	/* CPU writes to maps 0 and 1 */
    924	vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x03);
    925	/* odd-even addressing */
    926	vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x03);
    927	/* Character Map Select */
    928	if (set)
    929		vga_wseq(state->vgabase, VGA_SEQ_CHARACTER_MAP, font_select);
    930	/* clear synchronous reset */
    931	vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
    932
    933	/* Now, the graphics controller, select map 0 for CPU */
    934	vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x00);
    935	/* enable even-odd addressing */
    936	vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x10);
    937	/* map starts at b800:0 or b000:0 */
    938	vga_wgfx(state->vgabase, VGA_GFX_MISC, beg);
    939
    940	/* if 512 char mode is already enabled don't re-enable it. */
    941	if ((set) && (ch512 != vga_512_chars)) {
    942		vga_512_chars = ch512;
    943		/* 256-char: enable intensity bit
    944		   512-char: disable intensity bit */
    945		inb_p(video_port_status);	/* clear address flip-flop */
    946		/* color plane enable register */
    947		vga_wattr(state->vgabase, VGA_ATC_PLANE_ENABLE, ch512 ? 0x07 : 0x0f);
    948		/* Wilton (1987) mentions the following; I don't know what
    949		   it means, but it works, and it appears necessary */
    950		inb_p(video_port_status);
    951		vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);	
    952		clear_attribs = true;
    953	}
    954	raw_spin_unlock_irq(&vga_lock);
    955
    956	if (clear_attribs) {
    957		for (i = 0; i < MAX_NR_CONSOLES; i++) {
    958			struct vc_data *c = vc_cons[i].d;
    959			if (c && c->vc_sw == &vga_con) {
    960				/* force hi font mask to 0, so we always clear
    961				   the bit on either transition */
    962				c->vc_hi_font_mask = 0x00;
    963				clear_buffer_attributes(c);
    964				c->vc_hi_font_mask = ch512 ? 0x0800 : 0;
    965			}
    966		}
    967	}
    968	return 0;
    969}
    970
    971/*
    972 * Adjust the screen to fit a font of a certain height
    973 */
    974static int vgacon_adjust_height(struct vc_data *vc, unsigned fontheight)
    975{
    976	unsigned char ovr, vde, fsr;
    977	int rows, maxscan, i;
    978
    979	rows = vc->vc_scan_lines / fontheight;	/* Number of video rows we end up with */
    980	maxscan = rows * fontheight - 1;	/* Scan lines to actually display-1 */
    981
    982	/* Reprogram the CRTC for the new font size
    983	   Note: the attempt to read the overflow register will fail
    984	   on an EGA, but using 0xff for the previous value appears to
    985	   be OK for EGA text modes in the range 257-512 scan lines, so I
    986	   guess we don't need to worry about it.
    987
    988	   The same applies for the spill bits in the font size and cursor
    989	   registers; they are write-only on EGA, but it appears that they
    990	   are all don't care bits on EGA, so I guess it doesn't matter. */
    991
    992	raw_spin_lock_irq(&vga_lock);
    993	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
    994	ovr = inb_p(vga_video_port_val);
    995	outb_p(0x09, vga_video_port_reg);	/* Font size register */
    996	fsr = inb_p(vga_video_port_val);
    997	raw_spin_unlock_irq(&vga_lock);
    998
    999	vde = maxscan & 0xff;	/* Vertical display end reg */
   1000	ovr = (ovr & 0xbd) +	/* Overflow register */
   1001	    ((maxscan & 0x100) >> 7) + ((maxscan & 0x200) >> 3);
   1002	fsr = (fsr & 0xe0) + (fontheight - 1);	/*  Font size register */
   1003
   1004	raw_spin_lock_irq(&vga_lock);
   1005	outb_p(0x07, vga_video_port_reg);	/* CRTC overflow register */
   1006	outb_p(ovr, vga_video_port_val);
   1007	outb_p(0x09, vga_video_port_reg);	/* Font size */
   1008	outb_p(fsr, vga_video_port_val);
   1009	outb_p(0x12, vga_video_port_reg);	/* Vertical display limit */
   1010	outb_p(vde, vga_video_port_val);
   1011	raw_spin_unlock_irq(&vga_lock);
   1012	vga_video_font_height = fontheight;
   1013
   1014	for (i = 0; i < MAX_NR_CONSOLES; i++) {
   1015		struct vc_data *c = vc_cons[i].d;
   1016
   1017		if (c && c->vc_sw == &vga_con) {
   1018			if (con_is_visible(c)) {
   1019			        /* void size to cause regs to be rewritten */
   1020				cursor_size_lastfrom = 0;
   1021				cursor_size_lastto = 0;
   1022				c->vc_sw->con_cursor(c, CM_DRAW);
   1023			}
   1024			c->vc_font.height = c->vc_cell_height = fontheight;
   1025			vc_resize(c, 0, rows);	/* Adjust console size */
   1026		}
   1027	}
   1028	return 0;
   1029}
   1030
   1031static int vgacon_font_set(struct vc_data *c, struct console_font *font,
   1032			   unsigned int flags)
   1033{
   1034	unsigned charcount = font->charcount;
   1035	int rc;
   1036
   1037	if (vga_video_type < VIDEO_TYPE_EGAM)
   1038		return -EINVAL;
   1039
   1040	if (font->width != VGA_FONTWIDTH ||
   1041	    (charcount != 256 && charcount != 512))
   1042		return -EINVAL;
   1043
   1044	rc = vgacon_do_font_op(&vgastate, font->data, 1, charcount == 512);
   1045	if (rc)
   1046		return rc;
   1047
   1048	if (!(flags & KD_FONT_FLAG_DONT_RECALC))
   1049		rc = vgacon_adjust_height(c, font->height);
   1050	return rc;
   1051}
   1052
   1053static int vgacon_font_get(struct vc_data *c, struct console_font *font)
   1054{
   1055	if (vga_video_type < VIDEO_TYPE_EGAM)
   1056		return -EINVAL;
   1057
   1058	font->width = VGA_FONTWIDTH;
   1059	font->height = c->vc_font.height;
   1060	font->charcount = vga_512_chars ? 512 : 256;
   1061	if (!font->data)
   1062		return 0;
   1063	return vgacon_do_font_op(&vgastate, font->data, 0, vga_512_chars);
   1064}
   1065
   1066static int vgacon_resize(struct vc_data *c, unsigned int width,
   1067			 unsigned int height, unsigned int user)
   1068{
   1069	if ((width << 1) * height > vga_vram_size)
   1070		return -EINVAL;
   1071
   1072	if (user) {
   1073		/*
   1074		 * Ho ho!  Someone (svgatextmode, eh?) may have reprogrammed
   1075		 * the video mode!  Set the new defaults then and go away.
   1076		 */
   1077		screen_info.orig_video_cols = width;
   1078		screen_info.orig_video_lines = height;
   1079		vga_default_font_height = c->vc_cell_height;
   1080		return 0;
   1081	}
   1082	if (width % 2 || width > screen_info.orig_video_cols ||
   1083	    height > (screen_info.orig_video_lines * vga_default_font_height)/
   1084	    c->vc_cell_height)
   1085		return -EINVAL;
   1086
   1087	if (con_is_visible(c) && !vga_is_gfx) /* who knows */
   1088		vgacon_doresize(c, width, height);
   1089	return 0;
   1090}
   1091
   1092static int vgacon_set_origin(struct vc_data *c)
   1093{
   1094	if (vga_is_gfx ||	/* We don't play origin tricks in graphic modes */
   1095	    (console_blanked && !vga_palette_blanked))	/* Nor we write to blanked screens */
   1096		return 0;
   1097	c->vc_origin = c->vc_visible_origin = vga_vram_base;
   1098	vga_set_mem_top(c);
   1099	vga_rolled_over = 0;
   1100	return 1;
   1101}
   1102
   1103static void vgacon_save_screen(struct vc_data *c)
   1104{
   1105	static int vga_bootup_console = 0;
   1106
   1107	if (!vga_bootup_console) {
   1108		/* This is a gross hack, but here is the only place we can
   1109		 * set bootup console parameters without messing up generic
   1110		 * console initialization routines.
   1111		 */
   1112		vga_bootup_console = 1;
   1113		c->state.x = screen_info.orig_x;
   1114		c->state.y = screen_info.orig_y;
   1115	}
   1116
   1117	/* We can't copy in more than the size of the video buffer,
   1118	 * or we'll be copying in VGA BIOS */
   1119
   1120	if (!vga_is_gfx)
   1121		scr_memcpyw((u16 *) c->vc_screenbuf, (u16 *) c->vc_origin,
   1122			    c->vc_screenbuf_size > vga_vram_size ? vga_vram_size : c->vc_screenbuf_size);
   1123}
   1124
   1125static bool vgacon_scroll(struct vc_data *c, unsigned int t, unsigned int b,
   1126		enum con_scroll dir, unsigned int lines)
   1127{
   1128	unsigned long oldo;
   1129	unsigned int delta;
   1130
   1131	if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
   1132		return false;
   1133
   1134	if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
   1135		return false;
   1136
   1137	vgacon_restore_screen(c);
   1138	oldo = c->vc_origin;
   1139	delta = lines * c->vc_size_row;
   1140	if (dir == SM_UP) {
   1141		if (c->vc_scr_end + delta >= vga_vram_end) {
   1142			scr_memcpyw((u16 *) vga_vram_base,
   1143				    (u16 *) (oldo + delta),
   1144				    c->vc_screenbuf_size - delta);
   1145			c->vc_origin = vga_vram_base;
   1146			vga_rolled_over = oldo - vga_vram_base;
   1147		} else
   1148			c->vc_origin += delta;
   1149		scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
   1150				     delta), c->vc_video_erase_char,
   1151			    delta);
   1152	} else {
   1153		if (oldo - delta < vga_vram_base) {
   1154			scr_memmovew((u16 *) (vga_vram_end -
   1155					      c->vc_screenbuf_size +
   1156					      delta), (u16 *) oldo,
   1157				     c->vc_screenbuf_size - delta);
   1158			c->vc_origin = vga_vram_end - c->vc_screenbuf_size;
   1159			vga_rolled_over = 0;
   1160		} else
   1161			c->vc_origin -= delta;
   1162		c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
   1163		scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
   1164			    delta);
   1165	}
   1166	c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
   1167	c->vc_visible_origin = c->vc_origin;
   1168	vga_set_mem_top(c);
   1169	c->vc_pos = (c->vc_pos - oldo) + c->vc_origin;
   1170	return true;
   1171}
   1172
   1173/*
   1174 *  The console `switch' structure for the VGA based console
   1175 */
   1176
   1177static void vgacon_clear(struct vc_data *vc, int sy, int sx, int height,
   1178			 int width) { }
   1179static void vgacon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
   1180static void vgacon_putcs(struct vc_data *vc, const unsigned short *s,
   1181			 int count, int ypos, int xpos) { }
   1182
   1183const struct consw vga_con = {
   1184	.owner = THIS_MODULE,
   1185	.con_startup = vgacon_startup,
   1186	.con_init = vgacon_init,
   1187	.con_deinit = vgacon_deinit,
   1188	.con_clear = vgacon_clear,
   1189	.con_putc = vgacon_putc,
   1190	.con_putcs = vgacon_putcs,
   1191	.con_cursor = vgacon_cursor,
   1192	.con_scroll = vgacon_scroll,
   1193	.con_switch = vgacon_switch,
   1194	.con_blank = vgacon_blank,
   1195	.con_font_set = vgacon_font_set,
   1196	.con_font_get = vgacon_font_get,
   1197	.con_resize = vgacon_resize,
   1198	.con_set_palette = vgacon_set_palette,
   1199	.con_scrolldelta = vgacon_scrolldelta,
   1200	.con_set_origin = vgacon_set_origin,
   1201	.con_save_screen = vgacon_save_screen,
   1202	.con_build_attr = vgacon_build_attr,
   1203	.con_invert_region = vgacon_invert_region,
   1204};
   1205EXPORT_SYMBOL(vga_con);
   1206
   1207MODULE_LICENSE("GPL");