⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vga16fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/video/vga16.c -- VGA 16-color framebuffer driver *  * Copyright 1999 Ben Pfaff <pfaffben@debian.org> and Petr Vandrovec <VANDROVE@vc.cvut.cz> * Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm * Based on VESA framebuffer (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * 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/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/screen_info.h>#include <asm/io.h>#include <video/vga.h>#define VGA_FB_PHYS 0xA0000#define VGA_FB_PHYS_LEN 65536#define MODE_SKIP4	1#define MODE_8BPP	2#define MODE_CFB	4#define MODE_TEXT	8/* --------------------------------------------------------------------- *//* * card parameters */struct vga16fb_par {	/* structure holding original VGA register settings when the           screen is blanked */	struct {		unsigned char	SeqCtrlIndex;	  /* Sequencer Index reg.   */		unsigned char	CrtCtrlIndex;	  /* CRT-Contr. Index reg.  */		unsigned char	CrtMiscIO;	  /* Miscellaneous register */		unsigned char	HorizontalTotal;  /* CRT-Controller:00h */		unsigned char	HorizDisplayEnd;  /* CRT-Controller:01h */		unsigned char	StartHorizRetrace;/* CRT-Controller:04h */		unsigned char	EndHorizRetrace;  /* CRT-Controller:05h */		unsigned char	Overflow;	  /* CRT-Controller:07h */		unsigned char	StartVertRetrace; /* CRT-Controller:10h */		unsigned char	EndVertRetrace;	  /* CRT-Controller:11h */		unsigned char	ModeControl;	  /* CRT-Controller:17h */		unsigned char	ClockingMode;	  /* Seq-Controller:01h */	} vga_state;	struct vgastate state;	unsigned int ref_count;	int palette_blanked, vesa_blanked, mode, isVGA;	u8 misc, pel_msk, vss, clkdiv;	u8 crtc[VGA_CRT_C];};/* --------------------------------------------------------------------- */static struct fb_var_screeninfo vga16fb_defined __initdata = {	.xres		= 640,	.yres		= 480,	.xres_virtual	= 640,	.yres_virtual	= 480,	.bits_per_pixel	= 4,		.activate	= FB_ACTIVATE_TEST,	.height		= -1,	.width		= -1,	.pixclock	= 39721,	.left_margin	= 48,	.right_margin	= 16,	.upper_margin	= 33,	.lower_margin	= 10,	.hsync_len 	= 96,	.vsync_len	= 2,	.vmode		= FB_VMODE_NONINTERLACED,};/* name should not depend on EGA/VGA */static struct fb_fix_screeninfo vga16fb_fix __initdata = {	.id		= "VGA16 VGA",	.smem_start	= VGA_FB_PHYS,	.smem_len	= VGA_FB_PHYS_LEN,	.type		= FB_TYPE_VGA_PLANES,	.type_aux	= FB_AUX_VGA_PLANES_VGA4,	.visual		= FB_VISUAL_PSEUDOCOLOR,	.xpanstep	= 8,	.ypanstep	= 1,	.line_length	= 640 / 8,	.accel		= FB_ACCEL_NONE};/* The VGA's weird architecture often requires that we read a byte and   write a byte to the same location.  It doesn't matter *what* byte   we write, however.  This is because all the action goes on behind   the scenes in the VGA's 32-bit latch register, and reading and writing   video memory just invokes latch behavior.   To avoid race conditions (is this necessary?), reading and writing   the memory byte should be done with a single instruction.  One   suitable instruction is the x86 bitwise OR.  The following   read-modify-write routine should optimize to one such bitwise   OR. */static inline void rmw(volatile char __iomem *p){	readb(p);	writeb(1, p);}/* Set the Graphics Mode Register, and return its previous value.   Bits 0-1 are write mode, bit 3 is read mode. */static inline int setmode(int mode){	int oldmode;		oldmode = vga_io_rgfx(VGA_GFX_MODE);	vga_io_w(VGA_GFX_D, mode);	return oldmode;}/* Select the Bit Mask Register and return its value. */static inline int selectmask(void){	return vga_io_rgfx(VGA_GFX_BIT_MASK);}/* Set the value of the Bit Mask Register.  It must already have been   selected with selectmask(). */static inline void setmask(int mask){	vga_io_w(VGA_GFX_D, mask);}/* Set the Data Rotate Register and return its old value.    Bits 0-2 are rotate count, bits 3-4 are logical operation   (0=NOP, 1=AND, 2=OR, 3=XOR). */static inline int setop(int op){	int oldop;		oldop = vga_io_rgfx(VGA_GFX_DATA_ROTATE);	vga_io_w(VGA_GFX_D, op);	return oldop;}/* Set the Enable Set/Reset Register and return its old value.     The code here always uses value 0xf for thsi register. */static inline int setsr(int sr){	int oldsr;	oldsr = vga_io_rgfx(VGA_GFX_SR_ENABLE);	vga_io_w(VGA_GFX_D, sr);	return oldsr;}/* Set the Set/Reset Register and return its old value. */static inline int setcolor(int color){	int oldcolor;	oldcolor = vga_io_rgfx(VGA_GFX_SR_VALUE);	vga_io_w(VGA_GFX_D, color);	return oldcolor;}/* Return the value in the Graphics Address Register. */static inline int getindex(void){	return vga_io_r(VGA_GFX_I);}/* Set the value in the Graphics Address Register. */static inline void setindex(int index){	vga_io_w(VGA_GFX_I, index);}static void vga16fb_pan_var(struct fb_info *info, 			    struct fb_var_screeninfo *var){	struct vga16fb_par *par = info->par;	u32 xoffset, pos;	xoffset = var->xoffset;	if (info->var.bits_per_pixel == 8) {		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 2;	} else if (par->mode & MODE_TEXT) {		int fh = 16; // FIXME !!! font height. Fugde for now.		pos = (info->var.xres_virtual * (var->yoffset / fh) + xoffset) >> 3;	} else {		if (info->var.nonstd)			xoffset--;		pos = (info->var.xres_virtual * var->yoffset + xoffset) >> 3;	}	vga_io_wcrt(VGA_CRTC_START_HI, pos >> 8);	vga_io_wcrt(VGA_CRTC_START_LO, pos & 0xFF);	/* if we support CFB4, then we must! support xoffset with pixel	 * granularity if someone supports xoffset in bit resolution */	vga_io_r(VGA_IS1_RC);		/* reset flip-flop */	vga_io_w(VGA_ATT_IW, VGA_ATC_PEL);	if (var->bits_per_pixel == 8)		vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1);	else		vga_io_w(VGA_ATT_IW, xoffset & 7);	vga_io_r(VGA_IS1_RC);	vga_io_w(VGA_ATT_IW, 0x20);}static void vga16fb_update_fix(struct fb_info *info){	if (info->var.bits_per_pixel == 4) {		if (info->var.nonstd) {			info->fix.type = FB_TYPE_PACKED_PIXELS;			info->fix.line_length = info->var.xres_virtual / 2;		} else {			info->fix.type = FB_TYPE_VGA_PLANES;			info->fix.type_aux = FB_AUX_VGA_PLANES_VGA4;			info->fix.line_length = info->var.xres_virtual / 8;		}	} else if (info->var.bits_per_pixel == 0) {		info->fix.type = FB_TYPE_TEXT;		info->fix.type_aux = FB_AUX_TEXT_CGA;		info->fix.line_length = info->var.xres_virtual / 4;	} else {	/* 8bpp */		if (info->var.nonstd) {			info->fix.type = FB_TYPE_VGA_PLANES;			info->fix.type_aux = FB_AUX_VGA_PLANES_CFB8;			info->fix.line_length = info->var.xres_virtual / 4;		} else {			info->fix.type = FB_TYPE_PACKED_PIXELS;			info->fix.line_length = info->var.xres_virtual;		}	}}static void vga16fb_clock_chip(struct vga16fb_par *par,			       unsigned int pixclock,			       const struct fb_info *info,			       int mul, int div){	static const struct {		u32 pixclock;		u8  misc;		u8  seq_clock_mode;	} *ptr, *best, vgaclocks[] = {		{ 79442 /* 12.587 */, 0x00, 0x08},		{ 70616 /* 14.161 */, 0x04, 0x08},		{ 39721 /* 25.175 */, 0x00, 0x00},		{ 35308 /* 28.322 */, 0x04, 0x00},		{     0 /* bad */,    0x00, 0x00}};	int err;	pixclock = (pixclock * mul) / div;	best = vgaclocks;	err = pixclock - best->pixclock;	if (err < 0) err = -err;	for (ptr = vgaclocks + 1; ptr->pixclock; ptr++) {		int tmp;		tmp = pixclock - ptr->pixclock;		if (tmp < 0) tmp = -tmp;		if (tmp < err) {			err = tmp;			best = ptr;		}	}	par->misc |= best->misc;	par->clkdiv = best->seq_clock_mode;	pixclock = (best->pixclock * div) / mul;		}			       #define FAIL(X) return -EINVALstatic int vga16fb_open(struct fb_info *info, int user){	struct vga16fb_par *par = info->par;	if (!par->ref_count) {		memset(&par->state, 0, sizeof(struct vgastate));		par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |			VGA_SAVE_CMAP;		save_vga(&par->state);	}	par->ref_count++;	return 0;}static int vga16fb_release(struct fb_info *info, int user){	struct vga16fb_par *par = info->par;	if (!par->ref_count)		return -EINVAL;	if (par->ref_count == 1)		restore_vga(&par->state);	par->ref_count--;	return 0;}static int vga16fb_check_var(struct fb_var_screeninfo *var,			     struct fb_info *info){	struct vga16fb_par *par = info->par;	u32 xres, right, hslen, left, xtotal;	u32 yres, lower, vslen, upper, ytotal;	u32 vxres, xoffset, vyres, yoffset;	u32 pos;	u8 r7, rMode;	int shift;	int mode;	u32 maxmem;	par->pel_msk = 0xFF;	if (var->bits_per_pixel == 4) {		if (var->nonstd) {			if (!par->isVGA)				return -EINVAL;			shift = 3;			mode = MODE_SKIP4 | MODE_CFB;			maxmem = 16384;			par->pel_msk = 0x0F;		} else {			shift = 3;			mode = 0;			maxmem = 65536;		}	} else if (var->bits_per_pixel == 8) {		if (!par->isVGA)			return -EINVAL;	/* no support on EGA */		shift = 2;		if (var->nonstd) {			mode = MODE_8BPP | MODE_CFB;			maxmem = 65536;		} else {			mode = MODE_SKIP4 | MODE_8BPP | MODE_CFB;			maxmem = 16384;		}	} else		return -EINVAL;	xres = (var->xres + 7) & ~7;	vxres = (var->xres_virtual + 0xF) & ~0xF;	xoffset = (var->xoffset + 7) & ~7;	left = (var->left_margin + 7) & ~7;	right = (var->right_margin + 7) & ~7;	hslen = (var->hsync_len + 7) & ~7;	if (vxres < xres)		vxres = xres;	if (xres + xoffset > vxres)		xoffset = vxres - xres;	var->xres = xres;	var->right_margin = right;	var->hsync_len = hslen;	var->left_margin = left;	var->xres_virtual = vxres;	var->xoffset = xoffset;	xres >>= shift;	right >>= shift;	hslen >>= shift;	left >>= shift;	vxres >>= shift;	xtotal = xres + right + hslen + left;	if (xtotal >= 256)		FAIL("xtotal too big");	if (hslen > 32)		FAIL("hslen too big");	if (right + hslen + left > 64)		FAIL("hblank too big");	par->crtc[VGA_CRTC_H_TOTAL] = xtotal - 5;	par->crtc[VGA_CRTC_H_BLANK_START] = xres - 1;	par->crtc[VGA_CRTC_H_DISP] = xres - 1;	pos = xres + right;	par->crtc[VGA_CRTC_H_SYNC_START] = pos;	pos += hslen;	par->crtc[VGA_CRTC_H_SYNC_END] = pos & 0x1F;	pos += left - 2; /* blank_end + 2 <= total + 5 */	par->crtc[VGA_CRTC_H_BLANK_END] = (pos & 0x1F) | 0x80;	if (pos & 0x20)		par->crtc[VGA_CRTC_H_SYNC_END] |= 0x80;	yres = var->yres;	lower = var->lower_margin;	vslen = var->vsync_len;	upper = var->upper_margin;	vyres = var->yres_virtual;	yoffset = var->yoffset;	if (yres > vyres)		vyres = yres;	if (vxres * vyres > maxmem) {		vyres = maxmem / vxres;		if (vyres < yres)			return -ENOMEM;	}	if (yoffset + yres > vyres)		yoffset = vyres - yres;	var->yres = yres;	var->lower_margin = lower;	var->vsync_len = vslen;	var->upper_margin = upper;	var->yres_virtual = vyres;	var->yoffset = yoffset;	if (var->vmode & FB_VMODE_DOUBLE) {		yres <<= 1;		lower <<= 1;		vslen <<= 1;		upper <<= 1;	}	ytotal = yres + lower + vslen + upper;	if (ytotal > 1024) {		ytotal >>= 1;		yres >>= 1;		lower >>= 1;		vslen >>= 1;		upper >>= 1;		rMode = 0x04;	} else		rMode = 0x00;	if (ytotal > 1024)		FAIL("ytotal too big");	if (vslen > 16)		FAIL("vslen too big");	par->crtc[VGA_CRTC_V_TOTAL] = ytotal - 2;	r7 = 0x10;	/* disable linecompare */	if (ytotal & 0x100) r7 |= 0x01;	if (ytotal & 0x200) r7 |= 0x20;	par->crtc[VGA_CRTC_PRESET_ROW] = 0;	par->crtc[VGA_CRTC_MAX_SCAN] = 0x40;	/* 1 scanline, no linecmp */	if (var->vmode & FB_VMODE_DOUBLE)		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x80;	par->crtc[VGA_CRTC_CURSOR_START] = 0x20;	par->crtc[VGA_CRTC_CURSOR_END]   = 0x00;	if ((mode & (MODE_CFB | MODE_8BPP)) == MODE_CFB)		xoffset--;	pos = yoffset * vxres + (xoffset >> shift);	par->crtc[VGA_CRTC_START_HI]     = pos >> 8;	par->crtc[VGA_CRTC_START_LO]     = pos & 0xFF;	par->crtc[VGA_CRTC_CURSOR_HI]    = 0x00;	par->crtc[VGA_CRTC_CURSOR_LO]    = 0x00;	pos = yres - 1;	par->crtc[VGA_CRTC_V_DISP_END] = pos & 0xFF;	par->crtc[VGA_CRTC_V_BLANK_START] = pos & 0xFF;	if (pos & 0x100)		r7 |= 0x0A;	/* 0x02 -> DISP_END, 0x08 -> BLANK_START */	if (pos & 0x200) {		r7 |= 0x40;	/* 0x40 -> DISP_END */		par->crtc[VGA_CRTC_MAX_SCAN] |= 0x20; /* BLANK_START */	}	pos += lower;	par->crtc[VGA_CRTC_V_SYNC_START] = pos & 0xFF;	if (pos & 0x100)		r7 |= 0x04;	if (pos & 0x200)		r7 |= 0x80;	pos += vslen;	par->crtc[VGA_CRTC_V_SYNC_END] = (pos & 0x0F) & ~0x10; /* disabled IRQ */	pos += upper - 1; /* blank_end + 1 <= ytotal + 2 */	par->crtc[VGA_CRTC_V_BLANK_END] = pos & 0xFF; /* 0x7F for original VGA,                     but some SVGA chips requires all 8 bits to set */	if (vxres >= 512)		FAIL("vxres too long");	par->crtc[VGA_CRTC_OFFSET] = vxres >> 1;	if (mode & MODE_SKIP4)		par->crtc[VGA_CRTC_UNDERLINE] = 0x5F;	/* 256, cfb8 */	else		par->crtc[VGA_CRTC_UNDERLINE] = 0x1F;	/* 16, vgap */	par->crtc[VGA_CRTC_MODE] = rMode | ((mode & MODE_TEXT) ? 0xA3 : 0xE3);

⌨️ 快捷键说明

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