File Index
Files and directories
Sign in
FILE

vgacon.c

File preview with syntax highlighting.

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