写在前面:fb设备驱动将驱动进行了分层处理,由内核开发者完成一部分软件相关的代码实现,而将具体的硬件相关的驱动设置留给驱动开发者实现,这样一来,app应用层在使用open、read、write等操作函数时就不用考虑不同fb设备之间的差异,只用调用内核层中file_operation函数进行实现,而这些函数又是间接的调用了驱动层驱动开发者为具体的硬件操作而写的函数。
这样一来,app层、内核层、驱动层、各司其职,app层只用考虑业务逻辑的实现,内核层只用负责fb类设备的注册,而驱动层只用负责具体硬件相关的操作。很好的屏蔽了app使用不同硬件设备而带来的差异。(不光是fb设备驱动使用这种分层的驱动框架,这种思想在驱动中很是普遍)
博客内容包括:fb设备中内核开发者负责维护的fbmem.c框架的分析;以及以s3cfb.c为例,实际的分析fb设备的驱动。
在正式的分析之前,先介绍内核负责实现的文件:
1、drivers/video/fbmem.c:提供graphics类,注册fb的字符设备驱动,提供register_framebuffer接口给具体的framebuffer驱动编写者来注册fb设备;
2、drivers/video/fbsys.c:这个文件是处理fb在/sys目录下的一些属性文件的。
3、drivers/video/modedb.c:管理显示模式(显示器的分辨率,刷新率等);
4、drivers/video/fb_notify.c :管理链表,在注册fb设备驱动时会被调用。
其中以 fbmem.c 文件最为重要,其他的几个文件内的函数都间接的被这个文件中的函数包含,所以下面以 fbmem.c 文件分析内核完成的工作。
1.驱动架构的主文件fbmem.c:
1.1 驱动的注册:
module_init(fbmem_init);
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;
}
总结:①创建proc相关文件;②设备文件的注册;③fb设备类graphics的注册。具体分析如下:
1.1.1创建proc相关的文件:在/proc目录下创建fb文件
/proc目录以文件系统的方式为访问系统内核数据的操作提供接口。用户和应用程序可以通过 proc得到系统的信息,并可以改变内核的某些参数。关于他的详细内容在这里不做多余的陈述,而是看看他的实现:
在proc_fs.h文件中有对于这个函数的具体实现:
static inline struct proc_dir_entry *proc_create(const char *name, mode_t mode,
struct proc_dir_entry *parent, const struct file_operations *proc_fops)
{
return proc_create_data(name, mode, parent, proc_fops, NULL);
}
进而追踪proc_create_data函数得知:在proc_fs.h文件
static inline struct proc_dir_entry *proc_create_data(const char *name,
mode_t mode, struct proc_dir_entry *parent,
const struct file_operations *proc_fops, void *data)
{
return NULL;
}
但是不解的是这里的最底层的函数中只是返回了null,而并未做出其他的注册操作,但在/proc中确实有fb文件记录着fb设备相关的信息,由于时间的缘故,在这里不再做分析。
1.1.2驱动设备的注册:
register_chrdev(FB_MAJOR,"fb",&fb_fops)
这里指定fb设备的主设备号为29,名字为fb。
重要的是fb_fops这个file_operations结构体变量,内包含硬件的实现函数:
static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = fb_compat_ioctl,
#endif
.mmap = fb_mmap,
.open = fb_open,
.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
};
继续追踪register_chrdev函数的实体实现函数在fs.h中:
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
{
return __register_chrdev(major, 0, 256, name, fops);
}
被调用的__register_chrdev函数实体在char_dev.c中:
int __regist