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

📄 au1100fb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* fb_mmap * Map video memory in user space. We don't use the generic fb_mmap method mainly * to allow the use of the TLB streaming flag (CCA=6) */int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma){	struct au1100fb_device *fbdev;	unsigned int len;	unsigned long start=0, off;	fbdev = to_au1100fb_device(fbi);	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {		return -EINVAL;	}	start = fbdev->fb_phys & PAGE_MASK;	len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);	off = vma->vm_pgoff << PAGE_SHIFT;	if ((vma->vm_end - vma->vm_start + off) > len) {		return -EINVAL;	}	off += start;	vma->vm_pgoff = off >> PAGE_SHIFT;	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6	vma->vm_flags |= VM_IO;	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,				vma->vm_end - vma->vm_start,				vma->vm_page_prot)) {		return -EAGAIN;	}	return 0;}/* fb_cursor * Used to disable cursor drawing... */int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor){	if (nocursor)		return 0;	else		return -EINVAL;	/* just to force soft_cursor() call */}static struct fb_ops au1100fb_ops ={	.owner			= THIS_MODULE,	.fb_setcolreg		= au1100fb_fb_setcolreg,	.fb_blank		= au1100fb_fb_blank,	.fb_pan_display		= au1100fb_fb_pan_display,	.fb_fillrect		= cfb_fillrect,	.fb_copyarea		= cfb_copyarea,	.fb_imageblit		= cfb_imageblit,	.fb_rotate		= au1100fb_fb_rotate,	.fb_mmap		= au1100fb_fb_mmap,	.fb_cursor		= au1100fb_fb_cursor,};/*-------------------------------------------------------------------------*//* AU1100 LCD controller device driver */static int __init au1100fb_drv_probe(struct device *dev){	struct au1100fb_device *fbdev = NULL;	struct resource *regs_res;	unsigned long page;	u32 sys_clksrc;	if (!dev)			return -EINVAL;	/* Allocate new device private */	if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {		print_err("fail to allocate device private record");		return -ENOMEM;	}	fbdev->panel = &known_lcd_panels[drv_info.panel_idx];	dev_set_drvdata(dev, (void*)fbdev);	/* Allocate region for our registers and map them */	if (!(regs_res = platform_get_resource(to_platform_device(dev),					IORESOURCE_MEM, 0))) {		print_err("fail to retrieve registers resource");		return -EFAULT;	}	au1100fb_fix.mmio_start = regs_res->start;	au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1;	if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,				DRIVER_NAME)) {		print_err("fail to lock memory region at 0x%08lx",				au1100fb_fix.mmio_start);		return -EBUSY;	}	fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(au1100fb_fix.mmio_start);	print_dbg("Register memory map at %p", fbdev->regs);	print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);	/* Allocate the framebuffer to the maximum screen size * nbr of video buffers */	fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *		  	(fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;	fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len),					&fbdev->fb_phys, GFP_KERNEL);	if (!fbdev->fb_mem) {		print_err("fail to allocate frambuffer (size: %dK))",			  fbdev->fb_len / 1024);		return -ENOMEM;	}	au1100fb_fix.smem_start = fbdev->fb_phys;	au1100fb_fix.smem_len = fbdev->fb_len;	/*	 * Set page reserved so that mmap will work. This is necessary	 * since we'll be remapping normal memory.	 */	for (page = (unsigned long)fbdev->fb_mem;	     page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);	     page += PAGE_SIZE) {#if CONFIG_DMA_NONCOHERENT		SetPageReserved(virt_to_page(CAC_ADDR(page)));#else		SetPageReserved(virt_to_page(page));#endif	}	print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);	print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);	/* Setup LCD clock to AUX (48 MHz) */	sys_clksrc = au_readl(SYS_CLKSRC) & ~(SYS_CS_ML_MASK | SYS_CS_DL | SYS_CS_CL);	au_writel((sys_clksrc | (1 << SYS_CS_ML_BIT)), SYS_CLKSRC);	/* load the panel info into the var struct */	au1100fb_var.bits_per_pixel = fbdev->panel->bpp;	au1100fb_var.xres = fbdev->panel->xres;	au1100fb_var.xres_virtual = au1100fb_var.xres;	au1100fb_var.yres = fbdev->panel->yres;	au1100fb_var.yres_virtual = au1100fb_var.yres;	fbdev->info.screen_base = fbdev->fb_mem;	fbdev->info.fbops = &au1100fb_ops;	fbdev->info.fix = au1100fb_fix;	if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) {		return -ENOMEM;	}	if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {		print_err("Fail to allocate colormap (%d entries)",			   AU1100_LCD_NBR_PALETTE_ENTRIES);		kfree(fbdev->info.pseudo_palette);		return -EFAULT;	}	fbdev->info.var = au1100fb_var;	/* Set h/w registers */	au1100fb_setmode(fbdev);	/* Register new framebuffer */	if (register_framebuffer(&fbdev->info) < 0) {		print_err("cannot register new framebuffer");		goto failed;	}	return 0;failed:	if (fbdev->regs) {		release_mem_region(fbdev->regs_phys, fbdev->regs_len);	}	if (fbdev->fb_mem) {		dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys);	}	if (fbdev->info.cmap.len != 0) {		fb_dealloc_cmap(&fbdev->info.cmap);	}	kfree(fbdev);	dev_set_drvdata(dev, NULL);	return 0;}int au1100fb_drv_remove(struct device *dev){	struct au1100fb_device *fbdev = NULL;	if (!dev)		return -ENODEV;	fbdev = (struct au1100fb_device*) dev_get_drvdata(dev);#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)	au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);#endif	fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;	/* Clean up all probe data */	unregister_framebuffer(&fbdev->info);	release_mem_region(fbdev->regs_phys, fbdev->regs_len);	dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys);	fb_dealloc_cmap(&fbdev->info.cmap);	kfree(fbdev->info.pseudo_palette);	kfree((void*)fbdev);	return 0;}#ifdef CONFIG_PMstatic u32 sys_clksrc;static struct au1100fb_regs fbregs;int au1100fb_drv_suspend(struct device *dev, pm_message_t state){	struct au1100fb_device *fbdev = dev_get_drvdata(dev);	if (!fbdev)		return 0;	/* Save the clock source state */	sys_clksrc = au_readl(SYS_CLKSRC);	/* Blank the LCD */	au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);	/* Stop LCD clocking */	au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC);	memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));	return 0;}int au1100fb_drv_resume(struct device *dev){	struct au1100fb_device *fbdev = dev_get_drvdata(dev);	if (!fbdev)		return 0;	memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));	/* Restart LCD clocking */	au_writel(sys_clksrc, SYS_CLKSRC);	/* Unblank the LCD */	au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);	return 0;}#else#define au1100fb_drv_suspend NULL#define au1100fb_drv_resume NULL#endifstatic struct device_driver au1100fb_driver = {	.name		= "au1100-lcd",	.bus		= &platform_bus_type,	.probe		= au1100fb_drv_probe,        .remove		= au1100fb_drv_remove,	.suspend	= au1100fb_drv_suspend,        .resume		= au1100fb_drv_resume,};/*-------------------------------------------------------------------------*//* Kernel driver */int au1100fb_setup(char *options){	char* this_opt;	int num_panels = ARRAY_SIZE(known_lcd_panels);	char* mode = NULL;	int panel_idx = 0;	if (num_panels <= 0) {		print_err("No LCD panels supported by driver!");		return -EFAULT;			}	if (options) {		while ((this_opt = strsep(&options,",")) != NULL) {			/* Panel option */			if (!strncmp(this_opt, "panel:", 6)) {				int i;				this_opt += 6;				for (i = 0; i < num_panels; i++) {					if (!strncmp(this_opt,					      	     known_lcd_panels[i].name,							strlen(this_opt))) {						panel_idx = i;						break;					}				}				if (i >= num_panels) { 					print_warn("Panel %s not supported!", this_opt);				}			}			if (!strncmp(this_opt, "nocursor", 8)) {				this_opt += 8;				nocursor = 1;				print_info("Cursor disabled");			}			/* Mode option (only option that start with digit) */			else if (isdigit(this_opt[0])) {				mode = kmalloc(strlen(this_opt) + 1, GFP_KERNEL);				strncpy(mode, this_opt, strlen(this_opt) + 1);			}			/* Unsupported option */			else {				print_warn("Unsupported option \"%s\"", this_opt);			}		}	}	drv_info.panel_idx = panel_idx;	drv_info.opt_mode = mode;	print_info("Panel=%s Mode=%s",			known_lcd_panels[drv_info.panel_idx].name,		      	drv_info.opt_mode ? drv_info.opt_mode : "default");	return 0;}int __init au1100fb_init(void){	char* options;	int ret;	print_info("" DRIVER_DESC "");	memset(&drv_info, 0, sizeof(drv_info));	if (fb_get_options(DRIVER_NAME, &options))		return -ENODEV;	/* Setup driver with options */	ret = au1100fb_setup(options);	if (ret < 0) {		print_err("Fail to setup driver");		return ret;	}	return driver_register(&au1100fb_driver);}void __exit au1100fb_cleanup(void){	driver_unregister(&au1100fb_driver);	kfree(drv_info.opt_mode);}module_init(au1100fb_init);module_exit(au1100fb_cleanup);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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