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

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. Business Cards UVALive - 4384(画图看图。。)

    只能由三种情况 都横着放  都竖着放  横和竖交错放 那就去判断好了... 具体看代码 #include <iostream> #include <cstdio> #inclu ...

  2. MT【129】常数变易法

    已知数列\(\{x_n\}\)满足\[x_{n+1}=\left(\dfrac 2{n^2}+\dfrac 3n+1\right)x_n+n+1,n\in\mathbf N^*,\]且\(x_1=3\ ...

  3. 【BZOJ5311/CF321E】贞鱼/Ciel and Gondolas(动态规划,凸优化,决策单调性)

    [BZOJ5311/CF321E]贞鱼/Ciel and Gondolas(动态规划,凸优化,决策单调性) 题面 BZOJ CF 洛谷 辣鸡BZOJ卡常数!!!!!! 辣鸡BZOJ卡常数!!!!!! ...

  4. 【BZOJ2962】序列操作(线段树)

    [BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...

  5. 【NOI 2018】屠龙勇士(扩欧)

    题意理解错了... 一把剑打一条龙,打了$x$次后如果龙不死,你就Game Over了. 显然,面对每条龙使用的剑是固定的,如果所有龙中有一条没打死你就挂了. 可以知道,可行的答案集合就是所有龙的可行 ...

  6. 方程式EQGRP_Lost_in_Translation工具之fb.py

    使用方法: 环境搭建:win2003下测试: 下载python2.6并安装 下载pywin32并安装 将C:\Python26添加到环境变量PATH中 将整个windows目录复制到windows20 ...

  7. 响应式开发(五)-----Bootstrap CSS----------Bootstrap 网格系统

    如果我们看过一些bootstrap的框架,经常看到col-sm-3等样式class. Bootstrap 提供了一套响应式.移动设备优先的流式网格系统,随着屏幕或视口(viewport)尺寸的增加,系 ...

  8. IntelliJ IDEA详细配置和使用教程-字体、编码和基本设置

    IDEA使用--字体.编码和基本设置 https://blog.csdn.net/frankcheng5143/article/details/50779149 IntelliJ IDEA详细配置和使 ...

  9. nginx让用户通过用户名密码认证访问web页面

    在使用nginx转发的时候,要进行一次用户身份的确认. 1)通过htpasswd命令生成用户名及对应密码数据库文件. [root@bgs-5p173-wangwenting ~]# htpasswd ...

  10. Hadoop生态圈-phoenix(HBase)的索引配置

    Hadoop生态圈-phoenix(HBase)的索引配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 创建索引是为了优化查询,我们可以在phoenix上配置索引方式. 一.修改 ...