linux内核中Frambuffer代表的就是一个虚拟的显示设备,其目的是达到一种分层的思想,即抽象出来的显示设备对上面各个调用模块来说是统一不变的。对于不同设备对应一个个fb_info结构,最终操作的还是fb_info.fbops,底层设备与Frambuffer层建立连接是通过register_framebuffer(struct fb_info *fb_info)函数来建立连接的,最直接的代码如下:
int register_framebuffer(struct fb_info *fb_info)
{
.
.
.
for (i = 0 ; i < FB_MAX; i++) //找到一个空的位置用于存放新的fb_info
if (!registered_fb[i])//该数组在fbmem中定义,作为全局变量使用
break;
fb_info->node = i;
fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), "fb%d", i);//创建一个B_MAJOR为主设备号,i为次设备号,名称为fbi的设备节点
........对bf_info 进行进一步配置.......
registered_fb[i] = fb_info;//将fb_info放入到数组中去
。。。。。。
return 0;
}
现在假设一个应用程序来打开上面刚刚建立的设备节点,通过主设备号找到file_operations,然后调用其中的open成员函数,即fb_open()函数:
static int fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);
struct fb_info *info;
int res = 0;
if (fbidx >= FB_MAX)
return -ENODEV;
#ifdef CONFIG_KMOD
if (!(info = registered_fb[fbidx]))
try_to_load(fbidx);
#endif /* CONFIG_KMOD */
if (!(info = registered_fb[fbidx]))
return -ENODEV;
if (!try_module_get(info->fbops->owner))
return -ENODEV;
file->private_data = info;
if (info->fbops->fb_open) {
res = info->fbops->fb_open(info,1);
if (res)
module_put(info->fbops->owner);
}
return res;
}
可见是通过次设备号找到上面注册的fb_info,并调用fb_info.fbops中的fb_open()成员函数,其他read,write,ioctl等最终调用的也是fb_info.fbops中对应的成员函数,这样就保证了frambuffer对上层调用的稳定性。