framebuffer驱动详解2——fb驱动框架分析核心层

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

一、前言

framebuffer驱动框架包括以下两部分:

1、内核开发者实现的部分(核心层)

root@ubuntu:省略部分路径/x210_kernel/drivers/video# ls *.o
built-in.o     cfbfillrect.o  fbcmap.o  fbmem.o  fb_notify.o  fbsysfs.o
cfbcopyarea.o  cfbimgblt.o    fbcvt.o   fbmon.o  fb.o         modedb.o
root@ubuntu:省略部分路径/x210_kernel/drivers/video#

通过检查内核编译结果相应目录中的.o文件,得知驱动框架核心层主要涉及的文件:

(1)drivers/video/fbmem.c(主要文件)

该文件创建graphics类,注册fb设备驱动,提供fb设备注册接口register_framebuffer。

该文件相对于fb设备,就好比misc.c文件相对于杂散类设备,其结构和分析方法类似。

(2)drivers/video/fbsysfs.c

这个文件与fb在/sys目录下的一些属性文件有关。

(3)drivers/video/modedb.c

这个文件与显示模式(比如VGA、720P等)的管理有关。

(4)drivers/video/fb_notify.c

2、驱动工程师实现的部分(操作层)

root@ubuntu:省略部分路径/x210_kernel/drivers/video# cd samsung/
root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# ls *.o
built-in.o  s3cfb_fimd6x.o  s3cfb.o
root@ubuntu:省略部分路径/x210_kernel/drivers/video/samsung# 

通过检查内核编译结果相应目录中的.o文件,得知具体操作层主要涉及的文件:

(1)drivers/video/samsung/s3cfb.c,这是驱动主要文件。

(2)drivers/video/samsung/s3cfb_fimd6x.c,里面有很多LCD硬件操作的函数。

(3)arch/arm/mach-s5pv210/mach-x210.c,负责提供platform_device。

(4)arch/arm/plat-s5p/devs.c,为platform_device提供一些硬件描述信息。

接下来,我们将对这两部分内容进行源码级别的分析。

二、fb驱动框架核心层分析

1、fbmem_init()函数

此函数位于drivers/video/fbmem.c文件中。

static int __init fbmem_init(void)
{
	proc_create("fb", 0, NULL, &fb_proc_fops);

	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
		printk("unable to get major %d for fb devs\n", FB_MAJOR);

	fb_class = class_create(THIS_MODULE, "graphics");
	if (IS_ERR(fb_class)) {
	    printk(KERN_WARNING "Unable to create fb class;errno = %ld\n",\
                                                        PTR_ERR(fb_class));
		fb_class = NULL;
	}
	return 0;
}

#ifdef MODULE          //MODULE没有定义
module_init(fbmem_init);
static void __exit
fbmem_exit(void)
{
	remove_proc_entry("fb", NULL);
	class_destroy(fb_class);
	unregister_chrdev(FB_MAJOR, "fb");
}

module_exit(fbmem_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Framebuffer base");
#else //MODULE没有定义,所以对于fbmem_init而言,执行的是这个
subsys_initcall(fbmem_init);
#endif

(1)subsys_initcall(fbmem_init)

对于fbmem_init()函数,因为没有定义MODULE(表示以模块方式安装),因此执行的是subsys_initial(表示直接集成在内核中)。又因为是直接集成的,所以不需要卸载函数。

(2)proc_create("fb", 0, NULL, &fb_proc_fops);

fb_proc_fops和fb在proc文件系统中的表现,即cat /proc/fb的实现;

(3)register_chrdev(FB_MAJOR,"fb",&fb_fops)

利用register_chdev()函数注册fb设备,注册之后在cat /proc/devices时显示有“29 fb”。

其中,FB_MAJOR=29,而变量fb_fops的定义见下文。

(4)fb_class = class_create(THIS_MODULE, "graphics");

利用class_create()函数创建了一个名为“graphics”的类。即在/sys/class/下有graphics目录。

 

2、变量fb_fops

变量fb_fops定义在drivers/video/fbmem.c文件中,内容如下:

static const struct file_operations fb_fops = {
	.owner =	THIS_MODULE,
	.read =		fb_read,
	.write =	fb_write,
	.unlocked_ioctl = fb_ioctl,
    //省略部分代码
};

可知其函数成员所指向的函数,分别为fb_read,fb_write,fb_ioctl。后面将讨论这些函数。

 

3、register_framebuffer()函数

此函数位于drivers/video/fbmem.c文件中,是fb驱动框架设计的fb设备注册接口,内容如下。

/**
 *	register_framebuffer - registers a frame buffer device
 *	@fb_info: frame buffer info structure
 *	Registers a frame buffer device @fb_info.
 *	Returns negative errno on error, or zero for success.
 *
 */

int register_framebuffer(struct fb_info *fb_info)
{
	int i;
	struct fb_event event;
	struct fb_videomode mode;

	if (num_registered_fb == FB_MAX)
		return -ENXIO;

	if (fb_check_foreignness(fb_info))//判断大小端模式
		return -ENOSYS;

	remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
					 fb_is_primary_device(fb_info));

	num_registered_fb++;
	for (i = 0 ; i < FB_MAX; i++)
		if (!registered_fb[i])
			break;
	fb_info->node = i;
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->mm_lock);

	fb_info->dev = device_create(fb_class, fb_info->device,
				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
	if (IS_ERR(fb_info->dev)) {
		/* Not fatal */
		printk(KERN_WARNING "Unable to create device for framebuffer %d; \
                                errno = %ld\n", i, PTR_ERR(fb_info->dev));
		fb_info->dev = NULL;
	} else
		fb_init_device(fb_info);

	if (fb_info->pixmap.addr == NULL) {
		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
		if (fb_info->pixmap.addr) {
			fb_info->pixmap.size = FBPIXMAPSIZE;
			fb_info->pixmap.buf_align = 1;
			fb_info->pixmap.scan_align = 1;
			fb_info->pixmap.access_align = 32;
			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
		}
	}	
	fb_info->pixmap.offset = 0;

	if (!fb_info->pixmap.blit_x)
		fb_info->pixmap.blit_x = ~(u32)0;

	if (!fb_info->pixmap.blit_y)
		fb_info->pixmap.blit_y = ~(u32)0;

	if (!fb_info->modelist.prev || !fb_info->modelist.next)
		INIT_LIST_HEAD(&fb_info->modelist);

	fb_var_to_videomode(&mode, &fb_info->var);
	fb_add_videomode(&mode, &fb_info->modelist);
	registered_fb[i] = fb_info;

	event.info = fb_info;
	if (!lock_fb_info(fb_info))
		return -ENODEV;
	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
	unlock_fb_info(fb_info);
	return 0;
}

(1)struct fb_info 结构体

此结构体的定义如下:

struct fb_info {
	int node; //fb_info在registered_fb数组的下标
	int flags;
	struct mutex lock;		/* Lock for open/release/ioctl funcs */
	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */
	struct fb_var_screeninfo var;	/* Current var */
	struct fb_fix_screeninfo fix;	/* Current fix */
	struct fb_monspecs monspecs;	/* Current Monitor specs */
	struct work_struct queue;	/* Framebuffer event queue */
	struct fb_pixmap pixmap;	/* Image hardware mapper */
	struct fb_pixmap sprite;	/* Cursor hardware mapper */
	struct fb_cmap cmap;		/* Current cmap */
	struct list_head modelist;      /* mode list */
	struct fb_videomode *mode;	/* current mode */

//省略部分代码

	struct fb_ops *fbops;
	struct device *device;		/* This is the parent */
	struct device *dev;		/* This is this fb device */
	int class_flag;                    /* private sysfs flags */

	char __iomem *screen_base;	/* Virtual address */
	unsigned long screen_size;	/* Amount of ioremapped VRAM or 0 */ 
	void *pseudo_palette;		/* Fake palette of 16 colors */ 
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1
	u32 state;			/* Hardware state i.e suspend */
	void *fbcon_par;                /* fbcon use-only private area */
	/* From here on everything is device dependent */
	void *par;
	/* we need the PCI or similiar aperture base/size not
	   smem_start/size as smem_start may just be an object
	   allocated inside the aperture so may not actually overlap */
	struct apertures_struct {
		unsigned int count;
		struct aperture {
			resource_size_t base;
			resource_size_t size;
		} ranges[0];
	} *apertures;
};

(2)fb_check_foreignness()函数

判断大小端模式。

(3)remove_conflicting_framebuffers()函数

去掉冲突的fb。

(4)device_create()函数

在/sys/class/graphic目录下创建设备?还是说创建设备文件/dev/xxx?应该是后者。

(5)fb_init_device()函数

这是fb在sys文件系统的接口函数。涉及dev_set_drvdata和dev_get_drvdata。有待深入。

(6)fb_var_to_videomode()函数

1)什么是mode?

2)fb_var_to_videomode()函数的内容

/**
 * fb_var_to_videomode - convert fb_var_screeninfo to fb_videomode
 * @mode: pointer to struct fb_videomode
 * @var: pointer to struct fb_var_screeninfo
 */
void fb_var_to_videomode(struct fb_videomode *mode,
			 const struct fb_var_screeninfo *var)
{
	u32 pixclock, hfreq, htotal, vtotal;

	mode->name = NULL;
	mode->xres = var->xres;
	mode->yres = var->yres;
	mode->pixclock = var->pixclock;
	mode->hsync_len = var->hsync_len;
	mode->vsync_len = var->vsync_len;
	mode->left_margin = var->left_margin;
	mode->right_margin = var->right_margin;
	mode->upper_margin = var->upper_margin;
	mode->lower_margin = var->lower_margin;
	mode->sync = var->sync;
	mode->vmode = var->vmode & FB_VMODE_MASK;
	mode->flag = FB_MODE_IS_FROM_VAR;
	mode->refresh = 0;

	if (!var->pixclock)
		return;

	pixclock = PICOS2KHZ(var->pixclock) * 1000;

	htotal = var->xres + var->right_margin + var->hsync_len +
		var->left_margin;
	vtotal = var->yres + var->lower_margin + var->vsync_len +
		var->upper_margin;

	if (var->vmode & FB_VMODE_INTERLACED)
		vtotal /= 2;
	if (var->vmode & FB_VMODE_DOUBLE)
		vtotal *= 2;

	hfreq = pixclock/htotal;
	mode->refresh = hfreq/vtotal;
}

(7)fb_add_videomode()函数

(8)registered_fb[i] = fb_info

注册与登记该fb设备。结合fb_read等函数中对fb_info的使用。

关键点:数据如何封装、数据由谁准备由谁消费、数据如何传递。

(9)fb_notifier_call_chain()函数

待写。

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...