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

📄 pm3fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	info->fix.visual =		(bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;	info->fix.line_length = ((info->var.xres_virtual + 7)  >> 3) * bpp;/*	pm3fb_clear_memory(info, 0);*/	pm3fb_clear_colormap(par, 0, 0, 0);	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);	pm3fb_init_engine(info);	pm3fb_write_mode(info);	return 0;}static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,			   unsigned blue, unsigned transp,			   struct fb_info *info){	struct pm3_par *par = info->par;	if (regno >= 256)  /* no. of hw registers */	   return -EINVAL;	/* grayscale works only partially under directcolor */	/* grayscale = 0.30*R + 0.59*G + 0.11*B */	if (info->var.grayscale)	   red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;	/* Directcolor:	 *   var->{color}.offset contains start of bitfield	 *   var->{color}.length contains length of bitfield	 *   {hardwarespecific} contains width of DAC	 *   pseudo_palette[X] is programmed to (X << red.offset) |	 *					(X << green.offset) |	 *					(X << blue.offset)	 *   RAMDAC[X] is programmed to (red, green, blue)	 *   color depth = SUM(var->{color}.length)	 *	 * Pseudocolor:	 *	var->{color}.offset is 0	 *	var->{color}.length contains width of DAC or the number	 *			of unique colors available (color depth)	 *	pseudo_palette is not used	 *	RAMDAC[X] is programmed to (red, green, blue)	 *	color depth = var->{color}.length	 */	/*	 * This is the point where the color is converted to something that	 * is acceptable by the hardware.	 */#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)	red = CNVT_TOHW(red, info->var.red.length);	green = CNVT_TOHW(green, info->var.green.length);	blue = CNVT_TOHW(blue, info->var.blue.length);	transp = CNVT_TOHW(transp, info->var.transp.length);#undef CNVT_TOHW	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||	info->fix.visual == FB_VISUAL_DIRECTCOLOR) {		u32 v;		if (regno >= 16)			return -EINVAL;		v = (red << info->var.red.offset) |			(green << info->var.green.offset) |			(blue << info->var.blue.offset) |			(transp << info->var.transp.offset);		switch (info->var.bits_per_pixel) {		case 8:			break;		case 16:		case 32:			((u32 *)(info->pseudo_palette))[regno] = v;			break;		}		return 0;	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)		pm3fb_set_color(par, regno, red, green, blue);	return 0;}static int pm3fb_pan_display(struct fb_var_screeninfo *var,				 struct fb_info *info){	struct pm3_par *par = info->par;	const u32 xres = (var->xres + 31) & ~31;	par->base = pm3fb_shift_bpp(var->bits_per_pixel,					(var->yoffset * xres)					+ var->xoffset);	PM3_WAIT(par, 1);	PM3_WRITE_REG(par, PM3ScreenBase, par->base);	return 0;}static int pm3fb_blank(int blank_mode, struct fb_info *info){	struct pm3_par *par = info->par;	u32 video = par->video;	/*	 * Oxygen VX1 - it appears that setting PM3VideoControl and	 * then PM3RD_SyncControl to the same SYNC settings undoes	 * any net change - they seem to xor together.  Only set the	 * sync options in PM3RD_SyncControl.  --rmk	 */	video &= ~(PM3VideoControl_HSYNC_MASK |		   PM3VideoControl_VSYNC_MASK);	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |		 PM3VideoControl_VSYNC_ACTIVE_HIGH;	switch (blank_mode) {	case FB_BLANK_UNBLANK:		video |= PM3VideoControl_ENABLE;		break;	case FB_BLANK_NORMAL:		video &= ~PM3VideoControl_ENABLE;		break;	case FB_BLANK_HSYNC_SUSPEND:		video &= ~(PM3VideoControl_HSYNC_MASK |			  PM3VideoControl_BLANK_ACTIVE_LOW);		break;	case FB_BLANK_VSYNC_SUSPEND:		video &= ~(PM3VideoControl_VSYNC_MASK |			  PM3VideoControl_BLANK_ACTIVE_LOW);		break;	case FB_BLANK_POWERDOWN:		video &= ~(PM3VideoControl_HSYNC_MASK |			  PM3VideoControl_VSYNC_MASK |			  PM3VideoControl_BLANK_ACTIVE_LOW);		break;	default:		DPRINTK("Unsupported blanking %d\n", blank_mode);		return 1;	}	PM3_WAIT(par, 1);	PM3_WRITE_REG(par, PM3VideoControl, video);	return 0;}	/*	 *  Frame buffer operations	 */static struct fb_ops pm3fb_ops = {	.owner		= THIS_MODULE,	.fb_check_var	= pm3fb_check_var,	.fb_set_par	= pm3fb_set_par,	.fb_setcolreg	= pm3fb_setcolreg,	.fb_pan_display	= pm3fb_pan_display,	.fb_fillrect	= pm3fb_fillrect,	.fb_copyarea	= pm3fb_copyarea,	.fb_imageblit	= pm3fb_imageblit,	.fb_blank	= pm3fb_blank,	.fb_sync	= pm3fb_sync,	.fb_cursor	= pm3fb_cursor,};/* ------------------------------------------------------------------------- */	/*	 *  Initialization	 *//* mmio register are already mapped when this function is called *//* the pm3fb_fix.smem_start is also set */static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par){	unsigned long	memsize = 0;	unsigned long	tempBypass, i, temp1, temp2;	unsigned char	__iomem *screen_mem;	pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */	/* Linear frame buffer - request region and map it. */	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,				 "pm3fb smem")) {		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");		return 0;	}	screen_mem =		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);	if (!screen_mem) {		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);		return 0;	}	/* TODO: card-specific stuff, *before* accessing *any* FB memory */	/* For Appian Jeronimo 2000 board second head */	tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);	DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);	PM3_WAIT(par, 1);	PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);	/* pm3 split up memory, replicates, and do a lot of	 * nasty stuff IMHO ;-)	 */	for (i = 0; i < 32; i++) {		fb_writel(i * 0x00345678,			  (screen_mem + (i * 1048576)));		mb();		temp1 = fb_readl((screen_mem + (i * 1048576)));		/* Let's check for wrapover, write will fail at 16MB boundary */		if (temp1 == (i * 0x00345678))			memsize = i;		else			break;	}	DPRINTK("First detect pass already got %ld MB\n", memsize + 1);	if (memsize + 1 == i) {		for (i = 0; i < 32; i++) {			/* Clear first 32MB ; 0 is 0, no need to byteswap */			writel(0x0000000, (screen_mem + (i * 1048576)));		}		wmb();		for (i = 32; i < 64; i++) {			fb_writel(i * 0x00345678,				  (screen_mem + (i * 1048576)));			mb();			temp1 =			    fb_readl((screen_mem + (i * 1048576)));			temp2 =			    fb_readl((screen_mem + ((i - 32) * 1048576)));			/* different value, different RAM... */			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))				memsize = i;			else				break;		}	}	DPRINTK("Second detect pass got %ld MB\n", memsize + 1);	PM3_WAIT(par, 1);	PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);	iounmap(screen_mem);	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);	memsize = 1048576 * (memsize + 1);	DPRINTK("Returning 0x%08lx bytes\n", memsize);	return memsize;}static int __devinit pm3fb_probe(struct pci_dev *dev,				  const struct pci_device_id *ent){	struct fb_info *info;	struct pm3_par *par;	struct device *device = &dev->dev; /* for pci drivers */	int err;	int retval = -ENXIO;	err = pci_enable_device(dev);	if (err) {		printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);		return err;	}	/*	 * Dynamically allocate info and par	 */	info = framebuffer_alloc(sizeof(struct pm3_par), device);	if (!info)		return -ENOMEM;	par = info->par;	/*	 * Here we set the screen_base to the virtual memory address	 * for the framebuffer.	 */	pm3fb_fix.mmio_start = pci_resource_start(dev, 0);	pm3fb_fix.mmio_len = PM3_REGS_SIZE;#if defined(__BIG_ENDIAN)	pm3fb_fix.mmio_start += PM3_REGS_SIZE;	DPRINTK("Adjusting register base for big-endian.\n");#endif	/* Registers - request region and map it. */	if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,				 "pm3fb regbase")) {		printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");		goto err_exit_neither;	}	par->v_regs =		ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);	if (!par->v_regs) {		printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",			pm3fb_fix.id);		release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);		goto err_exit_neither;	}	/* Linear frame buffer - request region and map it. */	pm3fb_fix.smem_start = pci_resource_start(dev, 1);	pm3fb_fix.smem_len = pm3fb_size_memory(par);	if (!pm3fb_fix.smem_len) {		printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");		goto err_exit_mmio;	}	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,				 "pm3fb smem")) {		printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");		goto err_exit_mmio;	}	info->screen_base =		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);	if (!info->screen_base) {		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);		goto err_exit_mmio;	}	info->screen_size = pm3fb_fix.smem_len;#ifdef CONFIG_MTRR	if (!nomtrr)		par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start,						pm3fb_fix.smem_len,						MTRR_TYPE_WRCOMB, 1);#endif	info->fbops = &pm3fb_ops;	par->video = PM3_READ_REG(par, PM3VideoControl);	info->fix = pm3fb_fix;	info->pseudo_palette = par->palette;	info->flags = FBINFO_DEFAULT |			FBINFO_HWACCEL_XPAN |			FBINFO_HWACCEL_YPAN |			FBINFO_HWACCEL_COPYAREA |			FBINFO_HWACCEL_IMAGEBLIT |			FBINFO_HWACCEL_FILLRECT;	if (noaccel) {		printk(KERN_DEBUG "disabling acceleration\n");		info->flags |= FBINFO_HWACCEL_DISABLED;	}	info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);	if (!info->pixmap.addr) {		retval = -ENOMEM;		goto err_exit_pixmap;	}	info->pixmap.size = PM3_PIXMAP_SIZE;	info->pixmap.buf_align = 4;	info->pixmap.scan_align = 4;	info->pixmap.access_align = 32;	info->pixmap.flags = FB_PIXMAP_SYSTEM;	/*	 * This should give a reasonable default video mode. The following is	 * done when we can set a video mode.	 */	if (!mode_option)		mode_option = "640x480@60";	retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);	if (!retval || retval == 4) {		retval = -EINVAL;		goto err_exit_both;	}	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {		retval = -ENOMEM;		goto err_exit_both;	}	/*	 * For drivers that can...	 */	pm3fb_check_var(&info->var, info);	if (register_framebuffer(info) < 0) {		retval = -EINVAL;		goto err_exit_all;	}	printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,	   info->fix.id);	pci_set_drvdata(dev, info);	return 0; err_exit_all:	fb_dealloc_cmap(&info->cmap); err_exit_both:	kfree(info->pixmap.addr); err_exit_pixmap:	iounmap(info->screen_base);	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); err_exit_mmio:	iounmap(par->v_regs);	release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); err_exit_neither:	framebuffer_release(info);	return retval;}	/*	 *  Cleanup	 */static void __devexit pm3fb_remove(struct pci_dev *dev){	struct fb_info *info = pci_get_drvdata(dev);	if (info) {		struct fb_fix_screeninfo *fix = &info->fix;		struct pm3_par *par = info->par;		unregister_framebuffer(info);		fb_dealloc_cmap(&info->cmap);#ifdef CONFIG_MTRR	if (par->mtrr_handle >= 0)		mtrr_del(par->mtrr_handle, info->fix.smem_start,			 info->fix.smem_len);#endif /* CONFIG_MTRR */		iounmap(info->screen_base);		release_mem_region(fix->smem_start, fix->smem_len);		iounmap(par->v_regs);		release_mem_region(fix->mmio_start, fix->mmio_len);		pci_set_drvdata(dev, NULL);		kfree(info->pixmap.addr);		framebuffer_release(info);	}}static struct pci_device_id pm3fb_id_table[] = {	{ PCI_VENDOR_ID_3DLABS, 0x0a,	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },	{ 0, }};/* For PCI drivers */static struct pci_driver pm3fb_driver = {	.name =		"pm3fb",	.id_table =	pm3fb_id_table,	.probe =	pm3fb_probe,	.remove =	__devexit_p(pm3fb_remove),};MODULE_DEVICE_TABLE(pci, pm3fb_id_table);#ifndef MODULE	/*	 *  Setup	 *//* * Only necessary if your driver takes special options, * otherwise we fall back on the generic fb_setup(). */static int __init pm3fb_setup(char *options){	char *this_opt;	/* Parse user speficied options (`video=pm3fb:') */	if (!options || !*options)		return 0;	while ((this_opt = strsep(&options, ",")) != NULL) {		if (!*this_opt)			continue;		else if (!strncmp(this_opt, "noaccel", 7))			noaccel = 1;		else if (!strncmp(this_opt, "hwcursor=", 9))			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);#ifdef CONFIG_MTRR		else if (!strncmp(this_opt, "nomtrr", 6))			nomtrr = 1;#endif		else			mode_option = this_opt;	}	return 0;}#endif /* MODULE */static int __init pm3fb_init(void){	/*	 *  For kernel boot options (in 'video=pm3fb:<options>' format)	 */#ifndef MODULE	char *option = NULL;	if (fb_get_options("pm3fb", &option))		return -ENODEV;	pm3fb_setup(option);#endif	return pci_register_driver(&pm3fb_driver);}#ifdef MODULEstatic void __exit pm3fb_exit(void){	pci_unregister_driver(&pm3fb_driver);}module_exit(pm3fb_exit);#endifmodule_init(pm3fb_init);module_param(mode_option, charp, 0);MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");module_param(noaccel, bool, 0);MODULE_PARM_DESC(noaccel, "Disable acceleration");module_param(hwcursor, int, 0644);MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "			"(1=enable, 0=disable, default=1)");#ifdef CONFIG_MTRRmodule_param(nomtrr, bool, 0);MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");#endifMODULE_DESCRIPTION("Permedia3 framebuffer device driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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