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

📄 gbefb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				udelay(10);			if (i == 1000) {				printk(KERN_ERR "gbefb: cmap FIFO timeout\n");				return 1;			}			gbe->cmap[regno] = gbe_cmap[regno];		}	} else if (regno < 16) {		switch (info->var.bits_per_pixel) {		case 15:		case 16:			red >>= 3;			green >>= 3;			blue >>= 3;			pseudo_palette[regno] =				(red << info->var.red.offset) |				(green << info->var.green.offset) |				(blue << info->var.blue.offset);			break;		case 32:			pseudo_palette[regno] =				(red << info->var.red.offset) |				(green << info->var.green.offset) |				(blue << info->var.blue.offset);			break;		}	}	return 0;}/* *  Check video mode validity, eventually modify var to best match. */static int gbefb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	unsigned int line_length;	struct gbe_timing_info timing;	int ret;	/* Limit bpp to 8, 16, and 32 */	if (var->bits_per_pixel <= 8)		var->bits_per_pixel = 8;	else if (var->bits_per_pixel <= 16)		var->bits_per_pixel = 16;	else if (var->bits_per_pixel <= 32)		var->bits_per_pixel = 32;	else		return -EINVAL;	/* Check the mode can be mapped linearly with the tile table trick. */	/* This requires width x height x bytes/pixel be a multiple of 512 */	if ((var->xres * var->yres * var->bits_per_pixel) & 4095)		return -EINVAL;	var->grayscale = 0;	/* No grayscale for now */	ret = compute_gbe_timing(var, &timing);	var->pixclock = ret;	if (ret < 0)		return -EINVAL;	/* Adjust virtual resolution, if necessary */	if (var->xres > var->xres_virtual || (!ywrap && !ypan))		var->xres_virtual = var->xres;	if (var->yres > var->yres_virtual || (!ywrap && !ypan))		var->yres_virtual = var->yres;	if (var->vmode & FB_VMODE_CONUPDATE) {		var->vmode |= FB_VMODE_YWRAP;		var->xoffset = info->var.xoffset;		var->yoffset = info->var.yoffset;	}	/* No grayscale for now */	var->grayscale = 0;	/* Memory limit */	line_length = var->xres_virtual * var->bits_per_pixel / 8;	if (line_length * var->yres_virtual > gbe_mem_size)		return -ENOMEM;	/* Virtual resolution too high */	switch (var->bits_per_pixel) {	case 8:		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 0;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 16:		/* RGB 1555 */		var->red.offset = 10;		var->red.length = 5;		var->green.offset = 5;		var->green.length = 5;		var->blue.offset = 0;		var->blue.length = 5;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 32:		/* RGB 8888 */		var->red.offset = 24;		var->red.length = 8;		var->green.offset = 16;		var->green.length = 8;		var->blue.offset = 8;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 8;		break;	}	var->red.msb_right = 0;	var->green.msb_right = 0;	var->blue.msb_right = 0;	var->transp.msb_right = 0;	var->left_margin = timing.htotal - timing.hsync_end;	var->right_margin = timing.hsync_start - timing.width;	var->upper_margin = timing.vtotal - timing.vsync_end;	var->lower_margin = timing.vsync_start - timing.height;	var->hsync_len = timing.hsync_end - timing.hsync_start;	var->vsync_len = timing.vsync_end - timing.vsync_start;	return 0;}static int gbefb_mmap(struct fb_info *info,			struct vm_area_struct *vma){	unsigned long size = vma->vm_end - vma->vm_start;	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;	unsigned long addr;	unsigned long phys_addr, phys_size;	u16 *tile;	/* check range */	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))		return -EINVAL;	if (offset + size > gbe_mem_size)		return -EINVAL;	/* remap using the fastest write-through mode on architecture */	/* try not polluting the cache when possible */	pgprot_val(vma->vm_page_prot) =		pgprot_fb(pgprot_val(vma->vm_page_prot));	vma->vm_flags |= VM_IO | VM_RESERVED;	/* look for the starting tile */	tile = &gbe_tiles.cpu[offset >> TILE_SHIFT];	addr = vma->vm_start;	offset &= TILE_MASK;	/* remap each tile separately */	do {		phys_addr = (((unsigned long) (*tile)) << TILE_SHIFT) + offset;		if ((offset + size) < TILE_SIZE)			phys_size = size;		else			phys_size = TILE_SIZE - offset;		if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT,						phys_size, vma->vm_page_prot))			return -EAGAIN;		offset = 0;		size -= phys_size;		addr += phys_size;		tile++;	} while (size);	return 0;}static struct fb_ops gbefb_ops = {	.owner		= THIS_MODULE,	.fb_check_var	= gbefb_check_var,	.fb_set_par	= gbefb_set_par,	.fb_setcolreg	= gbefb_setcolreg,	.fb_mmap	= gbefb_mmap,	.fb_blank	= gbefb_blank,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,};/* * sysfs */static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);}static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision);}static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);static void __devexit gbefb_remove_sysfs(struct device *dev){	device_remove_file(dev, &dev_attr_size);	device_remove_file(dev, &dev_attr_revision);}static void gbefb_create_sysfs(struct device *dev){	device_create_file(dev, &dev_attr_size);	device_create_file(dev, &dev_attr_revision);}/* * Initialization */int __init gbefb_setup(char *options){	char *this_opt;	if (!options || !*options)		return 0;	while ((this_opt = strsep(&options, ",")) != NULL) {		if (!strncmp(this_opt, "monitor:", 8)) {			if (!strncmp(this_opt + 8, "crt", 3)) {				flat_panel_enabled = 0;				default_var = &default_var_CRT;				default_mode = &default_mode_CRT;			} else if (!strncmp(this_opt + 8, "1600sw", 6) ||				   !strncmp(this_opt + 8, "lcd", 3)) {				flat_panel_enabled = 1;				default_var = &default_var_LCD;				default_mode = &default_mode_LCD;			}		} else if (!strncmp(this_opt, "mem:", 4)) {			gbe_mem_size = memparse(this_opt + 4, &this_opt);			if (gbe_mem_size > CONFIG_FB_GBE_MEM * 1024 * 1024)				gbe_mem_size = CONFIG_FB_GBE_MEM * 1024 * 1024;			if (gbe_mem_size < TILE_SIZE)				gbe_mem_size = TILE_SIZE;		} else			mode_option = this_opt;	}	return 0;}static int __init gbefb_probe(struct platform_device *p_dev){	int i, ret = 0;	struct fb_info *info;	struct gbefb_par *par;#ifndef MODULE	char *options = NULL;#endif	info = framebuffer_alloc(sizeof(struct gbefb_par), &p_dev->dev);	if (!info)		return -ENOMEM;#ifndef MODULE	if (fb_get_options("gbefb", &options))		return -ENODEV;	gbefb_setup(options);#endif	if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {		printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");		ret = -EBUSY;		goto out_release_framebuffer;	}	gbe = (struct sgi_gbe *) ioremap(GBE_BASE, sizeof(struct sgi_gbe));	if (!gbe) {		printk(KERN_ERR "gbefb: couldn't map mmio region\n");		ret = -ENXIO;		goto out_release_mem_region;	}	gbe_revision = gbe->ctrlstat & 15;	gbe_tiles.cpu =		dma_alloc_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),				   &gbe_tiles.dma, GFP_KERNEL);	if (!gbe_tiles.cpu) {		printk(KERN_ERR "gbefb: couldn't allocate tiles table\n");		ret = -ENOMEM;		goto out_unmap;	}	if (gbe_mem_phys) {		/* memory was allocated at boot time */		gbe_mem = ioremap_nocache(gbe_mem_phys, gbe_mem_size);		if (!gbe_mem) {			printk(KERN_ERR "gbefb: couldn't map framebuffer\n");			ret = -ENOMEM;			goto out_tiles_free;		}		gbe_dma_addr = 0;	} else {		/* try to allocate memory with the classical allocator		 * this has high chance to fail on low memory machines */		gbe_mem = dma_alloc_coherent(NULL, gbe_mem_size, &gbe_dma_addr,					     GFP_KERNEL);		if (!gbe_mem) {			printk(KERN_ERR "gbefb: couldn't allocate framebuffer memory\n");			ret = -ENOMEM;			goto out_tiles_free;		}		gbe_mem_phys = (unsigned long) gbe_dma_addr;	}#ifdef CONFIG_X86	mtrr_add(gbe_mem_phys, gbe_mem_size, MTRR_TYPE_WRCOMB, 1);#endif	/* map framebuffer memory into tiles table */	for (i = 0; i < (gbe_mem_size >> TILE_SHIFT); i++)		gbe_tiles.cpu[i] = (gbe_mem_phys >> TILE_SHIFT) + i;	info->fbops = &gbefb_ops;	info->pseudo_palette = pseudo_palette;	info->flags = FBINFO_DEFAULT;	info->screen_base = gbe_mem;	fb_alloc_cmap(&info->cmap, 256, 0);	/* reset GBE */	gbe_reset();	par = info->par;	/* turn on default video mode */	if (fb_find_mode(&par->var, info, mode_option, NULL, 0,			 default_mode, 8) == 0)		par->var = *default_var;	info->var = par->var;	gbefb_check_var(&par->var, info);	gbefb_encode_fix(&info->fix, &info->var);	if (register_framebuffer(info) < 0) {		printk(KERN_ERR "gbefb: couldn't register framebuffer\n");		ret = -ENXIO;		goto out_gbe_unmap;	}	platform_set_drvdata(p_dev, info);	gbefb_create_sysfs(&p_dev->dev);	printk(KERN_INFO "fb%d: %s rev %d @ 0x%08x using %dkB memory\n",	       info->node, info->fix.id, gbe_revision, (unsigned) GBE_BASE,	       gbe_mem_size >> 10);	return 0;out_gbe_unmap:	if (gbe_dma_addr)		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);	else		iounmap(gbe_mem);out_tiles_free:	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),			  (void *)gbe_tiles.cpu, gbe_tiles.dma);out_unmap:	iounmap(gbe);out_release_mem_region:	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));out_release_framebuffer:	framebuffer_release(info);	return ret;}static int __devexit gbefb_remove(struct platform_device* p_dev){	struct fb_info *info = platform_get_drvdata(p_dev);	unregister_framebuffer(info);	gbe_turn_off();	if (gbe_dma_addr)		dma_free_coherent(NULL, gbe_mem_size, gbe_mem, gbe_mem_phys);	else		iounmap(gbe_mem);	dma_free_coherent(NULL, GBE_TLB_SIZE * sizeof(uint16_t),			  (void *)gbe_tiles.cpu, gbe_tiles.dma);	release_mem_region(GBE_BASE, sizeof(struct sgi_gbe));	iounmap(gbe);	gbefb_remove_sysfs(&p_dev->dev);	framebuffer_release(info);	return 0;}static struct platform_driver gbefb_driver = {	.probe = gbefb_probe,	.remove = __devexit_p(gbefb_remove),	.driver	= {		.name = "gbefb",	},};static struct platform_device *gbefb_device;int __init gbefb_init(void){	int ret = platform_driver_register(&gbefb_driver);	if (!ret) {		gbefb_device = platform_device_alloc("gbefb", 0);		if (gbefb_device) {			ret = platform_device_add(gbefb_device);		} else {			ret = -ENOMEM;		}		if (ret) {			platform_device_put(gbefb_device);			platform_driver_unregister(&gbefb_driver);		}	}	return ret;}void __exit gbefb_exit(void){	platform_device_unregister(gbefb_device);	platform_driver_unregister(&gbefb_driver);}module_init(gbefb_init);module_exit(gbefb_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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