vgacon.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,385 行 · 第 1/3 页

C
1,385
字号
/* *  linux/drivers/video/vgacon.c -- Low level VGA based console driver * *	Created 28 Sep 1997 by Geert Uytterhoeven * *	Rewritten by Martin Mares <mj@ucw.cz>, July 1998 * *  This file is based on the old console.c, vga.c and vesa_blank.c drivers. * *	Copyright (C) 1991, 1992  Linus Torvalds *			    1995  Jay Estabrook * *	User definable mapping table and font loading by Eugene G. Crosser, *	<crosser@average.org> * *	Improved loadable font/UTF-8 support by H. Peter Anvin *	Feb-Sep 1995 <peter.anvin@linux.org> * *	Colour palette handling, by Simon Tatham *	17-Jun-95 <sgt20@cam.ac.uk> * *	if 512 char mode is already enabled don't re-enable it, *	because it causes screen to flicker, by Mitja Horvat *	5-May-96 <mitja.horvat@guest.arnes.si> * *	Use 2 outw instead of 4 outb_p to reduce erroneous text *	flashing on RHS of screen during heavy console scrolling . *	Oct 1996, Paul Gortmaker. * * *  This file is subject to the terms and conditions of the GNU General Public *  License.  See the file COPYING in the main directory of this archive for *  more details. */#include <linux/config.h>#include <linux/module.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/tty.h>#include <linux/console.h>#include <linux/string.h>#include <linux/kd.h>#include <linux/slab.h>#include <linux/vt_kern.h>#include <linux/selection.h>#include <linux/spinlock.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <video/vga.h>#include <asm/io.h>static DEFINE_SPINLOCK(vga_lock);static int cursor_size_lastfrom;static int cursor_size_lastto;static u32 vgacon_xres;static u32 vgacon_yres;static struct vgastate state;#define BLANK 0x0020#define CAN_LOAD_EGA_FONTS	/* undefine if the user must not do this */#define CAN_LOAD_PALETTE	/* undefine if the user must not do this *//* You really do _NOT_ want to define this, unless you have buggy * Trident VGA which will resize cursor when moving it between column * 15 & 16. If you define this and your VGA is OK, inverse bug will * appear. */#undef TRIDENT_GLITCH#define VGA_FONTWIDTH       8   /* VGA does not support fontwidths != 8 *//* *  Interface used by the world */static const char *vgacon_startup(void);static void vgacon_init(struct vc_data *c, int init);static void vgacon_deinit(struct vc_data *c);static void vgacon_cursor(struct vc_data *c, int mode);static int vgacon_switch(struct vc_data *c);static int vgacon_blank(struct vc_data *c, int blank, int mode_switch);static int vgacon_set_palette(struct vc_data *vc, unsigned char *table);static int vgacon_scrolldelta(struct vc_data *c, int lines);static int vgacon_set_origin(struct vc_data *c);static void vgacon_save_screen(struct vc_data *c);static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,			 int lines);static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,			    u8 blink, u8 underline, u8 reverse);static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);static unsigned long vgacon_uni_pagedir[2];/* Description of the hardware situation */static unsigned long	vga_vram_base;		/* Base of video memory */static unsigned long	vga_vram_end;		/* End of video memory */static int		vga_vram_size;		/* Size of video memory */static u16		vga_video_port_reg;	/* Video register select port */static u16		vga_video_port_val;	/* Video register value port */static unsigned int	vga_video_num_columns;	/* Number of text columns */static unsigned int	vga_video_num_lines;	/* Number of text lines */static int		vga_can_do_color = 0;	/* Do we support colors? */static unsigned int	vga_default_font_height;/* Height of default screen font */static unsigned char	vga_video_type;		/* Card type */static unsigned char	vga_hardscroll_enabled;static unsigned char	vga_hardscroll_user_enable = 1;static unsigned char	vga_font_is_default = 1;static int		vga_vesa_blanked;static int 		vga_palette_blanked;static int 		vga_is_gfx;static int 		vga_512_chars;static int 		vga_video_font_height;static int 		vga_scan_lines;static unsigned int 	vga_rolled_over = 0;static int __init no_scroll(char *str){	/*	 * Disabling scrollback is required for the Braillex ib80-piezo	 * Braille reader made by F.H. Papenmeier (Germany).	 * Use the "no-scroll" bootflag.	 */	vga_hardscroll_user_enable = vga_hardscroll_enabled = 0;	return 1;}__setup("no-scroll", no_scroll);/* * By replacing the four outb_p with two back to back outw, we can reduce * the window of opportunity to see text mislocated to the RHS of the * console during heavy scrolling activity. However there is the remote * possibility that some pre-dinosaur hardware won't like the back to back * I/O. Since the Xservers get away with it, we should be able to as well. */static inline void write_vga(unsigned char reg, unsigned int val){	unsigned int v1, v2;	unsigned long flags;	/*	 * ddprintk might set the console position from interrupt	 * handlers, thus the write has to be IRQ-atomic.	 */	spin_lock_irqsave(&vga_lock, flags);#ifndef SLOW_VGA	v1 = reg + (val & 0xff00);	v2 = reg + 1 + ((val << 8) & 0xff00);	outw(v1, vga_video_port_reg);	outw(v2, vga_video_port_reg);#else	outb_p(reg, vga_video_port_reg);	outb_p(val >> 8, vga_video_port_val);	outb_p(reg + 1, vga_video_port_reg);	outb_p(val & 0xff, vga_video_port_val);#endif	spin_unlock_irqrestore(&vga_lock, flags);}static inline void vga_set_mem_top(struct vc_data *c){	write_vga(12, (c->vc_visible_origin - vga_vram_base) / 2);}#ifdef CONFIG_VGACON_SOFT_SCROLLBACK#include <linux/bootmem.h>/* software scrollback */static void *vgacon_scrollback;static int vgacon_scrollback_tail;static int vgacon_scrollback_size;static int vgacon_scrollback_rows;static int vgacon_scrollback_cnt;static int vgacon_scrollback_cur;static int vgacon_scrollback_save;static int vgacon_scrollback_restore;static void vgacon_scrollback_init(int pitch){	int rows = CONFIG_VGACON_SOFT_SCROLLBACK_SIZE * 1024/pitch;	if (vgacon_scrollback) {		vgacon_scrollback_cnt  = 0;		vgacon_scrollback_tail = 0;		vgacon_scrollback_cur  = 0;		vgacon_scrollback_rows = rows - 1;		vgacon_scrollback_size = rows * pitch;	}}static void __init vgacon_scrollback_startup(void){	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE					  * 1024);	vgacon_scrollback_init(vga_video_num_columns * 2);}static void vgacon_scrollback_update(struct vc_data *c, int t, int count){	void *p;	if (!vgacon_scrollback_size || c->vc_num != fg_console)		return;	p = (void *) (c->vc_origin + t * c->vc_size_row);	while (count--) {		scr_memcpyw(vgacon_scrollback + vgacon_scrollback_tail,			    p, c->vc_size_row);		vgacon_scrollback_cnt++;		p += c->vc_size_row;		vgacon_scrollback_tail += c->vc_size_row;		if (vgacon_scrollback_tail >= vgacon_scrollback_size)			vgacon_scrollback_tail = 0;		if (vgacon_scrollback_cnt > vgacon_scrollback_rows)			vgacon_scrollback_cnt = vgacon_scrollback_rows;		vgacon_scrollback_cur = vgacon_scrollback_cnt;	}}static void vgacon_restore_screen(struct vc_data *c){	vgacon_scrollback_save = 0;	if (!vga_is_gfx && !vgacon_scrollback_restore) {		scr_memcpyw((u16 *) c->vc_origin, (u16 *) c->vc_screenbuf,			    c->vc_screenbuf_size > vga_vram_size ?			    vga_vram_size : c->vc_screenbuf_size);		vgacon_scrollback_restore = 1;		vgacon_scrollback_cur = vgacon_scrollback_cnt;	}}static int vgacon_scrolldelta(struct vc_data *c, int lines){	int start, end, count, soff, diff;	void *d, *s;	if (!lines) {		c->vc_visible_origin = c->vc_origin;		vga_set_mem_top(c);		return 1;	}	if (!vgacon_scrollback)		return 1;	if (!vgacon_scrollback_save) {		vgacon_cursor(c, CM_ERASE);		vgacon_save_screen(c);		vgacon_scrollback_save = 1;	}	vgacon_scrollback_restore = 0;	start = vgacon_scrollback_cur + lines;	end = start + abs(lines);	if (start < 0)		start = 0;	if (start > vgacon_scrollback_cnt)		start = vgacon_scrollback_cnt;	if (end < 0)		end = 0;	if (end > vgacon_scrollback_cnt)		end = vgacon_scrollback_cnt;	vgacon_scrollback_cur = start;	count = end - start;	soff = vgacon_scrollback_tail - ((vgacon_scrollback_cnt - end) *					 c->vc_size_row);	soff -= count * c->vc_size_row;	if (soff < 0)		soff += vgacon_scrollback_size;	count = vgacon_scrollback_cnt - start;	if (count > c->vc_rows)		count = c->vc_rows;	diff = c->vc_rows - count;	d = (void *) c->vc_origin;	s = (void *) c->vc_screenbuf;	while (count--) {		scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);		d += c->vc_size_row;		soff += c->vc_size_row;		if (soff >= vgacon_scrollback_size)			soff = 0;	}	if (diff == c->vc_rows) {		vgacon_cursor(c, CM_MOVE);	} else {		while (diff--) {			scr_memcpyw(d, s, c->vc_size_row);			d += c->vc_size_row;			s += c->vc_size_row;		}	}	return 1;}#else#define vgacon_scrollback_startup(...) do { } while (0)#define vgacon_scrollback_init(...)    do { } while (0)#define vgacon_scrollback_update(...)  do { } while (0)static void vgacon_restore_screen(struct vc_data *c){	if (c->vc_origin != c->vc_visible_origin)		vgacon_scrolldelta(c, 0);}static int vgacon_scrolldelta(struct vc_data *c, int lines){	if (!lines)		/* Turn scrollback off */		c->vc_visible_origin = c->vc_origin;	else {		int margin = c->vc_size_row * 4;		int ul, we, p, st;		if (vga_rolled_over >		    (c->vc_scr_end - vga_vram_base) + margin) {			ul = c->vc_scr_end - vga_vram_base;			we = vga_rolled_over + c->vc_size_row;		} else {			ul = 0;			we = vga_vram_size;		}		p = (c->vc_visible_origin - vga_vram_base - ul + we) % we +		    lines * c->vc_size_row;		st = (c->vc_origin - vga_vram_base - ul + we) % we;		if (st < 2 * margin)			margin = 0;		if (p < margin)			p = 0;		if (p > st - margin)			p = st;		c->vc_visible_origin = vga_vram_base + (p + ul) % we;	}	vga_set_mem_top(c);	return 1;}#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */static const char __init *vgacon_startup(void){	const char *display_desc = NULL;	u16 saved1, saved2;	volatile u16 *p;	if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {	      no_vga:#ifdef CONFIG_DUMMY_CONSOLE		conswitchp = &dummy_con;		return conswitchp->con_startup();#else		return NULL;#endif	}	/* VGA16 modes are not handled by VGACON */	if ((ORIG_VIDEO_MODE == 0x0D) ||	/* 320x200/4 */	    (ORIG_VIDEO_MODE == 0x0E) ||	/* 640x200/4 */	    (ORIG_VIDEO_MODE == 0x10) ||	/* 640x350/4 */	    (ORIG_VIDEO_MODE == 0x12) ||	/* 640x480/4 */	    (ORIG_VIDEO_MODE == 0x6A))	/* 800x600/4, 0x6A is very common */		goto no_vga;	vga_video_num_lines = ORIG_VIDEO_LINES;	vga_video_num_columns = ORIG_VIDEO_COLS;	state.vgabase = NULL;	if (ORIG_VIDEO_MODE == 7) {	/* Is this a monochrome display? */		vga_vram_base = 0xb0000;		vga_video_port_reg = VGA_CRT_IM;		vga_video_port_val = VGA_CRT_DM;		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {			static struct resource ega_console_resource =			    { "ega", 0x3B0, 0x3BF };			vga_video_type = VIDEO_TYPE_EGAM;			vga_vram_end = 0xb8000;			display_desc = "EGA+";			request_resource(&ioport_resource,					 &ega_console_resource);		} else {			static struct resource mda1_console_resource =			    { "mda", 0x3B0, 0x3BB };			static struct resource mda2_console_resource =			    { "mda", 0x3BF, 0x3BF };			vga_video_type = VIDEO_TYPE_MDA;			vga_vram_end = 0xb2000;			display_desc = "*MDA";			request_resource(&ioport_resource,					 &mda1_console_resource);			request_resource(&ioport_resource,					 &mda2_console_resource);			vga_video_font_height = 14;		}	} else {		/* If not, it is color. */		vga_can_do_color = 1;		vga_vram_base = 0xb8000;		vga_video_port_reg = VGA_CRT_IC;		vga_video_port_val = VGA_CRT_DC;		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {			int i;			vga_vram_end = 0xc0000;			if (!ORIG_VIDEO_ISVGA) {				static struct resource ega_console_resource				    = { "ega", 0x3C0, 0x3DF };				vga_video_type = VIDEO_TYPE_EGAC;				display_desc = "EGA";				request_resource(&ioport_resource,						 &ega_console_resource);			} else {				static struct resource vga_console_resource				    = { "vga+", 0x3C0, 0x3DF };				vga_video_type = VIDEO_TYPE_VGAC;				display_desc = "VGA+";				request_resource(&ioport_resource,						 &vga_console_resource);#ifdef VGA_CAN_DO_64KB				/*				 * get 64K rather than 32K of video RAM.				 * This doesn't actually work on all "VGA"				 * controllers (it seems like setting MM=01				 * and COE=1 isn't necessarily a good idea)				 */				vga_vram_base = 0xa0000;				vga_vram_end = 0xb0000;				outb_p(6, VGA_GFX_I);				outb_p(6, VGA_GFX_D);#endif				/*				 * Normalise the palette registers, to point				 * the 16 screen colours to the first 16				 * DAC entries.				 */				for (i = 0; i < 16; i++) {					inb_p(VGA_IS1_RC);					outb_p(i, VGA_ATT_W);					outb_p(i, VGA_ATT_W);				}				outb_p(0x20, VGA_ATT_W);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?