cyblafb.c

来自「Linux环境下视频显示卡设备的驱动程序源代码」· C语言 代码 · 共 1,684 行 · 第 1/3 页

C
1,684
字号
	}	write3CE(GR23, DPMSCont);	out8(0x83C8, 4);	out8(0x83C6, PMCont);	//	// let fbcon do a softblank for us	//	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;}static struct fb_ops cyblafb_ops __devinitdata = {	.owner = THIS_MODULE,	.fb_setcolreg = cyblafb_setcolreg,	.fb_pan_display = cyblafb_pan_display,	.fb_blank = cyblafb_blank,	.fb_check_var = cyblafb_check_var,	.fb_set_par = cyblafb_set_par,	.fb_fillrect = cyblafb_fillrect,	.fb_copyarea = cyblafb_copyarea,	.fb_imageblit = cyblafb_imageblit,	.fb_sync = cyblafb_sync,	.fb_restore_state = cyblafb_restore_state,	.fb_save_state = cyblafb_save_state,};//==========================================================================//// getstartupmode() decides about the inital video mode//// There is no reason to use modedb, a lot of video modes there would// need altered timings to display correctly. So I decided that it is much// better to provide a limited optimized set of modes plus the option of// using the mode in effect at startup time (might be selected using the// vga=??? parameter). After that the user might use fbset to select any// mode he likes, check_var will not try to alter geometry parameters as// it would be necessary otherwise.////==========================================================================static int __devinit getstartupmode(struct fb_info *info){	u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend,	    vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend,	    cr00, cr01, cr02, cr03, cr04, cr05, cr2b,	    cr06, cr07, cr09, cr10, cr11, cr12, cr15, cr16, cr27,	    cr38, sr0d, sr18, sr19, gr0f, fi, pxclkdiv, vclkdiv, tmp, i;	struct modus {		int xres; int vxres; int yres; int vyres;		int bpp; int pxclk;		int left_margin; int right_margin;		int upper_margin; int lower_margin;		int hsync_len; int vsync_len;	} modedb[5] = {		{		0, 2048, 0, 4096, 0, 0, 0, 0, 0, 0, 0, 0}, {		640, 2048, 480, 4096, 0, 0, -40, 24, 17, 0, 216, 3}, {		800, 2048, 600, 4096, 0, 0, 96, 24, 14, 0, 136, 11}, {		1024, 2048, 768, 4096, 0, 0, 144, 24, 29, 0, 120, 3}, {		1280, 2048, 1024, 4096, 0, 0, 232, 16, 39, 0, 160, 3}	};	outb(0x00, 0x3d4); cr00 = inb(0x3d5);	outb(0x01, 0x3d4); cr01 = inb(0x3d5);	outb(0x02, 0x3d4); cr02 = inb(0x3d5);	outb(0x03, 0x3d4); cr03 = inb(0x3d5);	outb(0x04, 0x3d4); cr04 = inb(0x3d5);	outb(0x05, 0x3d4); cr05 = inb(0x3d5);	outb(0x06, 0x3d4); cr06 = inb(0x3d5);	outb(0x07, 0x3d4); cr07 = inb(0x3d5);	outb(0x09, 0x3d4); cr09 = inb(0x3d5);	outb(0x10, 0x3d4); cr10 = inb(0x3d5);	outb(0x11, 0x3d4); cr11 = inb(0x3d5);	outb(0x12, 0x3d4); cr12 = inb(0x3d5);	outb(0x15, 0x3d4); cr15 = inb(0x3d5);	outb(0x16, 0x3d4); cr16 = inb(0x3d5);	outb(0x27, 0x3d4); cr27 = inb(0x3d5);	outb(0x2b, 0x3d4); cr2b = inb(0x3d5);	outb(0x38, 0x3d4); cr38 = inb(0x3d5);	outb(0x0b, 0x3c4);	inb(0x3c5);	outb(0x0d, 0x3c4); sr0d = inb(0x3c5);	outb(0x18, 0x3c4); sr18 = inb(0x3c5);	outb(0x19, 0x3c4); sr19 = inb(0x3c5);	outb(0x0f, 0x3ce); gr0f = inb(0x3cf);	htotal = cr00 | (cr2b & 0x01) << 8;	hdispend = cr01 | (cr2b & 0x02) << 7;	hblankstart = cr02 | (cr2b & 0x10) << 4;	hblankend = (cr03 & 0x1f) | (cr05 & 0x80) >> 2;	hsyncstart = cr04 | (cr2b & 0x08) << 5;	hsyncend = cr05 & 0x1f;	modedb[0].xres = hblankstart * 8;	modedb[0].hsync_len = hsyncend * 8;	modedb[0].right_margin = hsyncstart * 8 - modedb[0].xres;	modedb[0].left_margin = (htotal + 5) * 8 - modedb[0].xres -	    modedb[0].right_margin - modedb[0].hsync_len;	vtotal = cr06 | (cr07 & 0x01) << 8 | (cr07 & 0x20) << 4	    | (cr27 & 0x80) << 3;	vdispend = cr12 | (cr07 & 0x02) << 7 | (cr07 & 0x40) << 3	    | (cr27 & 0x10) << 6;	vsyncstart = cr10 | (cr07 & 0x04) << 6 | (cr07 & 0x80) << 2	    | (cr27 & 0x20) << 5;	vsyncend = cr11 & 0x0f;	vblankstart = cr15 | (cr07 & 0x08) << 5 | (cr09 & 0x20) << 4	    | (cr27 & 0x40) << 4;	vblankend = cr16;	modedb[0].yres = vdispend + 1;	modedb[0].vsync_len = vsyncend;	modedb[0].lower_margin = vsyncstart - modedb[0].yres;	modedb[0].upper_margin = vtotal - modedb[0].yres -	    modedb[0].lower_margin - modedb[0].vsync_len + 2;	tmp = cr38 & 0x3c;	modedb[0].bpp = tmp == 0 ? 8 : tmp == 4 ? 16 : tmp == 28 ? 24 :	    tmp == 8 ? 32 : 8;	fi = ((5864727 * (sr18 + 8)) /	      (((sr19 & 0x3f) + 2) * (1 << ((sr19 & 0xc0) >> 6)))) >> 12;	pxclkdiv = ((gr0f & 0x08) >> 3 | (gr0f & 0x40) >> 5) + 1;	tmp = sr0d & 0x06;	vclkdiv = tmp == 0 ? 2 : tmp == 2 ? 4 : tmp == 4 ? 8 : 3; // * 2 !	modedb[0].pxclk = ((100000000 * pxclkdiv * vclkdiv) >> 1) / fi;	if (verbosity > 0)		output("detected startup mode: "		       "fbset -g %d %d %d ??? %d -t %d %d %d %d %d %d %d\n",		       modedb[0].xres, modedb[0].yres, modedb[0].xres,		       modedb[0].bpp, modedb[0].pxclk, modedb[0].left_margin,		       modedb[0].right_margin, modedb[0].upper_margin,		       modedb[0].lower_margin, modedb[0].hsync_len,		       modedb[0].vsync_len);	//	// We use this goto target in case of a failed check_var. No, I really	// do not want to do it in another way!	//      tryagain:	i = (mode == NULL) ? 0 :	    !strncmp(mode, "640x480", 7) ? 1 :	    !strncmp(mode, "800x600", 7) ? 2 :	    !strncmp(mode, "1024x768", 8) ? 3 :	    !strncmp(mode, "1280x1024", 9) ? 4 : 0;	ref = (ref < 50) ? 50 : (ref > 85) ? 85 : ref;	if (i == 0) {		info->var.pixclock = modedb[i].pxclk;		info->var.bits_per_pixel = modedb[i].bpp;	} else {		info->var.pixclock = (100000000 /				      ((modedb[i].left_margin +					modedb[i].xres +					modedb[i].right_margin +					modedb[i].hsync_len) *				       (modedb[i].upper_margin +					modedb[i].yres +					modedb[i].lower_margin +					modedb[i].vsync_len) * ref / 10000));		info->var.bits_per_pixel = bpp;	}	info->var.left_margin = modedb[i].left_margin;	info->var.right_margin = modedb[i].right_margin;	info->var.xres = modedb[i].xres;	if (!(modedb[i].yres == 1280 && modedb[i].bpp == 32))		info->var.xres_virtual = modedb[i].vxres;	else		info->var.xres_virtual = modedb[i].xres;	info->var.xoffset = 0;	info->var.hsync_len = modedb[i].hsync_len;	info->var.upper_margin = modedb[i].upper_margin;	info->var.yres = modedb[i].yres;	info->var.yres_virtual = modedb[i].vyres;	info->var.yoffset = 0;	info->var.lower_margin = modedb[i].lower_margin;	info->var.vsync_len = modedb[i].vsync_len;	info->var.sync = 0;	info->var.vmode = FB_VMODE_NONINTERLACED;	if (cyblafb_check_var(&info->var, info)) {		// 640x480 - 8@75 should really never fail. One case would		// be fp == 1 and nativex < 640 ... give up then		if (i == 1 && bpp == 8 && ref == 75) {			output("Can't find a valid mode :-(\n");			return -EINVAL;		}		// Our detected mode is unlikely to fail. If it does,		// try 640x480 - 8@75 ...		if (i == 0) {			mode = "640x480";			bpp = 8;			ref = 75;			output("Detected mode failed check_var! "			       "Trying 640x480 - 8@75\n");			goto tryagain;		}		// A specified video mode failed for some reason.		// Try the startup mode first		output("Specified mode '%s' failed check! "		       "Falling back to startup mode.\n", mode);		mode = NULL;		goto tryagain;	}	return 0;}//========================================================//// Detect activated memory size. Undefined values require// memsize parameter.////========================================================static unsigned int __devinit get_memsize(void){	unsigned char tmp;	unsigned int k;	if (memsize)		k = memsize * Kb;	else {		tmp = read3X4(CR1F) & 0x0F;		switch (tmp) {		case 0x03:			k = 1 * 1024 * 1024;			break;		case 0x07:			k = 2 * 1024 * 1024;			break;		case 0x0F:			k = 4 * 1024 * 1024;			break;		case 0x04:			k = 8 * 1024 * 1024;			break;		default:			k = 1 * 1024 * 1024;			output("Unknown memory size code %x in CR1F."			       " We default to 1 Mb for now, please"			       " do provide a memsize parameter!\n", tmp);		}	}	if (verbosity > 0)		output("framebuffer size = %d Kb\n", k / Kb);	return k;}//=========================================================//// Detect if a flat panel monitor connected to the special// interface is active. Override is possible by fp and crt// parameters.////=========================================================static unsigned int __devinit get_displaytype(void){	if (fp)		return DISPLAY_FP;	if (crt)		return DISPLAY_CRT;	return (read3CE(GR33) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;}//=====================================//// Get native resolution of flat panel////=====================================static int __devinit get_nativex(void){	int x, y, tmp;	if (nativex)		return nativex;	tmp = (read3CE(GR52) >> 4) & 3;	switch (tmp) {	case 0: x = 1280; y = 1024;		break;	case 2: x = 1024; y = 768;		break;	case 3: x = 800;  y = 600;		break;	case 4: x = 1400; y = 1050;		break;	case 1:	default:		x = 640; y = 480;		break;	}	if (verbosity > 0)		output("%dx%d flat panel found\n", x, y);	return x;}static int __devinit cybla_pci_probe(struct pci_dev *dev,				     const struct pci_device_id *id){	struct fb_info *info;	struct cyblafb_par *par;	info = framebuffer_alloc(sizeof(struct cyblafb_par), &dev->dev);	if (!info)		goto errout_alloc_info;	info->pixmap.addr = kzalloc(CYBLAFB_PIXMAPSIZE, GFP_KERNEL);	if (!info->pixmap.addr) {		output("allocation of pixmap buffer failed!\n");		goto errout_alloc_pixmap;	}	info->pixmap.size = CYBLAFB_PIXMAPSIZE - 4;	info->pixmap.buf_align = 4;	info->pixmap.access_align = 32;	info->pixmap.flags = FB_PIXMAP_SYSTEM;	info->pixmap.scan_align = 4;	par = info->par;	par->ops = cyblafb_ops;	info->fix = cyblafb_fix;	info->fbops = &par->ops;	info->fix = cyblafb_fix;	if (pci_enable_device(dev)) {		output("could not enable device!\n");		goto errout_enable;	}	// might already be requested by vga console or vesafb,	// so we do care about success	if (!request_region(0x3c0, 0x20, "cyblafb")) {		output("region 0x3c0/0x20 already reserved\n");		vesafb |= 1;	}	//	// Graphics Engine Registers	//	if (!request_region(GEBase, 0x100, "cyblafb")) {		output("region %#x/0x100 already reserved\n", GEBase);		vesafb |= 2;	}	regdump(par);	enable_mmio();	// setup MMIO region	info->fix.mmio_start = pci_resource_start(dev, 1);	info->fix.mmio_len = 0x20000;	if (!request_mem_region(info->fix.mmio_start,				info->fix.mmio_len, "cyblafb")) {		output("request_mem_region failed for mmio region!\n");		goto errout_mmio_reqmem;	}	io_virt = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);	if (!io_virt) {		output("ioremap failed for mmio region\n");		goto errout_mmio_remap;	}	// setup framebuffer memory ... might already be requested	// by vesafb. Not to fail in case of an unsuccessful request	// is useful if both are loaded.	info->fix.smem_start = pci_resource_start(dev, 0);	info->fix.smem_len = get_memsize();	if (!request_mem_region(info->fix.smem_start,				info->fix.smem_len, "cyblafb")) {		output("region %#lx/%#x already reserved\n",		       info->fix.smem_start, info->fix.smem_len);		vesafb |= 4;	}	info->screen_base = ioremap_nocache(info->fix.smem_start,					    info->fix.smem_len);	if (!info->screen_base) {		output("ioremap failed for smem region\n");		goto errout_smem_remap;	}	displaytype = get_displaytype();	if (displaytype == DISPLAY_FP)		nativex = get_nativex();	info->flags = FBINFO_DEFAULT		    | FBINFO_HWACCEL_COPYAREA		    | FBINFO_HWACCEL_FILLRECT		    | FBINFO_HWACCEL_IMAGEBLIT		    | FBINFO_READS_FAST//		    | FBINFO_PARTIAL_PAN_OK		    | FBINFO_MISC_ALWAYS_SETPAR;	info->pseudo_palette = par->pseudo_pal;	if (getstartupmode(info))		goto errout_findmode;	fb_alloc_cmap(&info->cmap, 256, 0);	if (register_framebuffer(info)) {		output("Could not register CyBla framebuffer\n");		goto errout_register;	}	pci_set_drvdata(dev, info);	//	// normal exit and error paths	//	return 0;      errout_register:      errout_findmode:	iounmap(info->screen_base);      errout_smem_remap:	if (!(vesafb & 4))		release_mem_region(info->fix.smem_start, info->fix.smem_len);	iounmap(io_virt);      errout_mmio_remap:	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);      errout_mmio_reqmem:	if (!(vesafb & 1))		release_region(0x3c0, 32);      errout_enable:	kfree(info->pixmap.addr);      errout_alloc_pixmap:	framebuffer_release(info);      errout_alloc_info:	output("CyblaFB version %s aborting init.\n", VERSION);	return -ENODEV;}static void __devexit cybla_pci_remove(struct pci_dev *dev){	struct fb_info *info = pci_get_drvdata(dev);	unregister_framebuffer(info);	iounmap(io_virt);	iounmap(info->screen_base);	if (!(vesafb & 4))		release_mem_region(info->fix.smem_start, info->fix.smem_len);	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);	fb_dealloc_cmap(&info->cmap);	if (!(vesafb & 2))		release_region(GEBase, 0x100);	if (!(vesafb & 1))		release_region(0x3c0, 32);	kfree(info->pixmap.addr);	framebuffer_release(info);	output("CyblaFB version %s normal exit.\n", VERSION);}//// List of boards that we are trying to support//static struct pci_device_id cybla_devices[] = {	{PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},	{0,}};MODULE_DEVICE_TABLE(pci, cybla_devices);static struct pci_driver cyblafb_pci_driver = {	.name = "cyblafb",	.id_table = cybla_devices,	.probe = cybla_pci_probe,	.remove = __devexit_p(cybla_pci_remove)};//=============================================================//// kernel command line example:////	video=cyblafb:1280x1024, bpp=16, ref=50 ...//// modprobe command line example:////	modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ...////=============================================================static int __devinit cyblafb_init(void){#ifndef MODULE	char *options = NULL;	char *opt;	if (fb_get_options("cyblafb", &options))		return -ENODEV;	if (options && *options)		while ((opt = strsep(&options, ",")) != NULL) {			if (!*opt)				continue;			else if (!strncmp(opt, "bpp=", 4))				bpp = simple_strtoul(opt + 4, NULL, 0);			else if (!strncmp(opt, "ref=", 4))				ref = simple_strtoul(opt + 4, NULL, 0);			else if (!strncmp(opt, "fp", 2))				displaytype = DISPLAY_FP;			else if (!strncmp(opt, "crt", 3))				displaytype = DISPLAY_CRT;			else if (!strncmp(opt, "nativex=", 8))				nativex = simple_strtoul(opt + 8, NULL, 0);			else if (!strncmp(opt, "center", 6))				center = 1;			else if (!strncmp(opt, "stretch", 7))				stretch = 1;			else if (!strncmp(opt, "pciwb=", 6))				pciwb = simple_strtoul(opt + 6, NULL, 0);			else if (!strncmp(opt, "pcirb=", 6))				pcirb = simple_strtoul(opt + 6, NULL, 0);			else if (!strncmp(opt, "pciwr=", 6))				pciwr = simple_strtoul(opt + 6, NULL, 0);			else if (!strncmp(opt, "pcirr=", 6))				pcirr = simple_strtoul(opt + 6, NULL, 0);			else if (!strncmp(opt, "memsize=", 8))				memsize = simple_strtoul(opt + 8, NULL, 0);			else if (!strncmp(opt, "verbosity=", 10))				verbosity = simple_strtoul(opt + 10, NULL, 0);			else				mode = opt;		}#endif	output("CyblaFB version %s initializing\n", VERSION);	return pci_register_driver(&cyblafb_pci_driver);}static void __exit cyblafb_exit(void){	pci_unregister_driver(&cyblafb_pci_driver);}module_init(cyblafb_init);module_exit(cyblafb_exit);MODULE_AUTHOR("Knut Petersen <knut_petersen@t-online.de>");MODULE_DESCRIPTION("Framebuffer driver for Cyberblade/i1 graphics core");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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