brintos

brintos / linux-shallow public Read only

0
0
Text · 35.9 KiB · 37bd187 Raw
1227 lines · c
1/*2 *  linux/drivers/video/vgacon.c -- Low level VGA based console driver3 *4 *	Created 28 Sep 1997 by Geert Uytterhoeven5 *6 *	Rewritten by Martin Mares <mj@ucw.cz>, July 19987 *8 *  This file is based on the old console.c, vga.c and vesa_blank.c drivers.9 *10 *	Copyright (C) 1991, 1992  Linus Torvalds11 *			    1995  Jay Estabrook12 *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 Anvin17 *	Feb-Sep 1995 <peter.anvin@linux.org>18 *19 *	Colour palette handling, by Simon Tatham20 *	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 Horvat24 *	5-May-96 <mitja.horvat@guest.arnes.si>25 *26 *	Use 2 outw instead of 4 outb_p to reduce erroneous text27 *	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 Public32 *  License.  See the file COPYING in the main directory of this archive for33 *  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 0x002062 63#define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 */64/*65 *  Interface used by the world66 */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-piezo101	 * 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 reduce112 * the window of opportunity to see text mislocated to the RHS of the113 * console during heavy scrolling activity. However there is the remote114 * possibility that some pre-dinosaur hardware won't like the back to back115 * 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 interrupt124	 * 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_CONSOLE195		conswitchp = &dummy_con;196		return conswitchp->con_startup();197#else198		return NULL;199#endif200	}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 point289				 * the 16 screen colours to the first 16290				 * 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 their302				 * default values303				 */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_EGAC354	    || vga_video_type == VIDEO_TYPE_VGAC355	    || 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 1376	 * if we are the default console, however if we are a fallback377	 * console, for example if fbcon has failed registration, then378	 * init will be 0, so we need to make sure our boot parameters379	 * have been copied to the console structure for vgacon_resize380	 * ultimately called by vc_resize.  Any subsequent calls to381	 * 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	} else392		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		else470			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		else523			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		else548			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 way625	 * we can spot the screen has been resized and we need to626	 * 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_blanked665	    || !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) and726	 * <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) and741		 *  <Start of horizontal Retrace> to maximum742		 * 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 by842 * Joel Hoffman (joel@wam.umd.edu). (He reports that the original843 * reference is: "From: p. 307 of _Programmer's Guide to PC & PS/2844 * Video Systems_ by Richard Wilton. 1987.  Microsoft Press".)845 *846 * Change for certain monochrome monitors by Yury Shevchuck847 * (sizif@botik.yaroslavl.su).848 */849 850#define colourmap 0xa0000851/* Pauline Middelink <middelin@polyware.iaf.nl> reports that we852   should use 0xA0000 for the bwmap as well.. */853#define blackwmap 0xa0000854#define cmapsz 8192855 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		else905			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 if912		 * we want to remain EGA compatible -- which we do913		 */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			else924				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 bit955		   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 what960		   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 clear972				   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 height984 */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 size994	   Note: the attempt to read the overflow register will fail995	   on an EGA, but using 0xff for the previous value appears to996	   be OK for EGA text modes in the range 257-512 scan lines, so I997	   guess we don't need to worry about it.998 999	   The same applies for the spill bits in the font size and cursor1000	   registers; they are write-only on EGA, but it appears that they1001	   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 reprogrammed1086		 * 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 can1120		 * set bootup console parameters without messing up generic1121		 * 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		} else1159			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		} else1172			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 console1186 */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");1227