---恢复内容开始---

Framebuffer模块初始化过程:--driver\video\fbmem.c

1、  初始化Framebuffer

FrameBuffer驱动是以模块的形式注册到系统中,在模块初始化时,创建FrameBuffer对应的设备文件及proc文件,并注册FrameBuffer设备操作接口函数fb_fops。

static int __init  fbmem_init(void)
{
proc_create("fb", , NULL, &fb_proc_fops);///向 proc 文件系统报告驱动状态和参数
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))///注册字符设备驱动,主设备号是29
printk("unable to get major %d for fb devs\n", FB_MAJOR);
fb_class = class_create(THIS_MODULE, "graphics");///创建 /sys/class/graphics 设备类,配合 mdev生成设备文件
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return ;
}

Framebuffer作为一个子系统,在fbmem_init中通过register_chrdev接口向系统注册一个主设备号位29的字符设备驱动。通过class_create创建graphics设备类,配合mdev机制生成供用户访问的设备文件(位于/dev目录)。

2、 Framebuffer设备驱动的接口集fb_fops的定义为:

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
.llseek = default_llseek,
};

在linux设备驱动中,所有的显示缓存设备均由framebuffer子系统内部管理,即linux设备驱动框架只认识一个主设备号为29的framebuffer设备。应用层所有针对显示缓存(最多32个)的访问均会推送给fb_fops进行进一步分发操作。

3、 注册Framebuffer

linux 提供了register_framebuffer()和unregister_framebuffer()函数分别作为注册和注销帧缓冲设备,这两个函数都接受fb_info指针为参数,原型为:

int register_framebuffer(struct fb_info  *fb_info);

int Unregister_framebuffer(struct fb_info  *fb_info);

对于register_framebuffer()而言,如果注册的帧缓冲设备超过了FB_MAX(目前定义为32),则返回为-ENXIO,注册成功则返回为0。

int register_framebuffer(struct fb_info *fb_info)
{
int ret; mutex_lock(&registration_lock);
ret = do_register_framebuffer(fb_info);
mutex_unlock(&registration_lock); return ret;
}
EXPORT_SYMBOL(register_framebuffer);// 在内核的启动过程会被调用,以便执行注册帧缓冲区硬件设备的操作
static int do_register_framebuffer(struct fb_info *fb_info)
{
int i, ret;
struct fb_event event;
struct fb_videomode mode; if (fb_check_foreignness(fb_info))
return -ENOSYS; ret = do_remove_conflicting_framebuffers(fb_info->apertures,
fb_info->fix.id,
fb_is_primary_device(fb_info));
if (ret)
return ret; if (num_registered_fb == FB_MAX)//如果注册的帧缓冲设备超过了FB_MAX(目前定义为32),则返回为-ENXIO,注册成功则返回为0。
return -ENXIO; num_registered_fb++;///已经注册了的帧缓冲区硬件设备个数
for (i = ; i < FB_MAX; i++)
if (!registered_fb[i])///registered_fb[i]保存所有已经注册了的帧缓冲区硬件设备
break;
fb_info->node = i;
atomic_set(&fb_info->count, );
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock); fb_info->dev = device_create(fb_class, fb_info->device,///在/sys/grapics/下创建 fbx设备,用于设备文件的创建
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 = ;
fb_info->pixmap.scan_align = ;
fb_info->pixmap.access_align = ;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = ; if (!fb_info->pixmap.blit_x)
fb_info->pixmap.blit_x = ~(u32); if (!fb_info->pixmap.blit_y)
fb_info->pixmap.blit_y = ~(u32); if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist); if (fb_info->skip_vt_switch)
pm_vt_switch_required(fb_info->dev, false);
else
pm_vt_switch_required(fb_info->dev, true); fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info; event.info = fb_info;
console_lock();
if (!lock_fb_info(fb_info)) {
console_unlock();
return -ENODEV;
} fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);///通知帧缓冲区控制台,有一个新的帧缓冲区设备被注册到内核中来了
unlock_fb_info(fb_info);
console_unlock();
return ;
}

每个从设备都需要传递一个fb_info的数据结构指针,其即代表单个显示缓存设备。从中,可以看到fb_info最终会存储到全局数组struct fb_info*registered_fb[FB_MAX]中,FB_MAX是32,从这里我们也可以看出,framebuffer最多支持32个从设备。另外,每个从设备注册还会在/sys/class/graphics/设备类中创建一个设备,最终由mdev在/dev/目录中生成对应的设备文件。假设M个从设备调用register_framebuffer接口,即会在/dev中生成M个设备文件,如/dev/fb0、/dev/fb1、/dev/fb2等等。这M个设备的主设备号都是29,从设备则是0、1、2等等。

每一个被注册的帧缓冲区硬件设备在/dev/graphics目录下都有一个对应的设备文件fb<minor>,其中,<minor>表示一个从设备号。例如,第一个被注册的帧缓冲区硬件设备在/dev/graphics目录下都有一个对应的设备文件fb0。用户空间的应用程序通过这个设备文件就可以操作帧缓冲区硬件设备了,即将要显示的画面渲染到帧缓冲区硬件设备上去。

帧缓冲区控制台在内核中对应的驱动程序模块为fbcon:  (drivers\video\console\Fbcon.c)

初始化:

static struct notifier_block fbcon_event_notifier = {
.notifier_call = fbcon_event_notify,
};
......
static int __init fb_console_init(void)//帧缓冲区控制台初始化
{
int i; console_lock();
fb_register_client(&fbcon_event_notifier);//调用fb_register_client来监听帧缓冲区硬件设备的注册事件,fbcon_event_notifier--->实现
fbcon_device = device_create(fb_class, NULL, MKDEV(, ), NULL,
"fbcon"); if (IS_ERR(fbcon_device)) {
printk(KERN_WARNING "Unable to create device "
"for fbcon; errno = %ld\n",
PTR_ERR(fbcon_device));
fbcon_device = NULL;
} else
fbcon_init_device(); for (i = ; i < MAX_NR_CONSOLES; i++)
con2fb_map[i] = -; console_unlock();
fbcon_start();
return ;
}

这个函数除了会调用函数device_create来创建一个类别为graphics的设备fbcon之外,还会调用函数fb_register_client来监听帧缓冲区硬件设备的注册事件,这是由函数fbcon_event_notify来实现的,如下所示:

static int fbcon_event_notify(struct notifier_block *self,
unsigned long action, void *data)
{
struct fb_event *event = data;
struct fb_info *info = event->info;
struct fb_videomode *mode;
struct fb_con2fbmap *con2fb;
struct fb_blit_caps *caps;
int idx, ret = ; switch(action) { ...... case FB_EVENT_FB_REGISTERED:
ret = fbcon_fb_registered(info);///---> 帧缓冲区硬件设备的注册事件最终是由函数fbcon_fb_registered来处理的
break; .......
}
done:
return ret;
}

帧缓冲区硬件设备的注册事件最终是由函数fbcon_fb_registered来处理的,它的实现如下所示:

static int fbcon_fb_registered(struct fb_info *info)
{
int ret = , i, idx; idx = info->node;
fbcon_select_primary(info);///检查当前注册的帧缓冲区硬件设备是否是一个主帧缓冲区硬件设备,如果是的话,那么就将它的信息记录下来 if (info_idx == -) {///如果是的话,那么就将它的信息记录下来
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map_boot[i] == idx) {
info_idx = idx;
break;
}
} if (info_idx != -)
ret = do_fbcon_takeover();
} else {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map_boot[i] == idx)
set_con2fb_map(i, idx, );
}
} return ret;
}

函数fbcon_select_primary用来检查当前注册的帧缓冲区硬件设备是否是一个主帧缓冲区硬件设备。如果是的话,那么就将它的信息记录下来。这个函数只有当指定了CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY编译选项时才有效,否则的话,它是一个空函数。

在Linux内核中,每一个控制台和每一个帧缓冲区硬件设备都有一个从0开始的编号,它们的初始对应关系保存在全局数组con2fb_map_boot中。控制台和帧缓冲区硬件设备的初始对应关系是可以通过设置内核启动参数来初始化的。在模块fbcon中,还有另外一个全局数组con2fb_map,也是用来映射控制台和帧缓冲区硬件设备的对应关系,不过它映射的是控制台和帧缓冲区硬件设备的实际对应关系。

---恢复内容结束---

Framebuffer 驱动学习总结(二)---- Framebuffer模块初始化的更多相关文章

  1. nginx-push-stream模块源码学习(二)——模块初始化

    本文重点介绍push stream模块的构成,至于nginx如何启动.维护该模块不会详细阐述,以后有时间会做详细阐述. 一.模块定义 1.1.  模块配置 通用nginx模块的配置struct有三种, ...

  2. Linux Framebuffer驱动剖析之二—驱动框架、接口实现和使用

    深入分析LinuxFramebuffer子系统的驱动框架.接口实现和使用. 一.LinuxFramebuffer的软件需求 上一篇文章详细阐述了LinuxFramebuffer的软件需求(请先理解第一 ...

  3. Linux Framebuffer驱动框架之二软件架构(未完待续)【转】

    本文转载自:http://blog.csdn.net/gqb_driver/article/details/12918547 /************************************ ...

  4. linux驱动学习(二) Makefile高级【转】

    转自:http://blog.csdn.net/ghostyu/article/details/6866863 版权声明:本文为博主原创文章,未经博主允许不得转载. 在我前一篇写的[ linux驱动学 ...

  5. Framebuffer 驱动学习总结(一) ---- 总体架构及关键结构体

    一.Framebuffer 设备驱动总体架构 帧缓冲设备为标准的字符型设备,在Linux中主设备号29,定义在/include/linux/major.h中的FB_MAJOR,次设备号定义帧缓冲的个数 ...

  6. Linux驱动学习之常用的模块操作命令

    1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...

  7. Webpack4 学习笔记二 CSS模块转换

    前言 此内容是个人学习笔记,以便日后翻阅.非教程,如有错误还请指出 webpack 打包css模块 webpack是js模块打包器, 如果在入口文件引入css文件或其它的less.sass等文件,需要 ...

  8. SDRAM学习(二)之初始化

    目录 1.SDRAM初始化的内容(结合英文数据手册) 2.SDRAM初始化的时序 3.代码的编写 4.modesim的仿真 SDRAM初始化的内容 SDRAMs must be powered up ...

  9. Linux内核驱动学习(二)添加自定义菜单到内核源码menuconfig

    文章目录 目标 drivers/Kconfig demo下的Kconfig 和 Makefile Kconfig Makefile demo_gpio.c 目标 Kernel:Linux 4.4 我编 ...

随机推荐

  1. 【JavaScript】table里面点击某td获取同一行tr的其他td值

    某td的input(保存按钮)上绑定方法,点击按钮保存该行所有数据 function locationedit(num){ var ordernumber = $("#"+num) ...

  2. ADO.NET:C#/SQL Server

    1.首次要准备的(工具)是:a.Microsoft Visual Studio Ultimate 2012;b.Microsoft SQL Server Management Studio ; 2.首 ...

  3. DAY2-Python学习笔记

    1.迭代器:可以直接作用于for循环的对象统称为可迭代对象:Iterable,使用isinstance()判断一个对象是否是Iterable对象: >>> from collecti ...

  4. oracle 存储过程创建报错 Procedure created with compilation errors

    出现这错误的话,存储过程还是会成功创建的,创建好后再逐个打开查找存储过程的问题 问题:基本上就是存储过程里面的表不存在,dblink 不存在    ,用户名.xx表  要么用户名不存在要么表不存在 创 ...

  5. 关于PHP 时区错误的问题

    php的ini文件中时区配置默认为关闭状态 这会导致调用时间函数时出错,所以要开启时区并且配置自己的时区: 查询手册找到所有的时区有: 所以修改配置为: 重启apache问题解决

  6. [UVALive 3902] Network

    图片加载可能有点慢,请跳过题面先看题解,谢谢 一道简单的贪心题,而且根节点已经给你了(\(S\)),这就很好做了. 显然,深度小于等于 \(k\) 的都不用管了(\(S\) 深度为0),那么我们只需要 ...

  7. Linux内核设计第六周学习总结 分析Linux内核创建一个新进程的过程

    陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.实验过程 登陆实验楼 ...

  8. ---web模型 --mvc和模型--struts2 入门

    关于web模型: 早期的web 应用主要是静态页丽的浏览〈如新闻的制监),随着Internet的发展,web应用也变得越来越复杂,不仅要 和数据库进行交互 ,还要和用户进行交互,由此衍生了各种服务器端 ...

  9. bzoj 3772 :精神污染 线段树+打标记 or 主席树

    3772: 精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 315  Solved: 87[Submit][Status][Discuss] D ...

  10. 笛卡尔树Cartesian Tree

    前言 最近做题目,已经不止一次用到笛卡尔树了.这种数据结构极为优秀,但是构造的细节很容易出错.因此写一篇文章做一个总结. 笛卡尔树 Cartesian Tree 引入问题 有N条的长条状的矩形,宽度都 ...