LCD FrameBuffer驱动程序框架分析
对于一个普通的字符设备,通常有以下五个步骤:
- 第一步:获取主设备号major,可以自动分配,也可以自己选没有被使用的主设备号
- 第二步:创建file_operation结构体,初始化成员变量.open、.release、.read、.write等成员变量
- 第三步:注册字符设备驱动
- register_chrdev(major,name,file_operation);根据主设备号和file_operation注册设备驱动
- class_creat();动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加到内核中。创建的逻辑类位于/sys/class中
- device_create();在/dev目录下创建相应的设备节点
- 第四步:入口函数,使用module_init()宏进行修饰,驱动程序加载时将执行这个函数,入口函数中调用第三部的函数
- 第五步:出口函数,使用module_exit()宏进行修饰,当驱动程序卸载时将执行这个函数,出口函数中进行:
- unregister_chrdev();注销字符设备驱动
- device_destroy();删除设备
- class_destroy();删除class
然而字符操作的这一系列操作内核已经帮我们实现了,这一下列操作在drivers/video/fbdev/core/fbmem.c文件中实现。实现过程如下:
- 第一步:主设备号FB_MAJOR在include/uapi/linux/major.h有定义,为29
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,
#if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
(defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \
!defined(CONFIG_MMU))
.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
.fsync = fb_deferred_io_fsync,
#endif
.llseek = default_llseek,
};
static int __init fbmem_init(void)
{
int ret;
if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops))
return -ENOMEM;
ret = register_chrdev(FB_MAJOR, "fb", &fb_fops);
if (ret) {
printk("unable to get major %d for fb devs\n", FB_MAJOR);
goto err_chrdev;
}
fb_class = class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
ret = PTR_ERR(fb_class);
pr_warn("Unable to create fb class; errno = %d\n", ret);
fb_class = NULL;
goto err_class;
}
fb_console_init();
return 0;
err_class:
unregister_chrdev(FB_MAJOR, "fb");
err_chrdev:
remove_proc_entry("fb", NULL);
return ret;
}
module_init(fbmem_init);
static void __exit
fbmem_exit(void)
{
fb_console_exit();
remove_proc_entry("fb", NULL);
class_destroy(fb_class);
unregister_chrdev(FB_MAJOR, "fb");
}
module_exit(fbmem_exit);
然后我们简单分析一下fb_fops结构体中的.open函数fb_open()
static int fb_open(struct inode *inode, struct file *file)
__acquires(&info->lock)
__releases(&info->lock)
{
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
info = get_fb_info(fbidx);
if (!info) {
request_module("fb%d", fbidx);
info = get_fb_info(fbidx);
if (!info)
return -ENODEV;
}
if (IS_ERR(info))
return PTR_ERR(info);
lock_fb_info(info);
if (!try_module_get(info->fbops->owner)) {
res = -ENODEV;
goto out;
}
file->private_data = info;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
#ifdef CONFIG_FB_DEFERRED_IO
if (info->fbdefio)
fb_deferred_io_open(info, inode, file);
#endif
out:
unlock_fb_info(info);
if (res)
put_fb_info(info);
return res;
}
在fb_open()函数中iminor(inode)根据设备文件的inode节点中的设备号来获取次设备号,get_fb_info()函数再根据次设备号获取一个fb_info结构体info,最终调用info->fbops->fb_open()函数。
同理分析fb_release()函数,最终调用info->fbops->fb_release()函数,所以内核为我们提供了一个framebuffer框架,我们只需要实现一个fb_info结构体,这个结构体可通过此设备号查找得到,并且对该结构体中的fbops初始化。经过简单分析我们基本上可以得出LCD FrameBuffer框架流程如下: