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

📄 2410fb.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
字号:
/* *  linux/drivers/video/vfb.c -- Virtual frame buffer device *  Copyright (C) 2007, 2010 fengGuojin(fgjnew@163.com) *   *  Copyright (C) 2002 James Simmons * *	Copyright (C) 1997 Geert Uytterhoeven * *  This file is subject to the terms and conditions of the GNU General Public *  License. See the file COPYING in the main directory of this archive for *  more details. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ioport.h>#include <linux/cpufreq.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.h>#include <asm/page.h>#include <asm/arch/regs-lcd.h>#include <asm/arch/regs-gpio.h>#include "2410fb.h"MODULE_DESCRIPTION("framebuffer for s3c2410");MODULE_LICENSE("GPL");#define VIDEOMEMSIZE	(2*320*240)	/* 1 MB */#define U32 unsigned intstatic unsigned char*videomemory;static u_long videomemorysize = VIDEOMEMSIZE;MODULE_PARM(videomemorysize, "l");static struct fb_var_screeninfo S3C2410fb_default __initdata = {	.xres =		240,	.yres =		320,	.xres_virtual =	240,	.yres_virtual =	320,	.bits_per_pixel = 	16,	.red =		{ 11, 5, 0 },	.green =		{ 5, 6, 0 },  	.blue =		{ 0, 5, 0 },  	.activate =		FB_ACTIVATE_NOW,  	.height =		-1,  	.width =		-1,  	.pixclock =	20000,  	.left_margin =	64,  	.right_margin =	64,  	.upper_margin =	32,  	.lower_margin =	32,  	.hsync_len =	64,  	.vsync_len =	2,  	.vmode =	FB_VMODE_NONINTERLACED,};static struct fb_fix_screeninfo S3C2410fb_fix __initdata = {	.id =		"2410fb",	.type =		FB_TYPE_PACKED_PIXELS,	.visual =		FB_VISUAL_TRUECOLOR,	.xpanstep =	0,	.ypanstep =	0,	.ywrapstep =	0,	.accel =		FB_ACCEL_NONE,	.type_aux	= 	0,};int S3C2410fb_init(void);int S3C2410fb_setup(char *);static int S3C2410fb_check_var(struct fb_var_screeninfo *var,struct fb_info *info);static int S3C2410fb_set_par(struct fb_info *info);static int S3C2410fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,u_int transp, struct fb_info *info);static int S3C2410fb_pan_display(struct fb_var_screeninfo *var,struct fb_info *info);static struct fb_ops S3C2410fb_ops = {	.fb_check_var	= S3C2410fb_check_var,	.fb_set_par	= S3C2410fb_set_par,	.fb_setcolreg	= S3C2410fb_setcolreg,	.fb_pan_display	= S3C2410fb_pan_display,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,	.fb_cursor	= soft_cursor,};static u_long get_line_length(int xres_virtual, int bpp){	u_long length;	length = xres_virtual * bpp;	length = (length + 31) & ~31;	length >>= 3;	return (length);}static int S3C2410fb_check_var(struct fb_var_screeninfo *var,			 struct fb_info *info){	u_long line_length;	/*	 *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!	 *  as FB_VMODE_SMOOTH_XPAN is only used internally	 */	if (var->vmode & FB_VMODE_CONUPDATE) {		var->vmode |= FB_VMODE_YWRAP;		var->xoffset = info->var.xoffset;		var->yoffset = info->var.yoffset;	}	/*	 *  Some very basic checks	 */	if (!var->xres)		var->xres = 1;	if (!var->yres)		var->yres = 1;	if (var->xres > var->xres_virtual)		var->xres_virtual = var->xres;	if (var->yres > var->yres_virtual)		var->yres_virtual = var->yres;	if (var->bits_per_pixel <= 1)		var->bits_per_pixel = 1;	else 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 <= 24)		var->bits_per_pixel = 24;	else if (var->bits_per_pixel <= 32)		var->bits_per_pixel = 32;	else		return -EINVAL;	if (var->xres_virtual < var->xoffset + var->xres)		var->xres_virtual = var->xoffset + var->xres;	if (var->yres_virtual < var->yoffset + var->yres)		var->yres_virtual = var->yoffset + var->yres;	/*	 *  Memory limit	 */	line_length =	    get_line_length(var->xres_virtual, var->bits_per_pixel);	if (line_length * var->yres_virtual > videomemorysize)		return -ENOMEM;	/*	 * Now that we checked it we alter var. The reason being is that the video	 * mode passed in might not work but slight changes to it might make it 	 * work. This way we let the user know what is acceptable.	 */	switch (var->bits_per_pixel) {	case 1:	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:		/* RGBA 5551 */		if (var->transp.length) {			var->red.offset = 0;			var->red.length = 5;			var->green.offset = 5;			var->green.length = 5;			var->blue.offset = 10;			var->blue.length = 5;			var->transp.offset = 15;			var->transp.length = 1;		} else {	/* RGB 565 */			var->red.offset = 0;			var->red.length = 5;			var->green.offset = 5;			var->green.length = 6;			var->blue.offset = 11;			var->blue.length = 5;			var->transp.offset = 0;			var->transp.length = 0;		}		break;	case 24:		/* RGB 888 */		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 16;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 32:		/* RGBA 8888 */		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 16;		var->blue.length = 8;		var->transp.offset = 24;		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;	return 0;}/* This routine actually sets the video mode. It's in here where we * the hardware state info->par and fix which can be affected by the  * change in par. For this driver it doesn't do much.  */static int S3C2410fb_set_par(struct fb_info *info){	info->fix.line_length = get_line_length(info->var.xres_virtual,info->var.bits_per_pixel);	return 0;}static int S3C2410fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,			 u_int transp, struct fb_info *info){	if (regno >= 256)	/* no. of hw registers */		return 1;	/*	 * Program hardware... do anything you want with transp	 */	/* grayscale works only partially under directcolor */	if (info->var.grayscale) {		/* grayscale = 0.30*R + 0.59*G + 0.11*B */		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 RAMDAC	 *   cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)	 *   RAMDAC[X] is programmed to (red, green, blue)	 * 	 * Pseudocolor:	 *    uses offset = 0 && length = RAMDAC register width.	 *    var->{color}.offset is 0	 *    var->{color}.length contains widht of DAC	 *    cmap is not used	 *    RAMDAC[X] is programmed to (red, green, blue)	 * Truecolor:	 *    does not use DAC. Usually 3 are present.	 *    var->{color}.offset contains start of bitfield	 *    var->{color}.length contains length of bitfield	 *    cmap is programmed to (red << red.offset) | (green << green.offset) |	 *                      (blue << blue.offset) | (transp << transp.offset)	 *    RAMDAC does not exist	 */#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)	switch (info->fix.visual) {	case FB_VISUAL_TRUECOLOR:	case FB_VISUAL_PSEUDOCOLOR:		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);		break;	case FB_VISUAL_DIRECTCOLOR:		red = CNVT_TOHW(red, 8);	/* expect 8 bit DAC */		green = CNVT_TOHW(green, 8);		blue = CNVT_TOHW(blue, 8);		/* hey, there is bug in transp handling... */		transp = CNVT_TOHW(transp, 8);		break;	}#undef CNVT_TOHW	/* Truecolor has hardware independent palette */	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {		u32 v;		if (regno >= 16)			return 1;		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:			((u32 *) (info->pseudo_palette))[regno] = v;			break;		case 24:		case 32:			((u32 *) (info->pseudo_palette))[regno] = v;			break;		}		return 0;	}	return 0;}static int S3C2410fb_pan_display(struct fb_var_screeninfo *var,struct fb_info *info){	if (var->vmode & FB_VMODE_YWRAP) {		if (var->yoffset < 0		    || var->yoffset >= info->var.yres_virtual		    || var->xoffset)			return -EINVAL;	} else {		if (var->xoffset + var->xres > info->var.xres_virtual ||		    var->yoffset + var->yres > info->var.yres_virtual)			return -EINVAL;	}	info->var.xoffset = var->xoffset;	info->var.yoffset = var->yoffset;	if (var->vmode & FB_VMODE_YWRAP)		info->var.vmode |= FB_VMODE_YWRAP;	else		info->var.vmode &= ~FB_VMODE_YWRAP;	return 0;}static void S3C2410fb_platform_release(struct device *device){	// This is called when the reference count goes to zero.}#define LCDCON_1 ((7<<8)|(3<<5)|(12<<1))#define LCDCON_2 (2<<24)|(319<<14)|(2<<6)|4#define LCDCON_3 (8<<19)|(239<<8)|8#define LCDCON_4 (13<<8)|6#define LCDCON_5 (1<<11)|(0<<9)|(0<<8)|(0<<6)|(1)static void init_2410LCD(struct fb_info *info){	u_long flags;	local_irq_save(flags);	unsigned long lcdcon2;	lcdcon2=LCDCON_2;	lcdcon2&=~LCD2_LINEVAL_MSK;	lcdcon2|=LCD2_LINEVAL(info->var.yres-1);	unsigned long lcdcon3=LCDCON_3;	lcdcon3&=~LCD3_HOZVAL_MSK;	lcdcon3|=LCD3_HOZVAL(info->var.xres-1);	__raw_writel(LCDCON_1&(~S3C2410_LCDCON1_ENVID), S3C2410_LCDCON1);	__raw_writel(lcdcon2, S3C2410_LCDCON2);	__raw_writel(lcdcon3, S3C2410_LCDCON3);	__raw_writel(LCDCON_4, S3C2410_LCDCON4);	__raw_writel(LCDCON_5, S3C2410_LCDCON5);	unsigned long VideoPhysicalTemp=info->fix.smem_start;//(unsigned long)info->screen_base;	unsigned long lcdsaddr1 = 		LCDADDR_BANK((VideoPhysicalTemp >> 22))		| LCDADDR_BASEU((VideoPhysicalTemp >> 1));	unsigned long lcdsaddr2= LCDADDR_BASEL( 		(VideoPhysicalTemp + (info->var.xres * 2 * (info->var.yres/*-1*/)))		>> 1);	unsigned long lcdsaddr3= LCDADDR_OFFSET(0) | (LCDADDR_PAGE(info->var.xres) /*>> 1*/);	__raw_writel(lcdsaddr1, S3C2410_LCDSADDR1);	__raw_writel(lcdsaddr2, S3C2410_LCDSADDR2);	__raw_writel(lcdsaddr3, S3C2410_LCDSADDR3);	__raw_writel(0, S3C2410_TPAL);	__raw_writel(LCDCON_1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);		printk("LCDCON1 0x%08x\n", __raw_readl(S3C2410_LCDCON1));	printk("LCDCON2 0x%08x\n", __raw_readl(S3C2410_LCDCON2));	printk("LCDCON3 0x%08x\n", __raw_readl(S3C2410_LCDCON3));	printk("LCDCON4 0x%08x\n", __raw_readl(S3C2410_LCDCON4));	printk("LCDCON5 0x%08x\n", __raw_readl(S3C2410_LCDCON5));	printk("LCDSADDR1 0x%08x\n", __raw_readl(S3C2410_LCDSADDR1));	printk("LCDSADDR2 0x%08x\n", __raw_readl(S3C2410_LCDSADDR2));	printk("LCDSADDR3 0x%08x\n", __raw_readl(S3C2410_LCDSADDR3));	local_irq_restore(flags);}static void S3C2410_setup_gpio(void){	DPRINTK("setup gpio\n");	__raw_writel(0xaaaaaaaa, S3C2410_GPDCON);	__raw_writel(3, S3C2410_LCDINTMSK);			// MASK LCD Sub Interrupt	__raw_writel(0, S3C2410_TPAL);				// Disable Temp Palette	__raw_writel(0, S3C2410_LPCSEL);			// Disable LPC3600}static int __init S3C2410fb_probe(struct device *device){	struct platform_device *dev = to_platform_device(device);	struct fb_info *info;	int retval = -ENOMEM;    	U32 pVideoBuffer;	videomemorysize=PAGE_ALIGN(videomemorysize+PAGE_SIZE);	videomemory=dma_alloc_writecombine(device,videomemorysize,&pVideoBuffer,GFP_KERNEL);	if(videomemory==NULL)return retval;	memset(videomemory, 0, videomemorysize);	info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);	if (!info)		goto err;	info->var = S3C2410fb_default;	info->fix = S3C2410fb_fix;	info->fbops = &S3C2410fb_ops;	info->pseudo_palette = info->par;	info->par = NULL;	info->flags = FBINFO_FLAG_DEFAULT;	info->screen_base =videomemory+PAGE_SIZE;	printk("videomemory=0x%08x, page_size=0x%08x, screen_base=0x%08x\n",videomemory,PAGE_SIZE,info->screen_base);	info->fix.smem_start=pVideoBuffer+PAGE_SIZE;	info->fix.smem_len=info->var.xres*info->var.yres*info->var.bits_per_pixel/8;	printk("pVideoBuffer=0x%08x, smem_len=0x%08x, smem_start=0x%08x\n",pVideoBuffer,info->fix.smem_len,info->fix.smem_start);		S3C2410fb_check_var(&info->var,info);	S3C2410fb_set_par(info);	S3C2410_setup_gpio();	init_2410LCD(info);	retval = fb_alloc_cmap(&info->cmap, 256, 0);	if (retval < 0)goto err1;	retval = register_framebuffer(info);	if (retval < 0)goto err2;		dev_set_drvdata(&dev->dev, info);	printk(KERN_INFO"fb%d: Virtual frame buffer device, using %ldK of video memory\n",	       info->node, videomemorysize >> 10);	return 0;err2:	fb_dealloc_cmap(&info->cmap);err1:	framebuffer_release(info);err:	return retval;}static int S3C2410fb_remove(struct device *device){	struct fb_info *info = dev_get_drvdata(device);	if (info) {		unregister_framebuffer(info);		vfree(videomemory);		framebuffer_release(info);	}	return 0;}static struct device_driver S3C2410fb_driver = {	.name	= "S3C2410fb",	.bus	= &platform_bus_type,	.probe	= S3C2410fb_probe,	.remove = S3C2410fb_remove,};static struct platform_device S3C2410fb_device = {	.name	= "S3C2410fb",	.id	= 0,	.dev	= {		.release = S3C2410fb_platform_release,		.coherent_dma_mask=0xffffffff,	}};int __init S3C2410fb_init(void){	int ret = 0;	ret = driver_register(&S3C2410fb_driver);	if (!ret) {		ret = platform_device_register(&S3C2410fb_device);		if (ret)			driver_unregister(&S3C2410fb_driver);	}	printk("init s3c2410fb success!\n");	return ret;}static void __exit S3C2410fb_exit(void){	platform_device_unregister(&S3C2410fb_device);	driver_unregister(&S3C2410fb_driver);}module_init(S3C2410fb_init);module_exit(S3C2410fb_exit);

⌨️ 快捷键说明

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