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

📄 cyblafb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Frame buffer driver for Trident Cyberblade/i1 graphics core * * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de> * * CREDITS: *	tridentfb.c by Jani Monoses *	see files above for further credits * */#define CYBLAFB_DEBUG 0#define CYBLAFB_KD_GRAPHICS_QUIRK 1#define CYBLAFB_PIXMAPSIZE 8192#include <linux/module.h>#include <linux/string.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <asm/types.h>#include <video/cyblafb.h>#define VERSION "0.62"struct cyblafb_par {	u32 pseudo_pal[16];	struct fb_ops ops;};static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {	.id = "CyBla",	.type = FB_TYPE_PACKED_PIXELS,	.xpanstep = 1,	.ypanstep = 1,	.ywrapstep = 1,	.visual = FB_VISUAL_PSEUDOCOLOR,	.accel = FB_ACCEL_NONE,};static char *mode __devinitdata = NULL;static int bpp __devinitdata = 8;static int ref __devinitdata = 75;static int fp __devinitdata;static int crt __devinitdata;static int memsize __devinitdata;static int basestride;static int vesafb;static int nativex;static int center;static int stretch;static int pciwb = 1;static int pcirb = 1;static int pciwr = 1;static int pcirr = 1;static int disabled;static int verbosity;static int displaytype;static void __iomem *io_virt;	// iospace virtual memory addressmodule_param(mode, charp, 0);module_param(bpp, int, 0);module_param(ref, int, 0);module_param(fp, int, 0);module_param(crt, int, 0);module_param(nativex, int, 0);module_param(center, int, 0);module_param(stretch, int, 0);module_param(pciwb, int, 0);module_param(pcirb, int, 0);module_param(pciwr, int, 0);module_param(pcirr, int, 0);module_param(memsize, int, 0);module_param(verbosity, int, 0);//=========================================//// Well, we have to fix the upper layers.// Until this has been done, we work around// the bugs.////=========================================#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)	if (disabled) { \		printk("********\n");\		dump_stack();\		return val;\	}#elif CYBLAFB_KD_GRAPHICS_QUIRK#define KD_GRAPHICS_RETURN(val)\	if (disabled) {\		return val;\	}#else#define KD_GRAPHICS_RETURN(val)#endif//=========================================//// Port access macros for memory mapped io////=========================================#define out8(r, v) writeb(v, io_virt + r)#define out32(r, v) writel(v, io_virt + r)#define in8(r) readb(io_virt + r)#define in32(r) readl(io_virt + r)//======================================//// Hardware access inline functions////======================================static inline u8 read3X4(u32 reg){	out8(0x3D4, reg);	return in8(0x3D5);}static inline u8 read3C4(u32 reg){	out8(0x3C4, reg);	return in8(0x3C5);}static inline u8 read3CE(u32 reg){	out8(0x3CE, reg);	return in8(0x3CF);}static inline void write3X4(u32 reg, u8 val){	out8(0x3D4, reg);	out8(0x3D5, val);}static inline void write3C4(u32 reg, u8 val){	out8(0x3C4, reg);	out8(0x3C5, val);}static inline void write3CE(u32 reg, u8 val){	out8(0x3CE, reg);	out8(0x3CF, val);}static inline void write3C0(u32 reg, u8 val){	in8(0x3DA);		// read to reset index	out8(0x3C0, reg);	out8(0x3C0, val);}//=================================================//// Enable memory mapped io and unprotect registers////=================================================static void enable_mmio(void){	u8 tmp;	outb(0x0B, 0x3C4);	inb(0x3C5);		// Set NEW mode	outb(SR0E, 0x3C4);	// write enable a lot of extended ports	outb(0x80, 0x3C5);	outb(SR11, 0x3C4);	// write enable those extended ports that	outb(0x87, 0x3C5);	// are not affected by SR0E_New	outb(CR1E, 0x3d4);	// clear write protect bit for port 0x3c2	tmp = inb(0x3d5) & 0xBF;	outb(CR1E, 0x3d4);	outb(tmp, 0x3d5);	outb(CR39, 0x3D4);	outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio}//=================================================//// Set pixel clock VCLK1// - multipliers set elswhere// - freq in units of 0.01 MHz//// Hardware bug: SR18 >= 250 is broken for the//		 cyberblade/i1////=================================================static void set_vclk(struct cyblafb_par *par, int freq){	u32 m, n, k;	int f, fi, d, di;	u8 lo = 0, hi = 0;	d = 2000;	k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;	for (m = 0; m < 64; m++)		for (n = 0; n < 250; n++) {			fi = (int)(((5864727 * (n + 8)) /				    ((m + 2) * (1 << k))) >> 12);			if ((di = abs(fi - freq)) < d) {				d = di;				f = fi;				lo = (u8) n;				hi = (u8) ((k << 6) | m);			}		}	write3C4(SR19, hi);	write3C4(SR18, lo);	if (verbosity > 0)		output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",		       freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);}//================================================//// Cyberblade specific Graphics Engine (GE) setup////================================================static void cyblafb_setup_GE(int pitch, int bpp){	KD_GRAPHICS_RETURN();	switch (bpp) {	case 8:		basestride = ((pitch >> 3) << 20) | (0 << 29);		break;	case 15:		basestride = ((pitch >> 3) << 20) | (5 << 29);		break;	case 16:		basestride = ((pitch >> 3) << 20) | (1 << 29);		break;	case 24:	case 32:		basestride = ((pitch >> 3) << 20) | (2 << 29);		break;	}	write3X4(CR36, 0x90);	// reset GE	write3X4(CR36, 0x80);	// enable GE	out32(GE24, 1 << 7);	// reset all GE pointers by toggling	out32(GE24, 0); 	//   d7 of GE24	write3X4(CR2D, 0x00);	// GE Timinigs, no delays	out32(GE6C, 0); 	// Pattern and Style, p 129, ok}//=====================================================================//// Cyberblade specific syncing////   A timeout might be caused by disabled mmio.//   Cause://     - bit CR39 & 1 == 0 upon return, X trident driver bug//     - kdm bug (KD_GRAPHICS not set on first switch)//     - kernel design flaw (it believes in the correctness//	 of kdm/X//   First we try to sync ignoring that problem, as most of the//   time that will succeed immediately and the enable_mmio()//   would only degrade performance.////=====================================================================static int cyblafb_sync(struct fb_info *info){	u32 status, i = 100000;	KD_GRAPHICS_RETURN(0);	while (((status = in32(GE20)) & 0xFe800000) && i != 0)		i--;	if (i == 0) {		enable_mmio();		i = 1000000;		while (((status = in32(GE20)) & 0xFA800000) && i != 0)			i--;		if (i == 0) {			output("GE Timeout, status: %x\n", status);			if (status & 0x80000000)				output("Bresenham Engine : Busy\n");			if (status & 0x40000000)				output("Setup Engine     : Busy\n");			if (status & 0x20000000)				output("SP / DPE         : Busy\n");			if (status & 0x10000000)				output("Memory Interface : Busy\n");			if (status & 0x08000000)				output("Com Lst Proc     : Busy\n");			if (status & 0x04000000)				output("Block Write      : Busy\n");			if (status & 0x02000000)				output("Command Buffer   : Full\n");			if (status & 0x01000000)				output("RESERVED         : Busy\n");			if (status & 0x00800000)				output("PCI Write Buffer : Busy\n");			cyblafb_setup_GE(info->var.xres,					 info->var.bits_per_pixel);		}	}	return 0;}//==============================//// Cyberblade specific fillrect////==============================static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr){	u32 bpp = info->var.bits_per_pixel, col, desty, height;	KD_GRAPHICS_RETURN();	switch (bpp) {	default:	case 8:		col = fr->color;		col |= col << 8;		col |= col << 16;		break;	case 16:		col = ((u32 *) (info->pseudo_palette))[fr->color];		col |= col << 16;		break;	case 32:		col = ((u32 *) (info->pseudo_palette))[fr->color];		break;	}	desty = fr->dy;	height = fr->height;	while (height) {		out32(GEB8, basestride | ((desty * info->var.xres_virtual *					   bpp) >> 6));		out32(GE60, col);		out32(GE48, fr->rop ? 0x66 : ROP_S);		out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);		out32(GE08, point(fr->dx, 0));		out32(GE0C, point(fr->dx + fr->width - 1,				  height > 4096 ? 4095 : height - 1));		if (likely(height <= 4096))			return;		desty += 4096;		height -= 4096;	}}//================================================//// Cyberblade specific copyarea//// This function silently assumes that it never// will be called with width or height exceeding// 4096.////================================================static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca){	u32 s1, s2, d1, d2, direction;	KD_GRAPHICS_RETURN();	s1 = point(ca->sx, 0);	s2 = point(ca->sx + ca->width - 1, ca->height - 1);	d1 = point(ca->dx, 0);	d2 = point(ca->dx + ca->width - 1, ca->height - 1);	if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))		direction = 0;	else		direction = 2;	out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *				   info->var.bits_per_pixel) >> 6));	out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *				   info->var.bits_per_pixel) >> 6));	out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);	out32(GE00, direction ? s2 : s1);	out32(GE04, direction ? s1 : s2);	out32(GE08, direction ? d2 : d1);	out32(GE0C, direction ? d1 : d2);}//=======================================================================//// Cyberblade specific imageblit//// Accelerated for the most usual case, blitting 1 - bit deep// character images. Everything else is passed to the generic imageblit// unless it is so insane that it is better to printk an alert.//// Hardware bug: _Never_ blit across pixel column 2048, that will lock// the system. We split those blit requests into three blitting// operations.////=======================================================================static void cyblafb_imageblit(struct fb_info *info,			      const struct fb_image *image){	u32 fgcol, bgcol;	u32 *pd = (u32 *) image->data;	u32 bpp = info->var.bits_per_pixel;	KD_GRAPHICS_RETURN();	// Used only for drawing the penguine (image->depth > 1)	if (image->depth != 1) {		cfb_imageblit(info, image);		return;	}	// That should never happen, but it would be fatal	if (image->width == 0 || image->height == 0) {		output("imageblit: width/height 0 detected\n");		return;	}	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {		fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];		bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];	} else {		fgcol = image->fg_color;		bgcol = image->bg_color;	}	switch (bpp) {	case 8:		fgcol |= fgcol << 8;		bgcol |= bgcol << 8;	case 16:		fgcol |= fgcol << 16;		bgcol |= bgcol << 16;	default:		break;	}	out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *				   bpp) >> 6));	out32(GE60, fgcol);	out32(GE64, bgcol);	if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {		u32 dds = ((image->width + 31) >> 5) * image->height;		out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);		out32(GE08, point(image->dx, 0));		out32(GE0C, point(image->dx + image->width - 1,				  image->height - 1));		while (dds--)			out32(GE9C, *pd++);	} else {		int i, j;		u32 ddstotal = (image->width + 31) >> 5;		u32 ddsleft = (2048 - image->dx + 31) >> 5;		u32 skipleft = ddstotal - ddsleft;		out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);		out32(GE08, point(image->dx, 0));		out32(GE0C, point(2048 - 1, image->height - 1));		for (i = 0; i < image->height; i++) {			for (j = 0; j < ddsleft; j++)				out32(GE9C, *pd++);			pd += skipleft;		}		if (image->dx % 32) {			out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);			out32(GE08, point(2048, 0));			if (image->width > ddsleft << 5)				out32(GE0C, point(image->dx + (ddsleft << 5) -						  1, image->height - 1));			else				out32(GE0C, point(image->dx + image->width - 1,						  image->height - 1));			pd = ((u32 *) image->data) + ddstotal - skipleft - 1;			for (i = 0; i < image->height; i++) {				out32(GE9C, swab32(swab32(*pd) << ((32 -					    (image->dx & 31)) & 31)));				pd += ddstotal;			}		}		if (skipleft) {			out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);			out32(GE08, point(image->dx + (ddsleft << 5), 0));			out32(GE0C, point(image->dx + image->width - 1,					  image->height - 1));			pd = (u32 *) image->data;			for (i = 0; i < image->height; i++) {				pd += ddsleft;				for (j = 0; j < skipleft; j++)					out32(GE9C, *pd++);			}		}	}}//==========================================================//// Check if video mode is acceptable. We change var->??? if// video mode is slightly off or return error otherwise.// info->??? must not be changed!////==========================================================static int cyblafb_check_var(struct fb_var_screeninfo *var,			     struct fb_info *info){	int bpp = var->bits_per_pixel;	//	// we try to support 8, 16, 24 and 32 bpp modes,	// default to 8	//	// there is a 24 bpp mode, but for now we change requests to 32 bpp	// (This is what tridentfb does ... will be changed in the future)	//	//	if (bpp % 8 != 0 || bpp < 8 || bpp > 32)		bpp = 8;	if (bpp == 24)		bpp = var->bits_per_pixel = 32;	//	// interlaced modes are broken, fail if one is requested	//	if (var->vmode & FB_VMODE_INTERLACED)		return -EINVAL;	//	// fail if requested resolution is higher than physical	// flatpanel resolution	//	if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex)		return -EINVAL;	//	// we do not allow vclk to exceed 230 MHz. If the requested	// vclk is too high, we default to 200 MHz	//	if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)		var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;	//

⌨️ 快捷键说明

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